Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit eb1b785

Browse filesBrowse files
committed
Fix specular artifacts for (NdotV < 0)
Cost: 1 VGPR. We clamp NdotV between 0.0001 and 1 as we fill the PreLightData. However, for direct lighting, this changes neither N nor V. Therefore, when we try to use this clamped NdotV value in other geometric calculations, results occasionally make no sense. Caveat: if (NdotV < 0) and (NdotL -> 0), H may point in the opposite hemisphere from N. Clamped XdotH products appear to take care of this issue.
1 parent ffa106e commit eb1b785
Copy full SHA for eb1b785

File tree

Expand file treeCollapse file tree

2 files changed

+16
-13
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

2 files changed

+16
-13
lines changed
Open diff view settings
Collapse file

‎Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.hlsl‎

Copy file name to clipboardExpand all lines: Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.hlsl
+15-11Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,9 @@ void GetBSDFDataDebug(uint paramId, BSDFData bsdfData, inout float3 result, inou
503503
struct PreLightData
504504
{
505505
// General
506-
float NdotV;
506+
float NdotV; // Between 0.0001 and 1
507+
float unNdotV; // Between -1 and 1
508+
507509

508510
// GGX iso
509511
float ggxLambdaV;
@@ -534,9 +536,11 @@ PreLightData GetPreLightData(float3 V, PositionInputs posInput, BSDFData bsdfDat
534536

535537
// General
536538
float3 iblNormalWS = bsdfData.normalWS;
539+
540+
preLightData.unNdotV = dot(bsdfData.normalWS, V);
537541
// GetShiftedNdotV return a positive NdotV
538542
// In case a material use negative normal for double sided lighting like Speedtree they need to do a new calculation
539-
preLightData.NdotV = GetShiftedNdotV(iblNormalWS, V); // Handle artificat for specular lighting
543+
preLightData.NdotV = GetShiftedNdotV(iblNormalWS, V, preLightData.unNdotV);
540544

541545
// GGX iso
542546
preLightData.ggxLambdaV = GetSmithJointGGXLambdaV(preLightData.NdotV, bsdfData.roughness);
@@ -635,7 +639,7 @@ void BSDF( float3 V, float3 L, float3 positionWS, PreLightData preLightData, BS
635639
out float3 specularLighting)
636640
{
637641
float NdotL = saturate(dot(bsdfData.normalWS, L));
638-
float NdotV = preLightData.NdotV;
642+
float NdotV = preLightData.unNdotV; // This value must not be clamped
639643
float LdotV = dot(L, V);
640644
// GCN Optimization: reference PBR Diffuse Lighting for GGX + Smith Microsurfaces
641645
float invLenLV = rsqrt(abs(2.0 * LdotV + 2.0)); // invLenLV = rcp(length(L + V))
@@ -661,12 +665,12 @@ void BSDF( float3 V, float3 L, float3 positionWS, PreLightData preLightData, BS
661665
bsdfData.roughnessB = ClampRoughnessForAnalyticalLights(bsdfData.roughnessB);
662666

663667
#ifdef LIT_USE_BSDF_PRE_LAMBDAV
664-
Vis = V_SmithJointGGXAnisoLambdaV( preLightData.TdotV, preLightData.BdotV, NdotV, TdotL, BdotL, NdotL,
665-
bsdfData.roughnessT, bsdfData.roughnessB, preLightData.anisoGGXLambdaV);
668+
Vis = V_SmithJointGGXAnisoLambdaV(preLightData.TdotV, preLightData.BdotV, preLightData.NdotV, TdotL, BdotL, NdotL,
669+
bsdfData.roughnessT, bsdfData.roughnessB, preLightData.anisoGGXLambdaV);
666670
#else
667671
// TODO: Do comparison between this correct version and the one from isotropic and see if there is any visual difference
668-
Vis = V_SmithJointGGXAniso( preLightData.TdotV, preLightData.BdotV, NdotV, TdotL, BdotL, NdotL,
669-
bsdfData.roughnessT, bsdfData.roughnessB);
672+
Vis = V_SmithJointGGXAniso(preLightData.TdotV, preLightData.BdotV, preLightData.NdotV, TdotL, BdotL, NdotL,
673+
bsdfData.roughnessT, bsdfData.roughnessB);
670674
#endif
671675

672676
D = D_GGXAniso(TdotH, BdotH, NdotH, bsdfData.roughnessT, bsdfData.roughnessB);
@@ -676,9 +680,9 @@ void BSDF( float3 V, float3 L, float3 positionWS, PreLightData preLightData, BS
676680
bsdfData.roughness = ClampRoughnessForAnalyticalLights(bsdfData.roughness);
677681

678682
#ifdef LIT_USE_BSDF_PRE_LAMBDAV
679-
Vis = V_SmithJointGGX(NdotL, NdotV, bsdfData.roughness, preLightData.ggxLambdaV);
683+
Vis = V_SmithJointGGX(NdotL, preLightData.NdotV, bsdfData.roughness, preLightData.ggxLambdaV);
680684
#else
681-
Vis = V_SmithJointGGX(NdotL, NdotV, bsdfData.roughness);
685+
Vis = V_SmithJointGGX(NdotL, preLightData.NdotV, bsdfData.roughness);
682686
#endif
683687
D = D_GGX(NdotH, bsdfData.roughness);
684688
}
@@ -687,9 +691,9 @@ void BSDF( float3 V, float3 L, float3 positionWS, PreLightData preLightData, BS
687691
#ifdef LIT_DIFFUSE_LAMBERT_BRDF
688692
float diffuseTerm = Lambert();
689693
#elif LIT_DIFFUSE_GGX_BRDF
690-
float3 diffuseTerm = DiffuseGGX(bsdfData.diffuseColor, NdotV, NdotL, NdotH, LdotV, bsdfData.perceptualRoughness);
694+
float3 diffuseTerm = DiffuseGGX(bsdfData.diffuseColor, preLightData.NdotV, NdotL, NdotH, LdotV, bsdfData.perceptualRoughness);
691695
#else
692-
float diffuseTerm = DisneyDiffuse(NdotV, NdotL, LdotH, bsdfData.perceptualRoughness);
696+
float diffuseTerm = DisneyDiffuse(preLightData.NdotV, NdotL, LdotH, bsdfData.perceptualRoughness);
693697
#endif
694698

695699
diffuseLighting = bsdfData.diffuseColor * diffuseTerm;
Collapse file

‎Assets/ScriptableRenderPipeline/ShaderLibrary/CommonLighting.hlsl‎

Copy file name to clipboardExpand all lines: Assets/ScriptableRenderPipeline/ShaderLibrary/CommonLighting.hlsl
+1-2Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,8 @@ float GetHorizonOcclusion(float3 V, float3 normalWS, float3 vertexNormal, float
188188
// A way to reduce artifact is to limit NdotV value to not be negative and calculate reflection vector for cubemap with a shifted normal (i.e what depends on the view)
189189
// This is what provide this function
190190
// Note: NdotV return by this function is always positive, no need for saturate
191-
float GetShiftedNdotV(inout float3 N, float3 V)
191+
float GetShiftedNdotV(inout float3 N, float3 V, float NdotV)
192192
{
193-
float NdotV = dot(N, V);
194193
const float limit = 0.0001; // Epsilon value that avoid divide by 0 (several BSDF divide by NdotV)
195194

196195
if (NdotV < limit)

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.