Variable computeMultiScatteringConst
computeMultiScattering: "\n// multi scattering equations\n// DFG approximation if the environment map has not created a LUT texture\nfn DFGApprox(\n normal: vec3f,\n viewDirection: vec3f,\n roughness: f32,\n) -> vec2f {\n let dotNV: f32 = saturate(dot( normal, viewDirection ));\n\n\tlet c0: vec4f = vec4( -1, -0.0275, -0.572, 0.022 );\n\tlet c1: vec4f = vec4( 1, 0.0425, 1.04, -0.04 );\n\n\tlet r: vec4f = roughness * c0 + c1;\n\tlet a004: f32 = min( r.x * r.x, exp2( -9.28 * dotNV ) ) * r.x + r.y;\n\t\n\tlet fab: vec2f = vec2( -1.04, 1.04 ) * a004 + r.zw;\n\n\treturn fab;\n}\n\n// DFG from LUT texture\nfn DFGFromLUT(\n normal: vec3f,\n viewDirection: vec3f,\n roughness: f32,\n clampSampler: sampler,\n lutTexture: texture_2d<f32>\n) -> vec2f {\n let NdotV: f32 = saturate(dot(normal, viewDirection));\n \n let brdfSamplePoint: vec2f = saturate(vec2(NdotV, roughness));\n \n return textureSampleLevel(\n lutTexture,\n clampSampler,\n brdfSamplePoint,\n 0.0\n ).rg;\n}\n\nstruct DFGDirect {\n dfgV: vec2f,\n dfgL: vec2f\n}\n\nfn DFGDirectApprox(\n normal: vec3f,\n viewDirection: vec3f,\n lightDirection: vec3f,\n roughness: f32\n) -> DFGDirect {\n var dfgDirect: DFGDirect;\n\n let NdotL: f32 = saturate(dot(normal, lightDirection));\n let NdotV: f32 = saturate(dot(normal, viewDirection));\n\n dfgDirect.dfgV = DFGApprox(\n vec3(0.0, 0.0, 1.0),\n vec3(sqrt(1.0 - NdotV * NdotV), 0.0, NdotV),\n roughness,\n );\n\n dfgDirect.dfgL = DFGApprox(\n vec3(0.0, 0.0, 1.0),\n vec3(sqrt(1.0 - NdotL * NdotL), 0.0, NdotL),\n roughness,\n );\n\n return dfgDirect;\n}\n\nfn DFGDirectFromLUT(\n normal: vec3f,\n viewDirection: vec3f,\n lightDirection: vec3f,\n roughness: f32,\n clampSampler: sampler,\n lutTexture: texture_2d<f32>\n) -> DFGDirect {\n var dfgDirect: DFGDirect;\n\n let NdotL: f32 = saturate(dot(normal, lightDirection));\n let NdotV: f32 = saturate(dot(normal, viewDirection));\n\n dfgDirect.dfgV = DFGFromLUT(\n vec3(0.0, 0.0, 1.0),\n vec3(sqrt(1.0 - NdotV * NdotV), 0.0, NdotV),\n roughness,\n clampSampler,\n lutTexture\n );\n\n dfgDirect.dfgL = DFGFromLUT(\n vec3(0.0, 0.0, 1.0),\n vec3(sqrt(1.0 - NdotL * NdotL), 0.0, NdotL),\n roughness,\n clampSampler,\n lutTexture\n );\n\n return dfgDirect;\n}\n\nstruct MultiScattering {\n singleScattering: vec3f,\n multiScattering: vec3f,\n}\n\nfn computeMultiscattering(\n fab: vec2f,\n specularColor: vec3f,\n f90: f32,\n iridescence: f32,\n iridescenceF0: vec3f,\n ptr_multiScattering: ptr<function, MultiScattering>\n) {\n\tvar Fr: vec3f = specularColor;\n Fr = mix(Fr, iridescenceF0, iridescence);\n\n\tlet FssEss: vec3f = Fr * fab.x + f90 * fab.y;\n\n\tlet Ess: f32 = fab.x + fab.y;\n\tlet Ems: f32 = 1.0 - Ess;\n\n\tlet Favg: vec3f = Fr + ( 1.0 - Fr ) * 0.047619; // 1/21\n\tlet Fms: vec3f = FssEss * Favg / ( 1.0 - Ems * Favg );\n\n (*ptr_multiScattering).singleScattering += FssEss;\n\t(*ptr_multiScattering).multiScattering += Fms * Ems;\n}\n" = ...
Helper to implement multi-scattering that compensates for the energy loss in rough surfaces due to multiple reflections. The IBL LUT texture is used to compute multi-scattering, however it can fall back to manually calculation in case it's missing.