summaryrefslogtreecommitdiffstats
path: root/lighting.cginc
diff options
context:
space:
mode:
Diffstat (limited to 'lighting.cginc')
-rw-r--r--lighting.cginc72
1 files changed, 39 insertions, 33 deletions
diff --git a/lighting.cginc b/lighting.cginc
index 5a31a25..87a3dfc 100644
--- a/lighting.cginc
+++ b/lighting.cginc
@@ -96,6 +96,33 @@ float3 getIndirectSpecular(v2f i, float roughness, float3 view_dir, float3 refle
return env_refl;
}
+// Geomerics SH evaluation
+// https://community.arm.com/cfs-file/__key/telligent-evolution-components-attachments/01-2066-00-00-00-01-27-70/Simplifying_2D00_Spherical_2D00_Harmonics_2D00_for_2D00_Lighting.pdf
+float shEvaluateDiffuseL1Geomerics(float L0, float3 L1, float3 n) {
+ // average energy
+ float R0 = max(L0, 0);
+
+ // avg direction of incoming light
+ float3 R1 = 0.5f * L1;
+
+ // directional brightness
+ float lenR1 = length(R1);
+
+ // linear angle between normal and direction 0-1
+ float q = dot(normalize(R1), n) * 0.5 + 0.5;
+ q = saturate(q);
+
+ // power for q
+ // lerps from 1 (linear) to 3 (cubic) based on directionality
+ float p = 1.0f + 2.0f * lenR1 / R0;
+
+ // dynamic range constant
+ // should vary between 4 (highly directional) and 0 (ambient)
+ float a = (1.0f - lenR1 / R0) / (1.0f + lenR1 / R0);
+
+ return R0 * (a + (1.0f - a) * (p + 1.0f) * pow(q, p));
+}
+
float3 yumSH9(float4 n, float3 worldPos, inout LightIndirect light) {
[branch]
if (_UdonLightVolumeEnabled) {
@@ -106,44 +133,23 @@ float3 yumSH9(float4 n, float3 worldPos, inout LightIndirect light) {
dot(light.L01b, n.xyz));
}
- // No light volumes - use SH9
- // 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
-
- // L0 band
+ // 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
- // L1 band
- float3x3 L1m = float3x3(unity_SHAr.xyz, unity_SHAg.xyz, unity_SHAb.xyz);
- float3 L1 = mul(L1m, n);
-
- // L2 band
- float4 v = float4(n.x * n.y, n.y * n.z, n.z * n.z, n.x * n.z);
- float3 L2 =
- float3(dot(unity_SHBr.xyzw, v), dot(unity_SHBg.xyzw, v), dot(unity_SHBb.xyzw, v)) +
- unity_SHC.xyz * (n.x * n.x - n.y * n.y);
-
- // TODO expose this as a parameter
- float wrap_term = 0.0f;
-
- // Original coefficients: 1, 2/3, 1/4.
- // Wrapped coefficients: 1, (2-w)/3, ((1-w)^2)/4.
- float l1_wrap = 1.0f - wrap_term * 0.75f;
- L1 *= l1_wrap;
-
- float l2_wrap_base = 1.0f - wrap_term;
- float l2_wrap = l2_wrap_base * l2_wrap_base;
- L2 *= l2_wrap;
+ 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);
light.L00 = L0;
- light.L01r = unity_SHAr.xyz * l1_wrap;
- light.L01g = unity_SHAg.xyz * l1_wrap;
- light.L01b = unity_SHAb.xyz * l1_wrap;
+ light.L01r = unity_SHAr.xyz;
+ light.L01g = unity_SHAg.xyz;
+ light.L01b = unity_SHAb.xyz;
- return L0 + L1 + L2;
+ return finalSH;
}
float4 getIndirectDiffuse(v2f i, Pbr pbr, inout LightIndirect light) {