@@ -8,7 +8,7 @@ import Schlick_to_F0 from './BSDF/Schlick_to_F0.js';
88import BRDF_Sheen from './BSDF/BRDF_Sheen.js' ;
99import { LTC_Evaluate , LTC_Uv } from './BSDF/LTC.js' ;
1010import LightingModel from '../core/LightingModel.js' ;
11- import { diffuseColor , specularColor , specularF90 , roughness , clearcoat , clearcoatRoughness , sheen , sheenRoughness , iridescence , iridescenceIOR , iridescenceThickness , ior , thickness , transmission , attenuationDistance , attenuationColor , dispersion } from '../core/PropertyNode.js' ;
11+ import { diffuseColor , diffuseContribution , specularColor , specularColorBlended , specularF90 , roughness , metalness , clearcoat , clearcoatRoughness , sheen , sheenRoughness , iridescence , iridescenceIOR , iridescenceThickness , ior , thickness , transmission , attenuationDistance , attenuationColor , dispersion } from '../core/PropertyNode.js' ;
1212import { normalView , clearcoatNormalView , normalWorld } from '../accessors/Normal.js' ;
1313import { positionViewDirection , positionView , positionWorld } from '../accessors/Position.js' ;
1414import { Fn , float , vec2 , vec3 , vec4 , mat3 , If } from '../tsl/TSLBase.js' ;
@@ -502,7 +502,7 @@ class PhysicalLightingModel extends LightingModel {
502502 eta2 : iridescenceIOR ,
503503 cosTheta1 : dotNVi ,
504504 thinFilmThickness : iridescenceThickness ,
505- baseF0 : specularColor
505+ baseF0 : specularColorBlended
506506 } ) ;
507507
508508 this . iridescenceF0 = Schlick_to_F0 ( { f : this . iridescenceFresnel , f90 : 1.0 , dotVH : dotNVi } ) ;
@@ -521,8 +521,8 @@ class PhysicalLightingModel extends LightingModel {
521521 n ,
522522 v ,
523523 roughness ,
524- diffuseColor ,
525- specularColor ,
524+ diffuseContribution ,
525+ specularColorBlended ,
526526 specularF90 , // specularF90
527527 position , // positionWorld
528528 modelWorldMatrix , // modelMatrix
@@ -549,13 +549,13 @@ class PhysicalLightingModel extends LightingModel {
549549 // Approximates multi-scattering in order to preserve energy.
550550 // http://www.jcgt.org/published/0008/01/03/
551551
552- computeMultiscattering ( singleScatter , multiScatter , specularF90 ) {
552+ computeMultiscattering ( singleScatter , multiScatter , specularF90 , f0 ) {
553553
554554 const dotNV = normalView . dot ( positionViewDirection ) . clamp ( ) ; // @ TODO: Move to core dotNV
555555
556556 const fab = DFGApprox ( { roughness, dotNV } ) ;
557557
558- const Fr = this . iridescenceF0 ? iridescence . mix ( specularColor , this . iridescenceF0 ) : specularColor ;
558+ const Fr = this . iridescenceF0 ? iridescence . mix ( f0 , this . iridescenceF0 ) : f0 ;
559559
560560 const FssEss = Fr . mul ( fab . x ) . add ( specularF90 . mul ( fab . y ) ) ;
561561
@@ -596,9 +596,9 @@ class PhysicalLightingModel extends LightingModel {
596596
597597 }
598598
599- reflectedLight . directDiffuse . addAssign ( irradiance . mul ( BRDF_Lambert ( { diffuseColor : diffuseColor . rgb } ) ) ) ;
599+ reflectedLight . directDiffuse . addAssign ( irradiance . mul ( BRDF_Lambert ( { diffuseColor : diffuseContribution } ) ) ) ;
600600
601- reflectedLight . directSpecular . addAssign ( irradiance . mul ( BRDF_GGX_Multiscatter ( { lightDirection, f0 : specularColor , f90 : 1 , roughness, f : this . iridescenceFresnel , USE_IRIDESCENCE : this . iridescence , USE_ANISOTROPY : this . anisotropy } ) ) ) ;
601+ reflectedLight . directSpecular . addAssign ( irradiance . mul ( BRDF_GGX_Multiscatter ( { lightDirection, f0 : specularColorBlended , f90 : 1 , roughness, f : this . iridescenceFresnel , USE_IRIDESCENCE : this . iridescence , USE_ANISOTROPY : this . anisotropy } ) ) ) ;
602602
603603 }
604604
@@ -633,11 +633,11 @@ class PhysicalLightingModel extends LightingModel {
633633
634634 // LTC Fresnel Approximation by Stephen Hill
635635 // http://blog.selfshadow.com/publications/s2016-advances/s2016_ltc_fresnel.pdf
636- const fresnel = specularColor . mul ( t2 . x ) . add ( specularColor . oneMinus ( ) . mul ( t2 . y ) ) . toVar ( ) ;
636+ const fresnel = specularColorBlended . mul ( t2 . x ) . add ( specularColorBlended . oneMinus ( ) . mul ( t2 . y ) ) . toVar ( ) ;
637637
638638 reflectedLight . directSpecular . addAssign ( lightColor . mul ( fresnel ) . mul ( LTC_Evaluate ( { N, V, P, mInv, p0, p1, p2, p3 } ) ) ) ;
639639
640- reflectedLight . directDiffuse . addAssign ( lightColor . mul ( diffuseColor ) . mul ( LTC_Evaluate ( { N, V, P, mInv : mat3 ( 1 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 1 ) , p0, p1, p2, p3 } ) ) ) ;
640+ reflectedLight . directDiffuse . addAssign ( lightColor . mul ( diffuseContribution ) . mul ( LTC_Evaluate ( { N, V, P, mInv : mat3 ( 1 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 1 ) , p0, p1, p2, p3 } ) ) ) ;
641641
642642 }
643643
@@ -663,7 +663,7 @@ class PhysicalLightingModel extends LightingModel {
663663
664664 const { irradiance, reflectedLight } = builder . context ;
665665
666- reflectedLight . indirectDiffuse . addAssign ( irradiance . mul ( BRDF_Lambert ( { diffuseColor } ) ) ) ;
666+ reflectedLight . indirectDiffuse . addAssign ( irradiance . mul ( BRDF_Lambert ( { diffuseColor : diffuseContribution } ) ) ) ;
667667
668668 }
669669
@@ -705,16 +705,26 @@ class PhysicalLightingModel extends LightingModel {
705705 }
706706
707707 // Both indirect specular and indirect diffuse light accumulate here
708+ // Compute multiscattering separately for dielectric and metallic, then mix
708709
709- const singleScattering = vec3 ( ) . toVar ( 'singleScattering' ) ;
710- const multiScattering = vec3 ( ) . toVar ( 'multiScattering' ) ;
711- const cosineWeightedIrradiance = iblIrradiance . mul ( 1 / Math . PI ) ;
710+ const singleScatteringDielectric = vec3 ( ) . toVar ( 'singleScatteringDielectric' ) ;
711+ const multiScatteringDielectric = vec3 ( ) . toVar ( 'multiScatteringDielectric' ) ;
712+ const singleScatteringMetallic = vec3 ( ) . toVar ( 'singleScatteringMetallic' ) ;
713+ const multiScatteringMetallic = vec3 ( ) . toVar ( 'multiScatteringMetallic' ) ;
714+
715+ this . computeMultiscattering ( singleScatteringDielectric , multiScatteringDielectric , specularF90 , specularColor ) ;
716+ this . computeMultiscattering ( singleScatteringMetallic , multiScatteringMetallic , specularF90 , diffuseColor . rgb ) ;
712717
713- this . computeMultiscattering ( singleScattering , multiScattering , specularF90 ) ;
718+ // Mix based on metalness
719+ const singleScattering = mix ( singleScatteringDielectric , singleScatteringMetallic , metalness ) ;
720+ const multiScattering = mix ( multiScatteringDielectric , multiScatteringMetallic , metalness ) ;
714721
715- const totalScattering = singleScattering . add ( multiScattering ) ;
722+ // Diffuse energy conservation uses dielectric path
723+ const totalScatteringDielectric = singleScatteringDielectric . add ( multiScatteringDielectric ) ;
716724
717- const diffuse = diffuseColor . mul ( totalScattering . r . max ( totalScattering . g ) . max ( totalScattering . b ) . oneMinus ( ) ) ;
725+ const diffuse = diffuseContribution . mul ( totalScatteringDielectric . r . max ( totalScatteringDielectric . g ) . max ( totalScatteringDielectric . b ) . oneMinus ( ) ) ;
726+
727+ const cosineWeightedIrradiance = iblIrradiance . mul ( 1 / Math . PI ) ;
718728
719729 reflectedLight . indirectSpecular . addAssign ( radiance . mul ( singleScattering ) ) ;
720730 reflectedLight . indirectSpecular . addAssign ( multiScattering . mul ( cosineWeightedIrradiance ) ) ;
0 commit comments