Repository navigation
Use IOR for dielectric specular reflectance - #26044
Open
stuartparmenter wants to merge 15 commits into
Open
stuartparmenter wants to merge 15 commits into
stuartparmenter wants to merge 15 commits into
Conversation
Contributor
|
Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke! If it's expected, please add the M-Deliberate-Rendering-Change label. If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it. |
Member
|
@goodartistscopy, your review here would be very welcome. |
Contributor
|
Glad you took it up, I'll have a look ! |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Objective
Bevy's
StandardMaterialsets dielectric reflectance with Filament'sreflectanceparameter, where F0 = 0.16 × reflectance². glTF defines it differently:KHR_materials_iorderives F0 from the index of refraction.KHR_materials_specularscales the specular response linearly withspecularFactorand tints F0 withspecularColorFactor.Filament's
reflectancecan't express glTF's IOR-driven F0 or its linear specular factor, so Bevy approximates them. It ignores the glTF IOR for reflection, squares the specular factors and textures, and drops the tint in deferred. As a result, glTF assets render differently in Bevy than in other glTF viewers. Everyreflectancevalue maps to an IOR with the same F0, so this PR switches to glTF's material parameters and keeps the shared GGX BRDF.It builds on Christophe Dehais's PR #24552.
Solution
((ior - 1) / (ior + 1))²tinted byspecular_tint, asKHR_materials_iorandKHR_materials_speculardefine it.StandardMaterial::reflectanceis replaced byiorand aspecularweight. glTF factors and textures map onto these fields without conversion.specularscales the whole dielectric specular lobe, both F0 and grazing reflectance, asspecularFactordoes in the spec. Every lighting path applies it. For image-based and baked lighting, the energy it removes goes to diffuse, as in the spec's dielectric BRDF.KHR_materials_clearcoatdefines. (This differs from the original PR which adjusted it relative to the coat, as Filament does.)Testing
Tested with my game, the affected examples, and headless renders in forward, deferred, deferred with SSR, and Solari. Not tested on WebGL2.
Showcase
Main and this branch were rendered with the same scenes. The glTF sample models use the HDRIs that Khronos's reference screenshots used, the Sample Viewer's exposure, and the
dfg_lutfeature. Withoutdfg_lut, Bevy's default polynomial approximation of the environment BRDF leaves a faint reflection at IOR 1.0.F0. Main uses 4% for every IOR and squares
specularFactor. This branch follows the spec.IORTestGrid. Reflection now follows the IOR, as in the reference.
SpecularTest. This branch is linear in both factors and caps F0 at 100%, as in the reference.
Specular tint in deferred. Main's deferred renderer drops the tint. On this branch deferred matches forward.
White furnace. Every sphere matches the background on both, so the specular weight moves energy between lobes without adding or losing any. The outlines mark the spheres.
Solari path tracer. Left to right: IOR 1.0, 1.5 and 2.42, a specular texture with alpha 0, and a red tint texture. Main ignores all of them.
I used Claude and Opus 5.5 and Fable 5.1 to help put this together and to help put together some of the comparison images. I stumbled on to the core issue here in my game where I was using Houdini MaterialX materials on my trees, converting to gltf, and loading in to Bevy and was noticing they did not look the same. I had built a smaller fix first, before stumbling on to the PR referenced above. It was the better direction, so I evaluated what was was needed/missing from the other PR and decided that there was enough still to do, and the PR had bitrotted signifigantly, that it made more sense to open this one instead. I spent a while trying to understand the differences between gltf, openpbr and filament here, and decided that embracing the gltf spec made the most sense to me. After many iterations of making sure I got everything and many iterations of testing, I cleaned up everything, reviewed it carefully, and put this PR together!