diff --git a/features/Hair Specular/Shaders/Hair/Hair.hlsli b/features/Hair Specular/Shaders/Hair/Hair.hlsli index 8fad10b14d..bdb742e906 100644 --- a/features/Hair Specular/Shaders/Hair/Hair.hlsli +++ b/features/Hair Specular/Shaders/Hair/Hair.hlsli @@ -96,7 +96,7 @@ namespace Hair const float3 Lp = L - NdotL * N; const float3 Vp = V - NdotL * N; - const float cosPhi = dot(Lp, Vp) * rsqrt(dot(Lp, Lp) * dot(Vp, Vp) + 1e-4); + const float cosPhi = dot(Lp, Vp) * rsqrt(dot(Lp, Lp) * dot(Vp, Vp) + EPSILON_DIVISION); const float cosHalfPhi = sqrt(saturate(0.5 + 0.5 * cosPhi)); float n_prime = 1.19 / cosThetaD + 0.36 * cosThetaD; diff --git a/package/Shaders/Common/BRDF.hlsli b/package/Shaders/Common/BRDF.hlsli index 8f1faf4489..a7f01906e1 100644 --- a/package/Shaders/Common/BRDF.hlsli +++ b/package/Shaders/Common/BRDF.hlsli @@ -41,7 +41,7 @@ namespace BRDF float2 cos_alpha_beta = NdotV < NdotL ? float2(NdotV, NdotL) : float2(NdotL, NdotV); float2 sin_alpha_beta = sqrt(saturate(1.0 - cos_alpha_beta * cos_alpha_beta)); - float C = sin_alpha_beta.x * sin_alpha_beta.y / (1e-6 + cos_alpha_beta.y); + float C = sin_alpha_beta.x * sin_alpha_beta.y / (EPSILON_DIVISION + cos_alpha_beta.y); return (1 / Math::PI) * (A + B * max(0.0, gamma) * C); } @@ -131,10 +131,10 @@ namespace BRDF // [Estevez et al. 2017, "Production Friendly Microfacet Sheen BRDF"] float D_Charlie(float roughness, float NdotH) { - float invAlpha = pow(roughness, -4); + float invAlpha = pow(abs(roughness), -4); float cos2h = NdotH * NdotH; - float sin2h = max(1.0 - cos2h, 1e-5); - return (2.0 + invAlpha) * pow(sin2h, invAlpha * 0.5) / Math::TAU; + float sin2h = 1.0 - cos2h; + return (2.0 + invAlpha) * pow(abs(sin2h), invAlpha * 0.5) / Math::TAU; } // Smith term for GGX @@ -145,7 +145,7 @@ namespace BRDF float a2 = a * a; float Vis_SmithV = NdotV + sqrt(a2 + (1.0 - a2) * NdotV * NdotV); float Vis_SmithL = NdotL + sqrt(a2 + (1.0 - a2) * NdotL * NdotL); - return rcp(Vis_SmithV * Vis_SmithL); + return rcp(max(Vis_SmithV * Vis_SmithL, EPSILON_DIVISION)); } // Appoximation of joint Smith term for GGX @@ -155,7 +155,7 @@ namespace BRDF float a = roughness * roughness; float Vis_SmithV = NdotL * (NdotV * (1.0 + a) + a); float Vis_SmithL = NdotV * (NdotL * (1.0 + a) + a); - return rcp(Vis_SmithV + Vis_SmithL) * 0.5; + return rcp(max(Vis_SmithV + Vis_SmithL, EPSILON_DIVISION)) * 0.5; } float Vis_SmithJoint(float roughness, float NdotV, float NdotL) @@ -164,14 +164,14 @@ namespace BRDF float a2 = a * a; float Vis_SmithV = NdotL * sqrt(a2 + (1.0 - a2) * NdotV * NdotV); float Vis_SmithL = NdotV * sqrt(a2 + (1.0 - a2) * NdotL * NdotL); - return rcp(Vis_SmithV + Vis_SmithL) * 0.5; + return rcp(max(Vis_SmithV + Vis_SmithL, EPSILON_DIVISION)) * 0.5; } float Vis_SmithJointAniso(float alphaX, float alphaY, float NdotL, float NdotV, float XdotL, float YdotL, float XdotV, float YdotV) { float Vis_SmithV = NdotL * length(float3(alphaX * XdotV, alphaY * YdotV, NdotV)); float Vis_SmithL = NdotV * length(float3(alphaX * XdotL, alphaY * YdotL, NdotL)); - return rcp(Vis_SmithV + Vis_SmithL) * 0.5; + return rcp(max(Vis_SmithV + Vis_SmithL, EPSILON_DIVISION)) * 0.5; } // [Estevez and Kulla 2017, "Production Friendly Microfacet Sheen BRDF"] @@ -192,13 +192,13 @@ namespace BRDF { float visV = NdotV < 0.5 ? exp(Vis_Charlie_L(NdotV, roughness)) : exp(2.0 * Vis_Charlie_L(0.5, roughness) - Vis_Charlie_L(1.0 - NdotV, roughness)); float visL = NdotL < 0.5 ? exp(Vis_Charlie_L(NdotL, roughness)) : exp(2.0 * Vis_Charlie_L(0.5, roughness) - Vis_Charlie_L(1.0 - NdotL, roughness)); - return rcp(((1.0 + visV + visL) * (4.0 * NdotL * NdotV))); + return rcp(((1.0 + visV + visL) * max(4.0 * NdotL * NdotV, EPSILON_DIVISION))); } // [Neubelt et al. 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886"] float Vis_Neubelt(float NdotV, float NdotL) { - return rcp(4.0 * (NdotL + NdotV - NdotL * NdotV)); + return rcp(4.0 * max(NdotL + NdotV - NdotL * NdotV, EPSILON_DIVISION)); } // [Lazarov 2013, "Getting More Physical in Call of Duty: Black Ops II"] diff --git a/package/Shaders/Common/Math.hlsli b/package/Shaders/Common/Math.hlsli index 2e7cc083c3..451c52f2f0 100644 --- a/package/Shaders/Common/Math.hlsli +++ b/package/Shaders/Common/Math.hlsli @@ -1,6 +1,9 @@ #ifndef __MATH_DEPENDENCY_HLSL__ #define __MATH_DEPENDENCY_HLSL__ +#define EPSILON_DOT_CLAMP 1e-5f // For dot product clamping +#define EPSILON_DIVISION 1e-6f // For division to avoid division by zero + namespace Math { static const float4x4 IdentityMatrix = { diff --git a/package/Shaders/Common/PBR.hlsli b/package/Shaders/Common/PBR.hlsli index 24205e1f6d..c0795cb8ed 100644 --- a/package/Shaders/Common/PBR.hlsli +++ b/package/Shaders/Common/PBR.hlsli @@ -216,7 +216,7 @@ namespace PBR const float3 Lp = L - NdotL * N; const float3 Vp = V - NdotL * N; - const float cosPhi = dot(Lp, Vp) * rsqrt(dot(Lp, Lp) * dot(Vp, Vp) + 1e-4); + const float cosPhi = dot(Lp, Vp) * rsqrt(dot(Lp, Lp) * dot(Vp, Vp) + EPSILON_DIVISION); const float cosHalfPhi = sqrt(saturate(0.5 + 0.5 * cosPhi)); float n_prime = 1.19 / cosThetaD + 0.36 * cosThetaD; @@ -309,8 +309,8 @@ namespace PBR float NdotH = dot(N, H); float VdotH = dot(V, H); - float satNdotL = clamp(NdotL, 1e-5, 1); - float satNdotV = saturate(abs(NdotV) + 1e-5); + float satNdotL = clamp(NdotL, EPSILON_DOT_CLAMP, 1); + float satNdotV = saturate(abs(NdotV) + EPSILON_DOT_CLAMP); float satVdotL = saturate(VdotL); float satNdotH = saturate(NdotH); float satVdotH = saturate(VdotH); @@ -364,8 +364,8 @@ namespace PBR float coatVdotH = satVdotH; [branch] if ((PBRFlags & Flags::CoatNormal) != 0) { - coatNdotL = clamp(dot(coatN, coatL), 1e-5, 1); - coatNdotV = saturate(abs(dot(coatN, coatV)) + 1e-5); + coatNdotL = clamp(dot(coatN, coatL), EPSILON_DOT_CLAMP, 1); + coatNdotV = saturate(abs(dot(coatN, coatV)) + EPSILON_DOT_CLAMP); coatNdotH = saturate(dot(coatN, coatH)); coatVdotH = saturate(dot(coatV, coatH)); } @@ -390,8 +390,8 @@ namespace PBR const float wetnessF0 = 0.02; float3 H = normalize(V + L); - float NdotL = clamp(dot(N, L), 1e-5, 1); - float NdotV = saturate(abs(dot(N, V)) + 1e-5); + float NdotL = clamp(dot(N, L), EPSILON_DOT_CLAMP, 1); + float NdotV = saturate(abs(dot(N, V)) + EPSILON_DOT_CLAMP); float NdotH = saturate(dot(N, H)); float VdotH = saturate(dot(V, H)); @@ -483,7 +483,7 @@ namespace PBR const float wetnessStrength = 1; const float wetnessF0 = 0.02; - float NdotV = saturate(abs(dot(N, V)) + 1e-5); + float NdotV = saturate(abs(dot(N, V)) + EPSILON_DOT_CLAMP); float2 specularBRDF = BRDF::EnvBRDFApproxLazarov(roughness, NdotV); float3 specularLobeWeight = wetnessF0 * specularBRDF.x + specularBRDF.y;