From 33a4a6d93f5f6c98cfc1bda95f9d3903310bc511 Mon Sep 17 00:00:00 2001 From: yum Date: Mon, 30 Jun 2025 20:37:47 -0700 Subject: add wrapped spherical harmonics --- yum_brdf.cginc | 9 ++++----- yum_lighting.cginc | 50 ++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/yum_brdf.cginc b/yum_brdf.cginc index 364a183..daa6793 100644 --- a/yum_brdf.cginc +++ b/yum_brdf.cginc @@ -99,10 +99,9 @@ float4 YumBRDF(v2f i, const YumLighting light, YumPbr pbr) { #if defined(_MATERIAL_TYPE_CLOTH_SUBSURFACE) // Energy conservative wrap diffuse for subsurface scattering - float wrap_diffuse = saturate((NoL + 0.5) / 2.25); - Fd *= wrap_diffuse; + Fd *= NoL_wrapped_d; // Apply subsurface color - Fd *= saturate(_Cloth_Subsurface_Color + NoL); + Fd *= saturate(_Cloth_Subsurface_Color + NoL_wrapped_d); #endif // Cloth specular BRDF - multiply by PI to match Unity intensities @@ -110,9 +109,9 @@ float4 YumBRDF(v2f i, const YumLighting light, YumPbr pbr) { #if defined(_MATERIAL_TYPE_CLOTH_SUBSURFACE) // No need to multiply by NoL when using subsurface scattering - direct_cloth = (Fd + Fr * NoL) * light.direct * _Cloth_Direct_Multiplier; + direct_cloth = (Fd + Fr * NoL_wrapped_s) * light.direct * _Cloth_Direct_Multiplier; #else - direct_cloth = (Fd + Fr) * NoL * light.direct * _Cloth_Direct_Multiplier; + direct_cloth = (Fd + Fr) * NoL_wrapped_d * light.direct * _Cloth_Direct_Multiplier; #endif } #endif diff --git a/yum_lighting.cginc b/yum_lighting.cginc index 56fca90..88e8da7 100644 --- a/yum_lighting.cginc +++ b/yum_lighting.cginc @@ -208,24 +208,50 @@ float3 yumSH9(float4 n, float3 worldPos, inout YumLighting light) { L21 * n.x * n.z + L22 * (n.x * n.x - n.y * n.y); +#if defined(_WRAPPED_LIGHTING) + float wrap_term = _Wrap_NoL_Diffuse_Strength; + // Original coefficients: 1, 2/3, 1/4. + // Wrapped coefficients: 1, (2-w)/3, ((1-w)^2)/4. + + // Setting w=0, the l1 band is: + // (2-w)/3 = 2/3 + // 2-w = 2 + // 1-w/2 = 1 + float l1_wrap = 1.0f - wrap_term * 0.75f; + L1 *= l1_wrap; + + // The l2 band is: + // ((1-w)^2)/4 = 1/4 + // (1-w)^2 = 1 + float l2_wrap = (1.0f-wrap_term); + l2_wrap *= l2_wrap; + L2 *= l2_wrap; +#else + float l1_wrap = 1.0f; +#endif + light.L00 = L00; - light.L01r = unity_SHAr.xyz; - light.L01g = unity_SHAg.xyz; - light.L01b = unity_SHAb.xyz; + light.L01r = unity_SHAr.xyz * l1_wrap; + light.L01g = unity_SHAg.xyz * l1_wrap; + light.L01b = unity_SHAb.xyz * l1_wrap; return L0 + L1 + L2; #else LightVolumeSH(worldPos, light.L00, light.L01r, light.L01g, light.L01b); -#if defined(_SPHERICAL_HARMONICS_L1) - return LightVolumeEvaluate(n.xyz, light.L00, light.L01r, light.L01g, light.L01b); -#else - [branch] - if (_UdonLightVolumeEnabled) { - return LightVolumeEvaluate(n.xyz, light.L00, light.L01r, light.L01g, light.L01b); - } else { - return LightVolumeEvaluate(n.xyz, light.L00, 0, 0, 0); - } + +#if defined(_WRAPPED_LIGHTING) + float wrap_term = _Wrap_NoL_Diffuse_Strength; + // Hack. Not energy preserving but sorta close. I think this looks better at fully flat mode. + float l1_wrap = 1.0f - wrap_term * 0.75f; + light.L01r *= l1_wrap; + light.L01g *= l1_wrap; + light.L01b *= l1_wrap; #endif + + return light.L00 + float3( + dot(light.L01r, n.xyz), + dot(light.L01g, n.xyz), + dot(light.L01b, n.xyz)); #endif } -- cgit v1.2.3