diff options
| author | yum <yum.food.vr@gmail.com> | 2026-03-16 16:22:45 -0700 |
|---|---|---|
| committer | yum <yum.food.vr@gmail.com> | 2026-03-16 16:22:45 -0700 |
| commit | 0b42d463db23d2c6eb0b6651486912ffed2f8857 (patch) | |
| tree | 20fc0398a794429146b7875ae6f655b01ab414de | |
| parent | 1a35d85c623569dd2e61b821bfe3a7f03f99343f (diff) | |
Fix normal filtering, which fixes both IBL and direct lighting flashing
| -rwxr-xr-x | brdf.cginc | 7 | ||||
| -rw-r--r-- | data.cginc | 1 | ||||
| -rwxr-xr-x | pbr.cginc | 28 |
3 files changed, 17 insertions, 19 deletions
@@ -42,7 +42,7 @@ float3 F_Schlick(float LoH, float3 f0, float f90) { // The `max(1e-4, _)` and `min(4096, _)` are hand picked to minimize the issue // of bloom making specular highlights flash as the camera moves. float D_GGX(float roughness, float NoH) { - float r2 = max(1e-4, roughness * roughness); + float r2 = roughness * roughness; float NoH2 = NoH * NoH; float NoH4 = NoH2 * NoH2; @@ -50,7 +50,8 @@ float D_GGX(float roughness, float NoH) { float r2_plus_k = r2 + k; float denom = NoH4 * r2_plus_k * r2_plus_k; - return min(4096, r2 / denom); + //return min(4096, r2 / denom); + return r2 / denom; } // Hammon "PBR Diffuse Lighting for GGX+Smith Microsurfaces" @@ -144,8 +145,6 @@ float4 brdf(Pbr pbr, LightData data, out BrdfData bd) { diffuse += direct_diffuse; } - return float4(specular + diffuse, 1); - // Indirect #if !defined(FURNACE_TEST_DIRECT) && (defined(FORWARD_BASE_PASS) || defined(OUTLINES_PASS)) { @@ -11,6 +11,7 @@ struct Pbr { float4 albedo; + float3 geometric_normal; float3 normal; float3x3 tbn; float smoothness; @@ -94,31 +94,28 @@ float2 parallax_offset(float2 uv, float3 view_dir_world, float3x3 tbn) { } #endif // _PARALLAX_HEIGHTMAP -// Tokuyashi and Kaplanyan 2019 "Improved Geometric Specular Antialiasing" -float normalFiltering(float3 normal, float perceptual_roughness) { - float3 du = ddx(normal); - float3 dv = ddy(normal); +// Tokuyoshi and Kaplanyan 2019 "Improved Geometric Specular Antialiasing" +float normalFiltering(float3 geometric_normal, float perceptual_roughness) { + float3 du = ddx(geometric_normal); + float3 dv = ddy(geometric_normal); - // Boxed equation in section 3.2 "Proposed Error Reduction." - float variance = dot(du, du) + dot(dv, dv); - float sigma = 0.5f; // standard deviation of pixel filter kernel in image space - float Sigma = sigma * sigma * variance; - - // Equation 1 in section 4.2 "Constraint for Conservative Isotropic Filtering" + float variance = _Specular_AA_Variance * (dot(du, du) + dot(dv, dv)); float roughness = perceptual_roughness * perceptual_roughness; - float kappa = 0.18; - roughness = roughness + min(2 * Sigma, kappa); + float kernel_roughness = min(2.0f * variance, _Specular_AA_Threshold); + float square_roughness = saturate(roughness * roughness + kernel_roughness); - return saturate(sqrt(roughness)); + return saturate(sqrt(sqrt(square_roughness))); } void propagateSmoothness(inout Pbr pbr) { - pbr.smoothness = 1.0f - normalFiltering(pbr.normal, 1.0f - pbr.smoothness); + pbr.smoothness = 1.0f - normalFiltering(pbr.geometric_normal, 1.0f - pbr.smoothness); pbr.roughness_perceptual = clamp(1.0f - pbr.smoothness, MIN_PERCEPTUAL_ROUGHNESS, 1); pbr.roughness = clamp(pbr.roughness_perceptual * pbr.roughness_perceptual, MIN_ROUGHNESS, 1); #if defined(_CLEARCOAT) - pbr.cc_roughness = max(MIN_ROUGHNESS, pbr.cc_roughness * pbr.cc_roughness); + pbr.cc_roughness_perceptual = clamp(pbr.cc_roughness_perceptual, MIN_PERCEPTUAL_ROUGHNESS, 1); + pbr.cc_roughness_perceptual = normalFiltering(pbr.geometric_normal, pbr.cc_roughness_perceptual); + pbr.cc_roughness = max(MIN_ROUGHNESS, pbr.cc_roughness_perceptual * pbr.cc_roughness_perceptual); #endif } @@ -181,6 +178,7 @@ Pbr getPbr(v2f i) { Pbr pbr = (Pbr) 0; float3 n = i.normal; + pbr.geometric_normal = n; float3 t = i.tangent.xyz; t = normalize(t - n * dot(n, t)); // Gram-Schmidt to avoid skew float3 b = normalize(cross(n, t)) * i.tangent.w; |
