浏览代码

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.
/Branch_Batching2
Evgenii Golubev 7 年前
当前提交
1f9e3e8f
共有 2 个文件被更改,包括 16 次插入13 次删除
  1. 26
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.hlsl
  2. 3
      Assets/ScriptableRenderPipeline/ShaderLibrary/CommonLighting.hlsl

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


struct PreLightData
{
// General
float NdotV;
float NdotV; // Between 0.0001 and 1
float unNdotV; // Between -1 and 1
// GGX iso
float ggxLambdaV;

// General
float3 iblNormalWS = bsdfData.normalWS;
preLightData.unNdotV = dot(bsdfData.normalWS, V);
preLightData.NdotV = GetShiftedNdotV(iblNormalWS, V); // Handle artificat for specular lighting
preLightData.NdotV = GetShiftedNdotV(iblNormalWS, V, preLightData.unNdotV);
// GGX iso
preLightData.ggxLambdaV = GetSmithJointGGXLambdaV(preLightData.NdotV, bsdfData.roughness);

out float3 specularLighting)
{
float NdotL = saturate(dot(bsdfData.normalWS, L));
float NdotV = preLightData.NdotV;
float NdotV = preLightData.unNdotV; // This value must not be clamped
float LdotV = dot(L, V);
// GCN Optimization: reference PBR Diffuse Lighting for GGX + Smith Microsurfaces
float invLenLV = rsqrt(abs(2.0 * LdotV + 2.0)); // invLenLV = rcp(length(L + V))

bsdfData.roughnessB = ClampRoughnessForAnalyticalLights(bsdfData.roughnessB);
#ifdef LIT_USE_BSDF_PRE_LAMBDAV
Vis = V_SmithJointGGXAnisoLambdaV( preLightData.TdotV, preLightData.BdotV, NdotV, TdotL, BdotL, NdotL,
bsdfData.roughnessT, bsdfData.roughnessB, preLightData.anisoGGXLambdaV);
Vis = V_SmithJointGGXAnisoLambdaV(preLightData.TdotV, preLightData.BdotV, preLightData.NdotV, TdotL, BdotL, NdotL,
bsdfData.roughnessT, bsdfData.roughnessB, preLightData.anisoGGXLambdaV);
Vis = V_SmithJointGGXAniso( preLightData.TdotV, preLightData.BdotV, NdotV, TdotL, BdotL, NdotL,
bsdfData.roughnessT, bsdfData.roughnessB);
Vis = V_SmithJointGGXAniso(preLightData.TdotV, preLightData.BdotV, preLightData.NdotV, TdotL, BdotL, NdotL,
bsdfData.roughnessT, bsdfData.roughnessB);
#endif
D = D_GGXAniso(TdotH, BdotH, NdotH, bsdfData.roughnessT, bsdfData.roughnessB);

bsdfData.roughness = ClampRoughnessForAnalyticalLights(bsdfData.roughness);
#ifdef LIT_USE_BSDF_PRE_LAMBDAV
Vis = V_SmithJointGGX(NdotL, NdotV, bsdfData.roughness, preLightData.ggxLambdaV);
Vis = V_SmithJointGGX(NdotL, preLightData.NdotV, bsdfData.roughness, preLightData.ggxLambdaV);
Vis = V_SmithJointGGX(NdotL, NdotV, bsdfData.roughness);
Vis = V_SmithJointGGX(NdotL, preLightData.NdotV, bsdfData.roughness);
#endif
D = D_GGX(NdotH, bsdfData.roughness);
}

float diffuseTerm = Lambert();
#elif LIT_DIFFUSE_GGX_BRDF
float3 diffuseTerm = DiffuseGGX(bsdfData.diffuseColor, NdotV, NdotL, NdotH, LdotV, bsdfData.perceptualRoughness);
float3 diffuseTerm = DiffuseGGX(bsdfData.diffuseColor, preLightData.NdotV, NdotL, NdotH, LdotV, bsdfData.perceptualRoughness);
float diffuseTerm = DisneyDiffuse(NdotV, NdotL, LdotH, bsdfData.perceptualRoughness);
float diffuseTerm = DisneyDiffuse(preLightData.NdotV, NdotL, LdotH, bsdfData.perceptualRoughness);
#endif
diffuseLighting = bsdfData.diffuseColor * diffuseTerm;

3
Assets/ScriptableRenderPipeline/ShaderLibrary/CommonLighting.hlsl


// 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)
// This is what provide this function
// Note: NdotV return by this function is always positive, no need for saturate
float GetShiftedNdotV(inout float3 N, float3 V)
float GetShiftedNdotV(inout float3 N, float3 V, float NdotV)
float NdotV = dot(N, V);
const float limit = 0.0001; // Epsilon value that avoid divide by 0 (several BSDF divide by NdotV)
if (NdotV < limit)

正在加载...
取消
保存