From 586f15513edd509f6ea7258eca52c1038024ac07 Mon Sep 17 00:00:00 2001 From: yum Date: Mon, 30 Jun 2025 14:37:18 -0700 Subject: Simplify wrapped lighting function, fix how NoL is used in brdf --- math.cginc | 42 ++++++++++++++++++++++-------------------- yum_brdf.cginc | 2 +- yum_lighting.cginc | 3 +-- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/math.cginc b/math.cginc index c1e71fb..3112418 100644 --- a/math.cginc +++ b/math.cginc @@ -3,13 +3,17 @@ #include "pema99.cginc" -#define PI 3.14159265358979323846264 -#define TAU (2 * PI) -#define HALF_PI (PI * 0.5) +#define PI 3.14159265358979323846264f +#define TAU (2.0f * PI) +#define HALF_PI (PI * 0.5f) +#define RCP_PI (1.0f / PI) +#define RCP_TAU (1.0f / TAU) #define PHI 1.618033989f +#define RCP_PHI 0.618033989f #define SQRT_2 1.414213562f #define SQRT_2_RCP 0.707106781f #define RCP_SQRT_2 0.707106781f +#define RCP_SQRT_3 0.577350269f #define TWO_OVER_THREE 0.6666666666666666f #define SQRT_3_OVER_2 0.8660254037844386f #define EULERS_CONSTANT 2.718281828f @@ -21,24 +25,22 @@ float pow5(float x) return (tmp * tmp) * x; } +// Wrap NoL. Assume it's already clamped. +// At k=0, you get standard lambertian shading. +// At k=0.5, you get half-lambertian shading. +// At k=1.0, you get flat shading. +// k must be on [0, 1]. +// Energy preserving, within some small bound. float wrapNoL(float NoL, float k) { -#if 0 - // https://www.iro.umontreal.ca/~derek/files/jgt_wrap_final.pdf - return pow(max(1E-4, (NoL + k) / (1 + k)), 1 + k); -#else - float k_sq = k * k; - float b = max(0, lerp(NoL, 1.0, k)); - float p = -6.0 * k_sq + 5.0 * k + 1.0; - // Using the formula - float F = pow(b, p); - - // Approximate integral of NoL with respect to theta - float I = (0.7856 * k_sq - 0.2148 * k) + 1.0; - - float G = F / max(I, 1E-6); - - return G; -#endif + float lambertian = NoL; + float half_lambertian = pow(max(1e-4, (NoL + 0.5f) / (1.0f + 0.5f)), 2); + float flat = RCP_PI; + + if (k < 0.5) { + return lerp(lambertian, half_lambertian, k * 2.0f); + } else { + return lerp(half_lambertian, flat, k * 2.0f - 1.0f); + } } float halfLambertianNoL(float NoL) { diff --git a/yum_brdf.cginc b/yum_brdf.cginc index 67c425c..364a183 100644 --- a/yum_brdf.cginc +++ b/yum_brdf.cginc @@ -129,7 +129,7 @@ float4 YumBRDF(v2f i, const YumLighting light, YumPbr pbr) { float3 diffuseColor = computeDiffuseColor(pbr.albedo, pbr.metallic); // Fd_Burley already includes 1/PI, so multiply by PI to match Unity intensities - float3 Fd = diffuseColor * Fd_Burley(pbr.roughness, NoV, NoL, LoH) * PI; + float3 Fd = diffuseColor * Fd_Burley(pbr.roughness, NoV, NoL_wrapped_d, LoH) * PI; Fd *= light.attenuation * pbr.ao; // Multiply by PI to match Unity intensities (same as Filament's implementation) diff --git a/yum_lighting.cginc b/yum_lighting.cginc index 103eb18..56fca90 100644 --- a/yum_lighting.cginc +++ b/yum_lighting.cginc @@ -316,7 +316,7 @@ YumLighting GetYumLighting(v2f i, YumPbr pbr) { light.specular *= _Brightness_Multiplier; #endif - light.NoL = dot(pbr.normal, light.dir); + light.NoL = saturate(dot(pbr.normal, light.dir)); #if defined(_QUANTIZE_NOL) light.NoL = floor(light.NoL * _Quantize_NoL_Steps) / _Quantize_NoL_Steps; #endif @@ -324,7 +324,6 @@ YumLighting GetYumLighting(v2f i, YumPbr pbr) { light.NoL_wrapped_s = saturate(wrapNoL(light.NoL, _Wrap_NoL_Specular_Strength)); light.NoL_wrapped_d = saturate(wrapNoL(light.NoL, _Wrap_NoL_Diffuse_Strength)); #endif - light.NoL = saturate(light.NoL); return light; } -- cgit v1.2.3