Fix furnace test energy loss for intermediate metalness values#32190
Fix furnace test energy loss for intermediate metalness values#32190
Conversation
📦 Bundle sizeFull ESM build, minified and gzipped.
🌳 Bundle size after tree-shakingMinimal build including a renderer, camera, empty scene, and dependencies.
|
5862a72 to
e0e6e81
Compare
d19e29a to
1769910
Compare
The furnace test was losing energy when metalness was between 0 and 1. This was due to incorrect application of the Fdez-Agüera multiscattering formula, which is designed for pure dielectric OR conductor F0 values, not blended ones. The fix follows the approach used in EEVEE/Frostbite: 1. Store baseColor (before metalness reduction) and metalness in the material struct 2. Store specularColorDielectric (F0 for dielectric path, 0.04 or IOR-based) 3. Compute multiscattering separately for dielectric (F0=specularColorDielectric) and metallic (F0=baseColor) paths 4. Mix the results based on metalness 5. Use the dielectric path for diffuse energy conservation Changes: - Modified PhysicalMaterial struct to add specularColorDielectric, baseColor, and metalness fields - Updated lights_physical_fragment.glsl.js to initialize these fields and compute specularColorDielectric - Modified RE_IndirectSpecular_Physical() in lights_physical_pars_fragment.glsl.js to: - Compute separate dielectric and metallic multiscattering paths - Mix the results based on metalness - Use dielectric path for diffuse energy conservation References: - Fdez-Agüera's "Multiple-Scattering Microfacet Model for Real-Time Image Based Lighting" http://www.jcgt.org/published/0008/01/03/ - EEVEE implementation approach
1769910 to
436115d
Compare
|
Couldn't get Claude to port the fix to the |
d09d31b to
626760a
Compare
|
Claude spotted an issue with the iridescence code while working on this:
I'll leave this for another PR. /fyi @WestLangley |
Ports the WebGLRenderer furnace test energy loss fix to WebGPURenderer. The furnace test was losing energy when metalness was between 0 and 1 because the Fdez-Agüera multiscattering formula is designed for pure dielectric OR conductor F0 values, not blended ones. This fix follows the EEVEE/Frostbite approach by: - Adding specularColorBlended property for mixed dielectric/metallic F0 - Keeping pure dielectric specularColor for energy-conserving multiscattering - Computing multiscattering separately for dielectric and metallic paths - Mixing results based on metalness - Using only dielectric path for diffuse energy conservation Changes: - PropertyNode.js: Added diffuseContribution and specularColorBlended properties - MeshPhysicalNodeMaterial.js: Separated dielectric and blended specular color computation - PhysicalLightingModel.js: Updated to compute dual-path multiscattering and use specularColorBlended in BRDF evaluations Related: #32190
Ports the WebGLRenderer furnace test energy loss fix to WebGPURenderer. The furnace test was losing energy when metalness was between 0 and 1 because the Fdez-Agüera multiscattering formula is designed for pure dielectric OR conductor F0 values, not blended ones. This fix follows the EEVEE/Frostbite approach by: - Adding specularColorBlended property for mixed dielectric/metallic F0 - Keeping pure dielectric specularColor for energy-conserving multiscattering - Computing multiscattering separately for dielectric and metallic paths - Mixing results based on metalness - Using only dielectric path for diffuse energy conservation Changes: - PropertyNode.js: Added diffuseContribution and specularColorBlended properties - MeshPhysicalNodeMaterial.js: Separated dielectric and blended specular color computation - PhysicalLightingModel.js: Updated to compute dual-path multiscattering and use specularColorBlended in BRDF evaluations Related: #32190
Description
Fixes energy conservation in the white furnace test when metalness values are between 0 and 1. Previously, intermediate metalness values (especially 0.5-1.0 roughness) were losing energy due to incorrect application of the multiscattering compensation formula.
Problem
The Fdez-Agüera multiscattering formula uses
Favg = F0 + (1 - F0) * (1/21), which is designed for pure dielectric OR conductor F0 values, not blended ones. The previous implementation applied this formula tospecularColor, which was already blended between dielectric (0.04 or IOR-based) and metallic (base color) F0 values based on metalness. This caused incorrect energy compensation for intermediate metalness values.Solution
Following the approach used in EEVEE and Frostbite:
Changes
Material Structure (PhysicalMaterial)
Reorganized and renamed fields for clarity:
diffuseColor- Original base color (before metalness reduction)diffuseContribution- Diffuse component reduced by metalness:baseColor * (1 - metalness)specularColor- Dielectric F0 (0.04 or IOR-based)specularColorBlended- Blended F0:mix(specularColor, diffuseColor, metalness)for direct lightingmetalness- Metalness factorIndirect Specular Lighting (RE_IndirectSpecular_Physical)
vec3 singleScattering = mix(singleScatteringDielectric, singleScatteringMetallic, metalness);vec3 multiScattering = mix(multiScatteringDielectric, multiScatteringMetallic, metalness);Direct Specular Lighting (BRDF_GGX_Multiscatter)
specularColorBlendedfor the blended specular reflectionOther Updates
diffuseContributioninstead of the olddiffuseColorspecularColorBlendeddiffuseContributionandspecularColorBlendedTesting
The white furnace test (
examples/webgl_furnace_test.html) now correctly preserves energy across all metalness (0-1) and roughness (0-1) combinations.Known Issues
computeMultiscatteringIridescencewhen iridescence is enabled, which is physically incorrect (iridescence should only affect dielectric reflections, not metallic ones). This will be addressed in a future PR.References
Scope
This PR addresses the WebGL renderer only. WebGPU renderer fixes will be addressed in a separate PR.
(Made using Claude Code Web)