From 5fa1c0ec5b2b59db3858a7dfe9f4001eeeff8cc9 Mon Sep 17 00:00:00 2001 From: yum Date: Mon, 23 Feb 2026 20:20:31 -0800 Subject: Add ambient occlusion & normal filtering --- lighting.cginc | 55 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 15 deletions(-) (limited to 'lighting.cginc') diff --git a/lighting.cginc b/lighting.cginc index 87a3dfc..28ac25b 100755 --- a/lighting.cginc +++ b/lighting.cginc @@ -90,9 +90,9 @@ float4 getDirectLightColorIntensity() { return float4(_LightColor0.xyz, _LightColor0.w); } -float3 getIndirectSpecular(v2f i, float roughness, float3 view_dir, float3 reflect_dir) { +float3 getIndirectSpecular(v2f i, float perceptual_roughness, float3 view_dir, float3 reflect_dir) { UnityGIInput data = InitialiseUnityGIInput(i.worldPos, view_dir); - float3 env_refl = UnityGI_prefilteredRadiance(data, roughness, reflect_dir); + float3 env_refl = UnityGI_prefilteredRadiance(data, perceptual_roughness, reflect_dir); return env_refl; } @@ -133,23 +133,42 @@ float3 yumSH9(float4 n, float3 worldPos, inout LightIndirect light) { dot(light.L01b, n.xyz)); } - // Geomerics SH evaluation - // Extract L0 and optionally incorporate part of L2 - float3 L0 = float3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w); - float3 L0L2 = float3(unity_SHBr.z, unity_SHBg.z, unity_SHBb.z) / 3.0; - L0 = L0 + L0L2; // useL2 = true - - float3 finalSH; - finalSH.r = shEvaluateDiffuseL1Geomerics(L0.r, unity_SHAr.xyz, n.xyz); - finalSH.g = shEvaluateDiffuseL1Geomerics(L0.g, unity_SHAg.xyz, n.xyz); - finalSH.b = shEvaluateDiffuseL1Geomerics(L0.b, unity_SHAb.xyz, n.xyz); + // Unity gives us the first three bands (L0-L2) of SH coefficients as follows: + // unity_SHA*.w: L0 coefficients + // unity_SHA*.xyz: L1 coefficients + // unity_SHB*: first four of the L2 coefficients + // unity_SHC: last L2 coefficient + + // Parse out coefficients into a simpler but less efficient format. + float3 L00 = float3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w); + float3 L1_1 = float3(unity_SHAr.x, unity_SHAg.x, unity_SHAb.x); + float3 L10 = float3(unity_SHAr.y, unity_SHAg.y, unity_SHAb.y); + float3 L11 = float3(unity_SHAr.z, unity_SHAg.z, unity_SHAb.z); + float3 L2_2 = float3(unity_SHBr.x, unity_SHBg.x, unity_SHBb.x); + float3 L2_1 = float3(unity_SHBr.y, unity_SHBg.y, unity_SHBb.y); + float3 L20 = float3(unity_SHBr.z, unity_SHBg.z, unity_SHBb.z); + float3 L21 = float3(unity_SHBr.w, unity_SHBg.w, unity_SHBb.w); + float3 L22 = unity_SHC; + + // Equation 13 from "An Efficient Representation for Irradiance Environment + // Maps" by Ramamoorthi and Hanrahan. Note that the order of some + // coefficients is different, and normalization constants have been + // premultiplied by Unity. + float3 L0 = L00; + float3 L1 = L1_1 * n.x + L10 * n.y + L11 * n.z; + float3 L2 = + L2_2 * n.x * n.y + + L2_1 * n.y * n.z + + L20 * n.z * n.z + + L21 * n.x * n.z + + L22 * (n.x * n.x - n.y * n.y); light.L00 = L0; light.L01r = unity_SHAr.xyz; light.L01g = unity_SHAg.xyz; light.L01b = unity_SHAb.xyz; - return finalSH; + return L0 + L1 + L2; } float4 getIndirectDiffuse(v2f i, Pbr pbr, inout LightIndirect light) { @@ -157,6 +176,12 @@ float4 getIndirectDiffuse(v2f i, Pbr pbr, inout LightIndirect light) { #if defined(FORWARD_BASE_PASS) diffuse.xyz += max(0, yumSH9(float4(i.normal, 1.0), i.worldPos, light)); #endif + +#if defined(_AMBIENT_OCCLUSION) + diffuse.xyz *= lerp(1, _OcclusionMap.Sample(bilinear_repeat_s, i.uv01.xy), 1); + //diffuse.xyz = _OcclusionMap.Sample(bilinear_repeat_s, i.uv01.xy); +#endif + return diffuse; } @@ -208,9 +233,9 @@ void GetLighting(v2f i, Pbr pbr, out LightData data) { data.indirect.double_LoV = saturate(2.0f * indirect_LoV * indirect_LoV - 1.0f); data.indirect.diffuse = getIndirectDiffuse(i, pbr, data.indirect); - data.indirect.specular = getIndirectSpecular(i, pbr.roughness, view_dir, -data.indirect.dir); + data.indirect.specular = getIndirectSpecular(i, pbr.roughness_perceptual, view_dir, -data.indirect.dir); #if defined(_CLEARCOAT) - data.indirect.specular_cc = getIndirectSpecular(i, pbr.cc_roughness, view_dir, dir_cc); + data.indirect.specular_cc = getIndirectSpecular(i, saturate(sqrt(pbr.cc_roughness)), view_dir, dir_cc); #if defined(_CLEARCOAT_MASK) float cc_mask = _Clearcoat_Mask.Sample(bilinear_clamp_s, i.uv01.xy).r; data.indirect.specular_cc *= cc_mask; -- cgit v1.2.3