1 //-----------------------------------------------------------------------------
2 // SurfaceData and BSDFData
3 //-----------------------------------------------------------------------------
4 // SurfaceData is defined in Hair.cs which generates Hair.cs.hlsl
5 #include "Hair.cs.hlsl"
6 #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/SubsurfaceScattering/SubsurfaceScattering.hlsl"
7 #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/NormalBuffer.hlsl"
8 #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/VolumeRendering.hlsl"
10 //-----------------------------------------------------------------------------
11 // Texture and constant buffer declaration
12 //-----------------------------------------------------------------------------
14 #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/LTCAreaLight/LTCAreaLight.hlsl"
15 #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/PreIntegratedFGD/PreIntegratedFGD.hlsl"
17 #define DEFAULT_HAIR_SPECULAR_VALUE 0.0465 // Hair is IOR 1.55
19 //-----------------------------------------------------------------------------
20 // Helper functions/variable specific to this material
21 //-----------------------------------------------------------------------------
23 float3 GetNormalForShadowBias(BSDFData bsdfData)
25 #if _USE_LIGHT_FACING_NORMAL
26 // TODO: should probably bias towards the light for splines...
27 return bsdfData.geomNormalWS;
29 return bsdfData.geomNormalWS;
33 float GetAmbientOcclusionForMicroShadowing(BSDFData bsdfData)
35 // Don't do micro shadow for hair, don't really make sense
39 void ClampRoughness(inout BSDFData bsdfData, float minRoughness)
41 bsdfData.perceptualRoughness = max(RoughnessToPerceptualRoughness(minRoughness), bsdfData.perceptualRoughness);
42 bsdfData.secondaryPerceptualRoughness = max(RoughnessToPerceptualRoughness(minRoughness), bsdfData.secondaryPerceptualRoughness);
45 // This function is use to help with debugging and must be implemented by any lit material
46 // Implementer must take into account what are the current override component and
47 // adjust SurfaceData properties accordingdly
48 void ApplyDebugToSurfaceData(float3x3 tangentToWorld, inout SurfaceData surfaceData)
51 // NOTE: THe _Debug* uniforms come from /HDRP/Debug/DebugDisplay.hlsl
53 // Override value if requested by user
54 // this can be use also in case of debug lighting mode like diffuse only
55 bool overrideAlbedo = _DebugLightingAlbedo.x != 0.0;
56 bool overrideSmoothness = _DebugLightingSmoothness.x != 0.0;
57 bool overrideNormal = _DebugLightingNormal.x != 0.0;
61 float3 overrideAlbedoValue = _DebugLightingAlbedo.yzw;
62 surfaceData.diffuseColor = overrideAlbedoValue;
65 if (overrideSmoothness)
67 float overrideSmoothnessValue = _DebugLightingSmoothness.y;
68 surfaceData.perceptualSmoothness = overrideSmoothnessValue;
69 surfaceData.secondaryPerceptualSmoothness = overrideSmoothnessValue;
74 surfaceData.normalWS = tangentToWorld[2];
77 if (_DebugFullScreenMode == FULLSCREENDEBUGMODE_VALIDATE_DIFFUSE_COLOR)
79 surfaceData.diffuseColor = pbrDiffuseColorValidate(surfaceData.diffuseColor, DEFAULT_HAIR_SPECULAR_VALUE, false, false).xyz;
81 else if (_DebugFullScreenMode == FULLSCREENDEBUGMODE_VALIDATE_SPECULAR_COLOR)
83 surfaceData.diffuseColor = pbrSpecularColorValidate(surfaceData.diffuseColor, DEFAULT_HAIR_SPECULAR_VALUE, false, false).xyz;
88 // Note: This will be available and used in ShaderPassForward.hlsl since in Hair.shader,
89 // just before including the core code of the pass (ShaderPassForward.hlsl) we include
90 // Material.hlsl (or Lighting.hlsl which includes it) which in turn includes us,
91 // Hair.shader, via the #if defined(UNITY_MATERIAL_*) glue mechanism.
92 void ApplyDebugToBSDFData(inout BSDFData bsdfData)
95 // Override value if requested by user
96 // this can be use also in case of debug lighting mode like specular only
97 bool overrideSpecularColor = _DebugLightingSpecularColor.x != 0.0;
99 if (overrideSpecularColor)
101 float3 overrideSpecularColor = _DebugLightingSpecularColor.yzw;
102 bsdfData.fresnel0 = overrideSpecularColor;
107 NormalData ConvertSurfaceDataToNormalData(SurfaceData surfaceData)
109 NormalData normalData;
110 normalData.normalWS = surfaceData.normalWS;
111 normalData.perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(surfaceData.perceptualSmoothness);
115 //-----------------------------------------------------------------------------
116 // conversion function for forward
117 //-----------------------------------------------------------------------------
119 float RoughnessToBlinnPhongSpecularExponent(float roughness)
121 return clamp(2 * rcp(roughness * roughness) - 2, FLT_EPS, rcp(FLT_EPS));
124 BSDFData ConvertSurfaceDataToBSDFData(uint2 positionSS, SurfaceData surfaceData)
127 ZERO_INITIALIZE(BSDFData, bsdfData);
129 // IMPORTANT: All enable flags are statically know at compile time, so the compiler can do compile time optimization
130 bsdfData.materialFeatures = surfaceData.materialFeatures;
132 bsdfData.ambientOcclusion = surfaceData.ambientOcclusion;
133 bsdfData.specularOcclusion = surfaceData.specularOcclusion;
135 bsdfData.diffuseColor = surfaceData.diffuseColor;
137 bsdfData.normalWS = surfaceData.normalWS;
138 bsdfData.geomNormalWS = surfaceData.geomNormalWS;
139 bsdfData.perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(surfaceData.perceptualSmoothness);
141 // This value will be override by the value in diffusion profile
142 bsdfData.fresnel0 = DEFAULT_HAIR_SPECULAR_VALUE;
143 bsdfData.transmittance = surfaceData.transmittance;
144 bsdfData.rimTransmissionIntensity = surfaceData.rimTransmissionIntensity;
146 // This is the hair tangent (which represents the hair strand direction, root to tip).
147 bsdfData.hairStrandDirectionWS = surfaceData.hairStrandDirectionWS;
150 if (HasFlag(surfaceData.materialFeatures, MATERIALFEATUREFLAGS_HAIR_KAJIYA_KAY))
152 bsdfData.secondaryPerceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(surfaceData.secondaryPerceptualSmoothness);
153 bsdfData.specularTint = surfaceData.specularTint;
154 bsdfData.secondarySpecularTint = surfaceData.secondarySpecularTint;
155 bsdfData.specularShift = surfaceData.specularShift;
156 bsdfData.secondarySpecularShift = surfaceData.secondarySpecularShift;
158 float roughness1 = PerceptualRoughnessToRoughness(bsdfData.perceptualRoughness);
159 float roughness2 = PerceptualRoughnessToRoughness(bsdfData.secondaryPerceptualRoughness);
161 bsdfData.specularExponent = RoughnessToBlinnPhongSpecularExponent(roughness1);
162 bsdfData.secondarySpecularExponent = RoughnessToBlinnPhongSpecularExponent(roughness2);
164 bsdfData.anisotropy = 0.8; // For hair we fix the anisotropy
167 ApplyDebugToBSDFData(bsdfData);
172 //-----------------------------------------------------------------------------
173 // Debug method (use to display values)
174 //-----------------------------------------------------------------------------
176 // This function call the generated debug function and allow to override the debug output if needed
177 void GetSurfaceDataDebug(uint paramId, SurfaceData surfaceData, inout float3 result, inout bool needLinearToSRGB)
179 GetGeneratedSurfaceDataDebug(paramId, surfaceData, result, needLinearToSRGB);
181 // Overide debug value output to be more readable
184 case DEBUGVIEW_HAIR_SURFACEDATA_NORMAL_VIEW_SPACE:
185 // Convert to view space
186 result = TransformWorldToViewDir(surfaceData.normalWS) * 0.5 + 0.5;
188 case DEBUGVIEW_HAIR_SURFACEDATA_GEOMETRIC_NORMAL_VIEW_SPACE:
189 result = TransformWorldToViewDir(surfaceData.geomNormalWS) * 0.5 + 0.5;
194 // This function call the generated debug function and allow to override the debug output if needed
195 void GetBSDFDataDebug(uint paramId, BSDFData bsdfData, inout float3 result, inout bool needLinearToSRGB)
197 GetGeneratedBSDFDataDebug(paramId, bsdfData, result, needLinearToSRGB);
199 // Overide debug value output to be more readable
202 case DEBUGVIEW_HAIR_BSDFDATA_NORMAL_VIEW_SPACE:
203 // Convert to view space
204 result = TransformWorldToViewDir(bsdfData.normalWS) * 0.5 + 0.5;
206 case DEBUGVIEW_HAIR_BSDFDATA_GEOMETRIC_NORMAL_VIEW_SPACE:
207 result = TransformWorldToViewDir(bsdfData.geomNormalWS) * 0.5 + 0.5;
212 void GetPBRValidatorDebug(SurfaceData surfaceData, inout float3 result)
214 result = surfaceData.diffuseColor;
217 //-----------------------------------------------------------------------------
220 // Make sure we respect naming conventions to reuse ShaderPassForward as is,
221 // ie struct (even if opaque to the ShaderPassForward) name is PreLightData,
222 // GetPreLightData prototype.
223 //-----------------------------------------------------------------------------
225 // Precomputed lighting data to send to the various lighting functions
228 float NdotV; // Could be negative due to normal mapping, use ClampNdotV()
231 float3 iblR; // Reflected specular direction, used for IBL in EvaluateBSDF_Env()
232 float iblPerceptualRoughness;
234 float3 specularFGD; // Store preintegrated BSDF for both specular and diffuse
238 // This function is call to precompute heavy calculation before lightloop
239 PreLightData GetPreLightData(float3 V, PositionInputs posInput, inout BSDFData bsdfData)
241 PreLightData preLightData;
242 // Don't init to zero to allow to track warning about uninitialized data
244 #if _USE_LIGHT_FACING_NORMAL
245 float3 N = ComputeViewFacingNormal(V, bsdfData.hairStrandDirectionWS);
247 float3 N = bsdfData.normalWS;
250 preLightData.NdotV = dot(N, V);
251 float clampedNdotV = ClampNdotV(preLightData.NdotV);
255 if (HasFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_HAIR_KAJIYA_KAY))
257 // Note: For Kajiya hair we currently rely on a single cubemap sample instead of two, as in practice smoothness of both lobe aren't too far from each other.
258 // and we take smoothness of the secondary lobe as it is often more rough (it is the colored one).
259 preLightData.iblPerceptualRoughness = bsdfData.secondaryPerceptualRoughness;
260 // TODO: adjust for Blinn-Phong here?
261 GetPreIntegratedFGDGGXAndDisneyDiffuse(clampedNdotV, preLightData.iblPerceptualRoughness, bsdfData.fresnel0, preLightData.specularFGD, preLightData.diffuseFGD, unused);
262 // We used lambert for hair for now
263 // Note: this normalization term is wrong, correct one is (1/(Pi^2)).
264 preLightData.diffuseFGD = 1.0;
268 preLightData.iblPerceptualRoughness = bsdfData.perceptualRoughness;
269 preLightData.specularFGD = 1.0;
270 preLightData.diffuseFGD = 1.0;
273 // Stretch hack... Copy-pasted from GGX, ALU-optimized for hair.
274 // float3 iblN = normalize(lerp(bsdfData.normalWS, N, bsdfData.anisotropy));
276 preLightData.iblR = reflect(-V, iblN);
277 preLightData.iblPerceptualRoughness *= saturate(1.2 - abs(bsdfData.anisotropy));
282 //-----------------------------------------------------------------------------
283 // bake lighting function
284 //-----------------------------------------------------------------------------
286 // This define allow to say that we implement a ModifyBakedDiffuseLighting function to be call in PostInitBuiltinData
287 #define MODIFY_BAKED_DIFFUSE_LIGHTING
289 void ModifyBakedDiffuseLighting(float3 V, PositionInputs posInput, SurfaceData surfaceData, inout BuiltinData builtinData)
291 // To get the data we need to do the whole process - compiler should optimize everything
292 BSDFData bsdfData = ConvertSurfaceDataToBSDFData(posInput.positionSS, surfaceData);
293 PreLightData preLightData = GetPreLightData(V, posInput, bsdfData);
295 // Add GI transmission contribution to bakeDiffuseLighting, we then drop backBakeDiffuseLighting (i.e it is not used anymore, this save VGPR)
297 // TODO: disabled until further notice (not clear how to handle occlusion).
298 //builtinData.bakeDiffuseLighting += builtinData.backBakeDiffuseLighting * bsdfData.transmittance;
301 // Premultiply (back) bake diffuse lighting information with diffuse pre-integration
302 builtinData.bakeDiffuseLighting *= preLightData.diffuseFGD * bsdfData.diffuseColor;
305 //-----------------------------------------------------------------------------
306 // light transport functions
307 //-----------------------------------------------------------------------------
309 LightTransportData GetLightTransportData(SurfaceData surfaceData, BuiltinData builtinData, BSDFData bsdfData)
311 LightTransportData lightTransportData;
313 // DiffuseColor for lightmapping
314 lightTransportData.diffuseColor = bsdfData.diffuseColor;
315 lightTransportData.emissiveColor = builtinData.emissiveColor;
317 return lightTransportData;
320 //-----------------------------------------------------------------------------
321 // LightLoop related function (Only include if required)
322 // HAS_LIGHTLOOP is define in Lighting.hlsl
323 //-----------------------------------------------------------------------------
327 //-----------------------------------------------------------------------------
328 // BSDF share between directional light, punctual light and area light (reference)
329 //-----------------------------------------------------------------------------
331 bool IsNonZeroBSDF(float3 V, float3 L, PreLightData preLightData, BSDFData bsdfData)
333 return true; // Due to either reflection or transmission being always active
336 CBSDF EvaluateBSDF(float3 V, float3 L, PreLightData preLightData, BSDFData bsdfData)
339 ZERO_INITIALIZE(CBSDF, cbsdf);
341 float3 T = bsdfData.hairStrandDirectionWS;
342 float3 N = bsdfData.normalWS;
344 #if _USE_LIGHT_FACING_NORMAL
345 // The Kajiya-Kay model has a "built-in" transmission, and the 'NdotL' is always positive.
346 float cosTL = dot(T, L);
347 float sinTL = sqrt(saturate(1.0 - cosTL * cosTL));
348 float NdotL = sinTL; // Corresponds to the cosine w.r.t. the light-facing normal
350 // Double-sided Lambert.
351 float NdotL = dot(N, L);
354 float NdotV = preLightData.NdotV;
355 float clampedNdotV = ClampNdotV(NdotV);
356 float clampedNdotL = saturate(NdotL);
358 float LdotV, NdotH, LdotH, invLenLV;
359 GetBSDFAngle(V, L, NdotL, NdotV, LdotV, NdotH, LdotH, invLenLV);
361 if (HasFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_HAIR_KAJIYA_KAY))
363 float3 t1 = ShiftTangent(T, N, bsdfData.specularShift);
364 float3 t2 = ShiftTangent(T, N, bsdfData.secondarySpecularShift);
366 float3 H = (L + V) * invLenLV;
368 // Balancing energy between lobes, as well as between diffuse and specular is left to artists.
369 float3 hairSpec1 = bsdfData.specularTint * D_KajiyaKay(t1, H, bsdfData.specularExponent);
370 float3 hairSpec2 = bsdfData.secondarySpecularTint * D_KajiyaKay(t2, H, bsdfData.secondarySpecularExponent);
372 float3 F = F_Schlick(bsdfData.fresnel0, LdotH);
374 #if _USE_LIGHT_FACING_NORMAL
375 // See "Analytic Tangent Irradiance Environment Maps for Anisotropic Surfaces".
376 cbsdf.diffR = rcp(PI * PI) * clampedNdotL;
377 // Transmission is built into the model, and it's not exactly clear how to split it.
380 // Double-sided Lambert.
381 cbsdf.diffR = Lambert() * clampedNdotL;
383 // Bypass the normal map...
384 float geomNdotV = dot(bsdfData.geomNormalWS, V);
386 // G = NdotL * NdotV.
387 cbsdf.specR = 0.25 * F * (hairSpec1 + hairSpec2) * clampedNdotL * saturate(geomNdotV * FLT_MAX);
389 // Yibing's and Morten's hybrid scatter model hack.
390 float scatterFresnel1 = pow(saturate(-LdotV), 9.0) * pow(saturate(1.0 - geomNdotV * geomNdotV), 12.0);
391 float scatterFresnel2 = saturate(PositivePow((1.0 - geomNdotV), 20.0));
393 cbsdf.specT = scatterFresnel1 + bsdfData.rimTransmissionIntensity * scatterFresnel2;
399 //-----------------------------------------------------------------------------
400 // Surface shading (all light types) below
401 //-----------------------------------------------------------------------------
403 // Hair used precomputed transmittance, no thick transmittance required
404 #define MATERIAL_INCLUDE_PRECOMPUTED_TRANSMISSION
405 #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightEvaluation.hlsl"
406 #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/MaterialEvaluation.hlsl"
407 #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/SurfaceShading.hlsl"
409 //-----------------------------------------------------------------------------
410 // EvaluateBSDF_Directional
411 //-----------------------------------------------------------------------------
413 DirectLighting EvaluateBSDF_Directional(LightLoopContext lightLoopContext,
414 float3 V, PositionInputs posInput, PreLightData preLightData,
415 DirectionalLightData lightData, BSDFData bsdfData,
416 BuiltinData builtinData)
418 return ShadeSurface_Directional(lightLoopContext, posInput, builtinData,
419 preLightData, lightData, bsdfData, V);
422 //-----------------------------------------------------------------------------
423 // EvaluateBSDF_Punctual (supports spot, point and projector lights)
424 //-----------------------------------------------------------------------------
426 DirectLighting EvaluateBSDF_Punctual(LightLoopContext lightLoopContext,
427 float3 V, PositionInputs posInput,
428 PreLightData preLightData, LightData lightData, BSDFData bsdfData, BuiltinData builtinData)
430 return ShadeSurface_Punctual(lightLoopContext, posInput, builtinData,
431 preLightData, lightData, bsdfData, V);
434 //-----------------------------------------------------------------------------
436 //-----------------------------------------------------------------------------
438 DirectLighting EvaluateBSDF_Line( LightLoopContext lightLoopContext,
439 float3 V, PositionInputs posInput,
440 PreLightData preLightData, LightData lightData, BSDFData bsdfData, BuiltinData builtinData)
442 DirectLighting lighting;
443 ZERO_INITIALIZE(DirectLighting, lighting);
450 //-----------------------------------------------------------------------------
452 //-----------------------------------------------------------------------------
454 DirectLighting EvaluateBSDF_Rect( LightLoopContext lightLoopContext,
455 float3 V, PositionInputs posInput,
456 PreLightData preLightData, LightData lightData, BSDFData bsdfData, BuiltinData builtinData)
458 DirectLighting lighting;
459 ZERO_INITIALIZE(DirectLighting, lighting);
466 DirectLighting EvaluateBSDF_Area(LightLoopContext lightLoopContext,
467 float3 V, PositionInputs posInput,
468 PreLightData preLightData, LightData lightData,
469 BSDFData bsdfData, BuiltinData builtinData)
471 if (lightData.lightType == GPULIGHTTYPE_TUBE)
473 return EvaluateBSDF_Line(lightLoopContext, V, posInput, preLightData, lightData, bsdfData, builtinData);
477 return EvaluateBSDF_Rect(lightLoopContext, V, posInput, preLightData, lightData, bsdfData, builtinData);
481 //-----------------------------------------------------------------------------
482 // EvaluateBSDF_SSLighting for screen space lighting
483 // ----------------------------------------------------------------------------
485 IndirectLighting EvaluateBSDF_ScreenSpaceReflection(PositionInputs posInput,
486 PreLightData preLightData,
488 inout float reflectionHierarchyWeight)
490 IndirectLighting lighting;
491 ZERO_INITIALIZE(IndirectLighting, lighting);
493 // TODO: this texture is sparse (mostly black). Can we avoid reading every texel? How about using Hi-S?
494 float4 ssrLighting = LOAD_TEXTURE2D_X(_SsrLightingTexture, posInput.positionSS);
496 // Note: RGB is already premultiplied by A.
497 // TODO: we should multiply all indirect lighting by the FGD value only ONCE.
498 lighting.specularReflected = ssrLighting.rgb /* * ssrLighting.a */ * preLightData.specularFGD;
499 reflectionHierarchyWeight = ssrLighting.a;
504 IndirectLighting EvaluateBSDF_ScreenspaceRefraction(LightLoopContext lightLoopContext,
505 float3 V, PositionInputs posInput,
506 PreLightData preLightData, BSDFData bsdfData,
507 EnvLightData envLightData,
508 inout float hierarchyWeight)
510 IndirectLighting lighting;
511 ZERO_INITIALIZE(IndirectLighting, lighting);
518 //-----------------------------------------------------------------------------
520 // ----------------------------------------------------------------------------
522 // _preIntegratedFGD and _CubemapLD are unique for each BRDF
523 IndirectLighting EvaluateBSDF_Env( LightLoopContext lightLoopContext,
524 float3 V, PositionInputs posInput,
525 PreLightData preLightData, EnvLightData lightData, BSDFData bsdfData,
526 int influenceShapeType, int GPUImageBasedLightingType,
527 inout float hierarchyWeight)
529 IndirectLighting lighting;
530 ZERO_INITIALIZE(IndirectLighting, lighting);
532 if (GPUImageBasedLightingType == GPUIMAGEBASEDLIGHTINGTYPE_REFRACTION)
536 float3 positionWS = posInput.positionWS;
539 float3 R = preLightData.iblR;
541 // Note: using influenceShapeType and projectionShapeType instead of (lightData|proxyData).shapeType allow to make compiler optimization in case the type is know (like for sky)
542 EvaluateLight_EnvIntersection(positionWS, bsdfData.normalWS, lightData, influenceShapeType, R, weight);
545 // TODO: We need to match the PerceptualRoughnessToMipmapLevel formula for planar, so we don't do this test (which is specific to our current lightloop)
546 // Specific case for Texture2Ds, their convolution is a gaussian one and not a GGX one - So we use another roughness mip mapping.
547 if (IsEnvIndexTexture2D(lightData.envIndex))
549 // Empirical remapping
550 iblMipLevel = PositivePow(preLightData.iblPerceptualRoughness, 0.8) * uint(max(_ColorPyramidScale.z - 1, 0));
554 iblMipLevel = PerceptualRoughnessToMipmapLevel(preLightData.iblPerceptualRoughness);
557 float4 preLD = SampleEnv(lightLoopContext, lightData.envIndex, R, iblMipLevel);
558 weight *= preLD.a; // Used by planar reflection to discard pixel
560 envLighting = preLightData.specularFGD * preLD.rgb;
562 if (HasFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_HAIR_KAJIYA_KAY))
564 // We tint the HDRI with the secondary lob specular as it is more representatative of indirect lighting on hair.
565 envLighting *= bsdfData.secondarySpecularTint;
568 UpdateLightingHierarchyWeights(hierarchyWeight, weight);
569 envLighting *= weight * lightData.multiplier;
570 lighting.specularReflected = envLighting;
575 //-----------------------------------------------------------------------------
577 // ----------------------------------------------------------------------------
579 void PostEvaluateBSDF( LightLoopContext lightLoopContext,
580 float3 V, PositionInputs posInput,
581 PreLightData preLightData, BSDFData bsdfData, BuiltinData builtinData, AggregateLighting lighting,
582 out float3 diffuseLighting, out float3 specularLighting)
584 AmbientOcclusionFactor aoFactor;
585 GetScreenSpaceAmbientOcclusionMultibounce(posInput.positionSS, preLightData.NdotV, bsdfData.perceptualRoughness, bsdfData.ambientOcclusion, bsdfData.specularOcclusion, bsdfData.diffuseColor, bsdfData.fresnel0, aoFactor);
586 ApplyAmbientOcclusionFactor(aoFactor, builtinData, lighting);
588 // Apply the albedo to the direct diffuse lighting (only once). The indirect (baked)
589 // diffuse lighting has already multiply the albedo in ModifyBakedDiffuseLighting().
590 diffuseLighting = bsdfData.diffuseColor * lighting.direct.diffuse + builtinData.bakeDiffuseLighting + builtinData.emissiveColor;
591 specularLighting = lighting.direct.specular + lighting.indirect.specularReflected;
594 PostEvaluateBSDFDebugDisplay(aoFactor, builtinData, lighting, bsdfData.diffuseColor, diffuseLighting, specularLighting);
598 #endif // #ifdef HAS_LIGHTLOOP