OSDN Git Service

Added Assets for main menu
[mindgames/Mindgames_main.git] / Mindgames / Library / PackageCache / com.unity.render-pipelines.high-definition@6.9.0-preview / Runtime / Material / Hair / Hair.hlsl
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"
9
10 //-----------------------------------------------------------------------------
11 // Texture and constant buffer declaration
12 //-----------------------------------------------------------------------------
13
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"
16
17 #define DEFAULT_HAIR_SPECULAR_VALUE 0.0465 // Hair is IOR 1.55
18
19 //-----------------------------------------------------------------------------
20 // Helper functions/variable specific to this material
21 //-----------------------------------------------------------------------------
22
23 float3 GetNormalForShadowBias(BSDFData bsdfData)
24 {
25 #if _USE_LIGHT_FACING_NORMAL
26     // TODO: should probably bias towards the light for splines...
27     return bsdfData.geomNormalWS;
28 #else
29     return bsdfData.geomNormalWS;
30 #endif
31 }
32
33 float GetAmbientOcclusionForMicroShadowing(BSDFData bsdfData)
34 {
35     // Don't do micro shadow for hair, don't really make sense
36     return 1.0;
37 }
38
39 void ClampRoughness(inout BSDFData bsdfData, float minRoughness)
40 {
41     bsdfData.perceptualRoughness = max(RoughnessToPerceptualRoughness(minRoughness), bsdfData.perceptualRoughness);
42     bsdfData.secondaryPerceptualRoughness = max(RoughnessToPerceptualRoughness(minRoughness), bsdfData.secondaryPerceptualRoughness);
43 }
44
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)
49 {
50 #ifdef DEBUG_DISPLAY
51     // NOTE: THe _Debug* uniforms come from /HDRP/Debug/DebugDisplay.hlsl
52
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;
58
59     if (overrideAlbedo)
60     {
61         float3 overrideAlbedoValue = _DebugLightingAlbedo.yzw;
62         surfaceData.diffuseColor = overrideAlbedoValue;
63     }
64
65     if (overrideSmoothness)
66     {
67         float overrideSmoothnessValue = _DebugLightingSmoothness.y;
68         surfaceData.perceptualSmoothness = overrideSmoothnessValue;
69         surfaceData.secondaryPerceptualSmoothness = overrideSmoothnessValue;
70     }
71
72     if (overrideNormal)
73     {
74         surfaceData.normalWS = tangentToWorld[2];
75     }
76
77     if (_DebugFullScreenMode == FULLSCREENDEBUGMODE_VALIDATE_DIFFUSE_COLOR)
78     {
79         surfaceData.diffuseColor = pbrDiffuseColorValidate(surfaceData.diffuseColor, DEFAULT_HAIR_SPECULAR_VALUE, false, false).xyz;
80     }
81     else if (_DebugFullScreenMode == FULLSCREENDEBUGMODE_VALIDATE_SPECULAR_COLOR)
82     {
83         surfaceData.diffuseColor = pbrSpecularColorValidate(surfaceData.diffuseColor, DEFAULT_HAIR_SPECULAR_VALUE, false, false).xyz;
84     }
85 #endif
86 }
87
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)
93 {
94 #ifdef DEBUG_DISPLAY
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;
98
99     if (overrideSpecularColor)
100     {
101         float3 overrideSpecularColor = _DebugLightingSpecularColor.yzw;
102         bsdfData.fresnel0 = overrideSpecularColor;
103     }
104 #endif
105 }
106
107 NormalData ConvertSurfaceDataToNormalData(SurfaceData surfaceData)
108 {
109     NormalData normalData;
110     normalData.normalWS = surfaceData.normalWS;
111     normalData.perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(surfaceData.perceptualSmoothness);
112     return normalData;
113 }
114
115 //-----------------------------------------------------------------------------
116 // conversion function for forward
117 //-----------------------------------------------------------------------------
118
119 float RoughnessToBlinnPhongSpecularExponent(float roughness)
120 {
121     return clamp(2 * rcp(roughness * roughness) - 2, FLT_EPS, rcp(FLT_EPS));
122 }
123
124 BSDFData ConvertSurfaceDataToBSDFData(uint2 positionSS, SurfaceData surfaceData)
125 {
126     BSDFData bsdfData;
127     ZERO_INITIALIZE(BSDFData, bsdfData);
128
129     // IMPORTANT: All enable flags are statically know at compile time, so the compiler can do compile time optimization
130     bsdfData.materialFeatures = surfaceData.materialFeatures;
131
132     bsdfData.ambientOcclusion = surfaceData.ambientOcclusion;
133     bsdfData.specularOcclusion = surfaceData.specularOcclusion;
134
135     bsdfData.diffuseColor = surfaceData.diffuseColor;
136
137     bsdfData.normalWS = surfaceData.normalWS;
138     bsdfData.geomNormalWS = surfaceData.geomNormalWS;
139     bsdfData.perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(surfaceData.perceptualSmoothness);
140
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;
145
146     // This is the hair tangent (which represents the hair strand direction, root to tip).
147     bsdfData.hairStrandDirectionWS = surfaceData.hairStrandDirectionWS;
148
149     // Kajiya kay
150     if (HasFlag(surfaceData.materialFeatures, MATERIALFEATUREFLAGS_HAIR_KAJIYA_KAY))
151     {
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;
157
158         float roughness1 = PerceptualRoughnessToRoughness(bsdfData.perceptualRoughness);
159         float roughness2 = PerceptualRoughnessToRoughness(bsdfData.secondaryPerceptualRoughness);
160
161         bsdfData.specularExponent          = RoughnessToBlinnPhongSpecularExponent(roughness1);
162         bsdfData.secondarySpecularExponent = RoughnessToBlinnPhongSpecularExponent(roughness2);
163
164         bsdfData.anisotropy = 0.8; // For hair we fix the anisotropy
165     }
166
167     ApplyDebugToBSDFData(bsdfData);
168
169     return bsdfData;
170 }
171
172 //-----------------------------------------------------------------------------
173 // Debug method (use to display values)
174 //-----------------------------------------------------------------------------
175
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)
178 {
179     GetGeneratedSurfaceDataDebug(paramId, surfaceData, result, needLinearToSRGB);
180
181     // Overide debug value output to be more readable
182     switch (paramId)
183     {
184     case DEBUGVIEW_HAIR_SURFACEDATA_NORMAL_VIEW_SPACE:
185         // Convert to view space
186         result = TransformWorldToViewDir(surfaceData.normalWS) * 0.5 + 0.5;
187         break;
188     case DEBUGVIEW_HAIR_SURFACEDATA_GEOMETRIC_NORMAL_VIEW_SPACE:
189         result = TransformWorldToViewDir(surfaceData.geomNormalWS) * 0.5 + 0.5;
190         break;
191     }
192 }
193
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)
196 {
197     GetGeneratedBSDFDataDebug(paramId, bsdfData, result, needLinearToSRGB);
198
199     // Overide debug value output to be more readable
200     switch (paramId)
201     {
202     case DEBUGVIEW_HAIR_BSDFDATA_NORMAL_VIEW_SPACE:
203         // Convert to view space
204         result = TransformWorldToViewDir(bsdfData.normalWS) * 0.5 + 0.5;
205         break;
206     case DEBUGVIEW_HAIR_BSDFDATA_GEOMETRIC_NORMAL_VIEW_SPACE:
207         result = TransformWorldToViewDir(bsdfData.geomNormalWS) * 0.5 + 0.5;
208         break;
209     }
210 }
211
212 void GetPBRValidatorDebug(SurfaceData surfaceData, inout float3 result)
213 {
214     result = surfaceData.diffuseColor;
215 }
216
217 //-----------------------------------------------------------------------------
218 // PreLightData
219 //
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 //-----------------------------------------------------------------------------
224
225 // Precomputed lighting data to send to the various lighting functions
226 struct PreLightData
227 {
228     float NdotV;        // Could be negative due to normal mapping, use ClampNdotV()
229
230     // IBL
231     float3 iblR;                     // Reflected specular direction, used for IBL in EvaluateBSDF_Env()
232     float  iblPerceptualRoughness;
233
234     float3 specularFGD;              // Store preintegrated BSDF for both specular and diffuse
235     float  diffuseFGD;
236 };
237
238 // This function is call to precompute heavy calculation before lightloop
239 PreLightData GetPreLightData(float3 V, PositionInputs posInput, inout BSDFData bsdfData)
240 {
241     PreLightData preLightData;
242     // Don't init to zero to allow to track warning about uninitialized data
243
244 #if _USE_LIGHT_FACING_NORMAL
245     float3 N = ComputeViewFacingNormal(V, bsdfData.hairStrandDirectionWS);
246 #else
247     float3 N = bsdfData.normalWS;
248 #endif
249
250     preLightData.NdotV = dot(N, V);
251     float clampedNdotV = ClampNdotV(preLightData.NdotV);
252
253     float unused;
254
255     if (HasFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_HAIR_KAJIYA_KAY))
256     {
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;
265     }
266     else
267     {
268         preLightData.iblPerceptualRoughness = bsdfData.perceptualRoughness;
269         preLightData.specularFGD = 1.0;
270         preLightData.diffuseFGD = 1.0;
271     }
272
273     // Stretch hack... Copy-pasted from GGX, ALU-optimized for hair.
274     // float3 iblN = normalize(lerp(bsdfData.normalWS, N, bsdfData.anisotropy));
275     float3 iblN = N;
276     preLightData.iblR = reflect(-V, iblN);
277     preLightData.iblPerceptualRoughness *= saturate(1.2 - abs(bsdfData.anisotropy));
278
279     return preLightData;
280 }
281
282 //-----------------------------------------------------------------------------
283 // bake lighting function
284 //-----------------------------------------------------------------------------
285
286 // This define allow to say that we implement a ModifyBakedDiffuseLighting function to be call in PostInitBuiltinData
287 #define MODIFY_BAKED_DIFFUSE_LIGHTING
288
289 void ModifyBakedDiffuseLighting(float3 V, PositionInputs posInput, SurfaceData surfaceData, inout BuiltinData builtinData)
290 {
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);
294
295     // Add GI transmission contribution to bakeDiffuseLighting, we then drop backBakeDiffuseLighting (i.e it is not used anymore, this save VGPR)
296     {
297         // TODO: disabled until further notice (not clear how to handle occlusion).
298         //builtinData.bakeDiffuseLighting += builtinData.backBakeDiffuseLighting * bsdfData.transmittance;
299     }
300
301     // Premultiply (back) bake diffuse lighting information with diffuse pre-integration
302     builtinData.bakeDiffuseLighting *= preLightData.diffuseFGD * bsdfData.diffuseColor;
303 }
304
305 //-----------------------------------------------------------------------------
306 // light transport functions
307 //-----------------------------------------------------------------------------
308
309 LightTransportData GetLightTransportData(SurfaceData surfaceData, BuiltinData builtinData, BSDFData bsdfData)
310 {
311     LightTransportData lightTransportData;
312
313     // DiffuseColor for lightmapping
314     lightTransportData.diffuseColor = bsdfData.diffuseColor;
315     lightTransportData.emissiveColor = builtinData.emissiveColor;
316
317     return lightTransportData;
318 }
319
320 //-----------------------------------------------------------------------------
321 // LightLoop related function (Only include if required)
322 // HAS_LIGHTLOOP is define in Lighting.hlsl
323 //-----------------------------------------------------------------------------
324
325 #ifdef HAS_LIGHTLOOP
326
327 //-----------------------------------------------------------------------------
328 // BSDF share between directional light, punctual light and area light (reference)
329 //-----------------------------------------------------------------------------
330
331 bool IsNonZeroBSDF(float3 V, float3 L, PreLightData preLightData, BSDFData bsdfData)
332 {
333     return true; // Due to either reflection or transmission being always active
334 }
335
336 CBSDF EvaluateBSDF(float3 V, float3 L, PreLightData preLightData, BSDFData bsdfData)
337 {
338     CBSDF cbsdf;
339     ZERO_INITIALIZE(CBSDF, cbsdf);
340
341     float3 T = bsdfData.hairStrandDirectionWS;
342     float3 N = bsdfData.normalWS;
343
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
349 #else
350     // Double-sided Lambert.
351     float NdotL = dot(N, L);
352 #endif
353
354     float NdotV = preLightData.NdotV;
355     float clampedNdotV = ClampNdotV(NdotV);
356     float clampedNdotL = saturate(NdotL);
357
358     float LdotV, NdotH, LdotH, invLenLV;
359     GetBSDFAngle(V, L, NdotL, NdotV, LdotV, NdotH, LdotH, invLenLV);
360
361     if (HasFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_HAIR_KAJIYA_KAY))
362     {
363         float3 t1 = ShiftTangent(T, N, bsdfData.specularShift);
364         float3 t2 = ShiftTangent(T, N, bsdfData.secondarySpecularShift);
365
366         float3 H = (L + V) * invLenLV;
367
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);
371
372         float3 F = F_Schlick(bsdfData.fresnel0, LdotH);
373
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.
378         cbsdf.diffT = 0;
379     #else
380         // Double-sided Lambert.
381         cbsdf.diffR = Lambert() * clampedNdotL;
382     #endif
383         // Bypass the normal map...
384         float geomNdotV = dot(bsdfData.geomNormalWS, V);
385
386         // G = NdotL * NdotV.
387         cbsdf.specR = 0.25 * F * (hairSpec1 + hairSpec2) * clampedNdotL * saturate(geomNdotV * FLT_MAX);
388
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));
392
393         cbsdf.specT = scatterFresnel1 + bsdfData.rimTransmissionIntensity * scatterFresnel2;
394     }
395
396     return cbsdf;
397 }
398
399 //-----------------------------------------------------------------------------
400 // Surface shading (all light types) below
401 //-----------------------------------------------------------------------------
402
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"
408
409 //-----------------------------------------------------------------------------
410 // EvaluateBSDF_Directional
411 //-----------------------------------------------------------------------------
412
413 DirectLighting EvaluateBSDF_Directional(LightLoopContext lightLoopContext,
414                                         float3 V, PositionInputs posInput, PreLightData preLightData,
415                                         DirectionalLightData lightData, BSDFData bsdfData,
416                                         BuiltinData builtinData)
417 {
418     return ShadeSurface_Directional(lightLoopContext, posInput, builtinData,
419                                     preLightData, lightData, bsdfData, V);
420 }
421
422 //-----------------------------------------------------------------------------
423 // EvaluateBSDF_Punctual (supports spot, point and projector lights)
424 //-----------------------------------------------------------------------------
425
426 DirectLighting EvaluateBSDF_Punctual(LightLoopContext lightLoopContext,
427                                      float3 V, PositionInputs posInput,
428                                      PreLightData preLightData, LightData lightData, BSDFData bsdfData, BuiltinData builtinData)
429 {
430     return ShadeSurface_Punctual(lightLoopContext, posInput, builtinData,
431                                  preLightData, lightData, bsdfData, V);
432 }
433
434 //-----------------------------------------------------------------------------
435 // EvaluateBSDF_Line
436 //-----------------------------------------------------------------------------
437
438 DirectLighting EvaluateBSDF_Line(   LightLoopContext lightLoopContext,
439                                     float3 V, PositionInputs posInput,
440                                     PreLightData preLightData, LightData lightData, BSDFData bsdfData, BuiltinData builtinData)
441 {
442     DirectLighting lighting;
443     ZERO_INITIALIZE(DirectLighting, lighting);
444
445     // TODO
446
447     return lighting;
448 }
449
450 //-----------------------------------------------------------------------------
451 // EvaluateBSDF_Rect
452 //-----------------------------------------------------------------------------
453
454 DirectLighting EvaluateBSDF_Rect(   LightLoopContext lightLoopContext,
455                                     float3 V, PositionInputs posInput,
456                                     PreLightData preLightData, LightData lightData, BSDFData bsdfData, BuiltinData builtinData)
457 {
458     DirectLighting lighting;
459     ZERO_INITIALIZE(DirectLighting, lighting);
460
461     // TODO
462
463     return lighting;
464 }
465
466 DirectLighting EvaluateBSDF_Area(LightLoopContext lightLoopContext,
467     float3 V, PositionInputs posInput,
468     PreLightData preLightData, LightData lightData,
469     BSDFData bsdfData, BuiltinData builtinData)
470 {
471     if (lightData.lightType == GPULIGHTTYPE_TUBE)
472     {
473         return EvaluateBSDF_Line(lightLoopContext, V, posInput, preLightData, lightData, bsdfData, builtinData);
474     }
475     else
476     {
477         return EvaluateBSDF_Rect(lightLoopContext, V, posInput, preLightData, lightData, bsdfData, builtinData);
478     }
479 }
480
481 //-----------------------------------------------------------------------------
482 // EvaluateBSDF_SSLighting for screen space lighting
483 // ----------------------------------------------------------------------------
484
485 IndirectLighting EvaluateBSDF_ScreenSpaceReflection(PositionInputs posInput,
486                                                     PreLightData   preLightData,
487                                                     BSDFData       bsdfData,
488                                                     inout float    reflectionHierarchyWeight)
489 {
490     IndirectLighting lighting;
491     ZERO_INITIALIZE(IndirectLighting, lighting);
492
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);
495
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;
500
501     return lighting;
502 }
503
504 IndirectLighting EvaluateBSDF_ScreenspaceRefraction(LightLoopContext lightLoopContext,
505                                                     float3 V, PositionInputs posInput,
506                                                     PreLightData preLightData, BSDFData bsdfData,
507                                                     EnvLightData envLightData,
508                                                     inout float hierarchyWeight)
509 {
510     IndirectLighting lighting;
511     ZERO_INITIALIZE(IndirectLighting, lighting);
512
513     // TODO
514
515     return lighting;
516 }
517
518 //-----------------------------------------------------------------------------
519 // EvaluateBSDF_Env
520 // ----------------------------------------------------------------------------
521
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)
528 {
529     IndirectLighting lighting;
530     ZERO_INITIALIZE(IndirectLighting, lighting);
531
532     if (GPUImageBasedLightingType == GPUIMAGEBASEDLIGHTINGTYPE_REFRACTION)
533         return lighting;
534
535     float3 envLighting;
536     float3 positionWS = posInput.positionWS;
537     float weight = 1.0;
538
539     float3 R = preLightData.iblR;
540
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);
543
544     float iblMipLevel;
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))
548     {
549         // Empirical remapping
550         iblMipLevel = PositivePow(preLightData.iblPerceptualRoughness, 0.8) * uint(max(_ColorPyramidScale.z - 1, 0));
551     }
552     else
553     {
554         iblMipLevel = PerceptualRoughnessToMipmapLevel(preLightData.iblPerceptualRoughness);
555     }
556
557     float4 preLD = SampleEnv(lightLoopContext, lightData.envIndex, R, iblMipLevel);
558     weight *= preLD.a; // Used by planar reflection to discard pixel
559
560     envLighting = preLightData.specularFGD * preLD.rgb;
561
562     if (HasFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_HAIR_KAJIYA_KAY))
563     {
564         // We tint the HDRI with the secondary lob specular as it is more representatative of indirect lighting on hair.
565         envLighting *= bsdfData.secondarySpecularTint;
566     }
567
568     UpdateLightingHierarchyWeights(hierarchyWeight, weight);
569     envLighting *= weight * lightData.multiplier;
570     lighting.specularReflected = envLighting;
571
572     return lighting;
573 }
574
575 //-----------------------------------------------------------------------------
576 // PostEvaluateBSDF
577 // ----------------------------------------------------------------------------
578
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)
583 {
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);
587
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;
592
593 #ifdef DEBUG_DISPLAY
594     PostEvaluateBSDFDebugDisplay(aoFactor, builtinData, lighting, bsdfData.diffuseColor, diffuseLighting, specularLighting);
595 #endif
596 }
597
598 #endif // #ifdef HAS_LIGHTLOOP