AcademySoftwareFoundation / AcademySoftwareFoundation/OpenPBR
specular_color tinting of internal reflections is inconsistent in the reference MaterialX graph (TIR untinted, partial internal reflection tinted)
- 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