AcademySoftwareFoundation / AcademySoftwareFoundation/OpenPBR

specular_color tinting of internal reflections is inconsistent in the reference MaterialX graph (TIR untinted, partial internal reflection tinted)

Open
#311 4 comments 0 reactions 0 assignees View on GitHub
Dominant language
CSS
Stars
793
Forks
44
PR merge metrics
No merged PRs in 30d

Description

## Summary

The reference MaterialX graph for `open_pbr_surface` does **not** distinguish between external and internal reflection when applying `specular_color`, and as a side effect it tints the two kinds of *internal* reflection inconsistently:

- **partial internal reflection** (below the critical angle) is **tinted** by `specular_color`;
- **total internal reflection (TIR)** (above the critical angle) is **not** tinted by `specular_color`.

This came up in the working-group discussion around `specular_color` / back-face behavior; filing it so it can be resolved in the spec and reflected in the reference graph (and noted for the ASWF/OpenUSD normative shading-model docs).

## What the graph does

The dielectric base is built from two independent single-mode lobes:

| Node | `scatter_mode` | `tint` |
|------|----------------|--------|
| `dielectric_reflection` (+ `_tf` thin-film variant) | `"R"` | **`specular_color`** |
| `dielectric_transmission` | `"T"` | `if_transmission_tint` (white; becomes `transmission_color` only when `transmission_depth == 0`) |

```
dielectric_base = layer(
top = dielectric_reflection_tf_mix # the R lobe, tinted by specular_color
base = mix(dielectric_transmission(+ volume), opaque_base, transmission_weight)
)
```

`specular_color` is wired straight into `tint` of a single `dielectric_bsdf` with `scatter_mode="R"`. That node reflects on whichever side the interface is hit (the `dielectric_bsdf` decides entering-vs-exiting internally from the `ior`), and `tint` multiplies the **whole** lobe. There is no `backfacing` node, `geompropvalue` facing test, or any view-direction conditional in the graph — so the tint applies uniformly to reflections from both hemispheres.

Verified in both:
- the OpenPBR reference graph (`reference/open_pbr_surface.mtlx`), and
- the shipped MaterialX library (`libraries/bxdf/open_pbr_surface.mtlx`, MaterialX 1.39.5).

## The inconsistency

Because TIR is modeled inside the **transmission** lobe (`scatter_mode="T"`) rather than the reflection lobe:

- partial internal reflection → produced by the `R` lobe → **tinted** by `specular_color`;
- TIR → produced by the `T` lobe → **never** tinted by `specular_color`.

So whether an internal reflection is tinted depends on whether the ray is above or below the critical angle — which was never intended to be an observable distinction of `specular_color`. There is effectively no single, well-defined behavior for "internal reflection."

## Spec ambiguity

The graph matches **neither** interpretation cleanly:

- **Literal current spec** — `specular_color` tints the BRDF (light reflected back into the same hemisphere, from upper *or* lower incidence), transmission unaffected. Under this reading TIR reflections *should also* be tinted, but they are not (they live in the `T` lobe).
- **"External-only" intent** (raised in the working group) — `specular_color` should tint only the external reflection. Under this reading partial internal reflections *should not* be tinted, but they are (the `R` lobe).

## Root cause / MaterialX limitation

With the current MaterialX node set, a single `dielectric_bsdf(scatter_mode="R")` does not expose entering-vs-exiting, so the tint cannot be gated on facing. Cleanly implementing an external-only (or a consistent internal) behavior would require either additional MaterialX functionality or a graph restructuring.

## Proposed next steps

1. Decide the intended semantics: does `specular_color` tint (a) external reflection only, (b) all reflections including internal (both partial and TIR), or (c) something else?
2. Clarify the spec text accordingly (the current wording is being read inconsistently).
3. Once decided, correct the reference MaterialX graph — and, if it needs facing/entering-exiting information that MaterialX cannot currently express, raise the corresponding MaterialX feature request.
4. Note the current graph↔spec difference for the ASWF/OpenUSD normative shading-model documentation.

Contributor guide

No contributing guide indexed for this repository

Research direction

Compare reference/open_pbr_surface.mtlx and libraries/bxdf/open_pbr_surface.mtlx with the current spec wording. First resolve whether specular_color applies to external reflection only or to all internal and external reflection; done means the semantics are clarified, the reference graph is aligned, and the ASWF/OpenUSD normative shading-model documentation notes the result.

Written by the indexing model from the issue text.

Assessment

Domain
computer-graphics, documentation
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.