diff options
| author | yum <yum.food.vr@gmail.com> | 2026-03-30 14:54:36 -0700 |
|---|---|---|
| committer | yum <yum.food.vr@gmail.com> | 2026-03-30 14:54:36 -0700 |
| commit | f009c086daa3f93de4a3d9ede315e6bc5f0e8d9b (patch) | |
| tree | 8c425b708f266f476a9a187826f7f9cd6357099b | |
| parent | a4697f5093479c3bc80ed29b2ebf45dc2794a40d (diff) | |
Glitter: move back to dominant direction for IBL
| -rwxr-xr-x | 3ner.shader | 1 | ||||
| -rwxr-xr-x | brdf.cginc | 2 | ||||
| -rw-r--r-- | glitter.cginc | 21 | ||||
| -rwxr-xr-x | globals.cginc | 1 | ||||
| -rwxr-xr-x | lighting.cginc | 43 |
5 files changed, 30 insertions, 38 deletions
diff --git a/3ner.shader b/3ner.shader index 0910996..5cc10be 100755 --- a/3ner.shader +++ b/3ner.shader @@ -661,7 +661,6 @@ Shader "yum_food/3ner" [ThryToggle(_GLITTER)] _Glitter_Enabled("Enable", Float) = 0 _Glitter_Amount("Amount", Range(0, 1)) = 0.5 _Glitter_Roughness("Roughness", Range(0.001, 0.1)) = 0.01 - _Glitter_IBL_Roughness("IBL Roughness", Range(0.001, 1)) = 0.01 _Glitter_Tint("Tint", Color) = (1, 1, 1, 1) [HideInInspector] m_end_Glitter("Glitter", Float) = 0 //endex @@ -236,7 +236,7 @@ float4 brdf(v2f i, Pbr pbr, LightData data, out BrdfData bd) { float3 indirect_f_glitter = F_Schlick(data.glitter.indirect_LoH, 0.15f, 1.0f); float indirect_g_glitter = G_GGXSmith(pbr.roughness, data.glitter.indirect_NoL, data.common.NoV); float3 indirect_specular_glitter = (data.glitter.indirect_D * indirect_g_glitter) - * indirect_f_glitter * data.glitter.indirect_specular * data.glitter.indirect_NoL + * indirect_f_glitter * max(0, data.indirect.L00) * data.glitter.indirect_NoL * _Glitter_Tint; // No spec ao for glitter, please. specular += indirect_specular_glitter * remainder; diff --git a/glitter.cginc b/glitter.cginc index 676b902..022b176 100644 --- a/glitter.cginc +++ b/glitter.cginc @@ -14,9 +14,7 @@ * 1. Syntax changes required to translate GLSL to HLSL. * 2. Stylistic preferences, like using "1" or "1.0" instead of "1.". * 3. The `GetGlitterLighting` function, which populates data required for - * IBL. The original paper only discusses analytic lighting. For IBL, you - * also need the micro-normal to figure out which part of the cubemap to - * sample. + * indirect glitter. The original paper only discusses analytic lighting. * * @article{KPT:2025:Glinty, * title = {Evaluating and Sampling Glinty NDFs in Constant Time}, @@ -171,6 +169,7 @@ float3 disk_to_ndf_ggx(float2 v_disk, float alpha) { return float3(alpha * hemi.xy, hemi.z) / denom; } +// Algorithm 1 from Kemppinen et. al. float D_Kemppinen(float3 h, float alpha, float glint_alpha, float2 uv, float2x2 uv_J, float N, float filter_size, out float3 micro_normal) { float res = sqrt(N); @@ -235,9 +234,6 @@ struct LightGlitter { float direct_D; float indirect_D; - float3 indirect_specular; - float3 indirect_dir; - float3 indirect_H; float indirect_NoL; float indirect_LoH; }; @@ -246,7 +242,7 @@ struct LightGlitter { LightGlitter GetGlitterLighting( float glitter_amount, float glitter_roughness, float2 uv, float3x3 tbn, float roughness, - float3 normal, float3 V, float3 direct_H, float3 indirect_H) { + float3 normal, float3 V, float3 direct_H, float3 indirect_dir) { LightGlitter g; const float glitter_filter_size = 0.7f; float2x2 uv_J = uv_ellipsoid(transpose(float2x2(ddx(uv), ddy(uv)))); @@ -259,19 +255,16 @@ LightGlitter GetGlitterLighting( uv, uv_J, N, glitter_filter_size, direct_micro_normal); // Indirect + float3 indirect_H = normalize(V + indirect_dir); float3 indirect_H_tangent = mul(indirect_H, transpose(tbn)); - float3 indirect_micro_normal; // used to sample cubemap + float3 indirect_micro_normal; // unused, but required by D_Kemppinen g.indirect_D = D_Kemppinen(indirect_H_tangent, roughness, glitter_roughness, uv, uv_J, N, glitter_filter_size, indirect_micro_normal); - // Normal vector is the halfway vector in IBL. - g.indirect_H = normalize(mul(indirect_micro_normal, tbn)); - g.indirect_dir = reflect(-V, g.indirect_H); - g.indirect_NoL = max(1e-4, dot(normal, g.indirect_dir)); - g.indirect_LoH = max(1e-4, dot(g.indirect_dir, g.indirect_H)); + g.indirect_NoL = max(1e-4, dot(normal, indirect_dir)); + g.indirect_LoH = max(1e-4, dot(indirect_dir, indirect_H)); return g; } #endif #endif // __GLITTER_INC - diff --git a/globals.cginc b/globals.cginc index 2b9c163..88fb663 100755 --- a/globals.cginc +++ b/globals.cginc @@ -155,7 +155,6 @@ int _Details_UV_Channel; #if defined(_GLITTER) float _Glitter_Amount; float _Glitter_Roughness; -float _Glitter_IBL_Roughness; float3 _Glitter_Tint; #endif // _GLITTER diff --git a/lighting.cginc b/lighting.cginc index 52c9cac..b6d3f8e 100755 --- a/lighting.cginc +++ b/lighting.cginc @@ -42,6 +42,15 @@ float3 getIndirectSpecular(v2f i, float perceptual_roughness, float3 view_dir, f return env_refl; } +float3 getAverageSHDirection(float3 L1r, float3 L1g, float3 L1b, float3 fallback_dir) { + float3 raw_dir = L1r + L1g + L1b; + float raw_dir_len = length(raw_dir); + if (abs(raw_dir_len) < 1e-3) { + return fallback_dir; + } + return raw_dir / raw_dir_len; +} + // 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) { @@ -139,22 +148,11 @@ float4 getIndirectDiffuse(v2f i, Pbr pbr, inout LightData light) { #endif #if defined(_SHADOWS) || defined(_SSFD) - float3x3 mat = float3x3( - light.indirect.L01r, - light.indirect.L01g, - light.indirect.L01b - ); - // Multiply unit vector by L1 matrix to get vector pointing in direction of - // light. - float3 raw_dir = mul(mat, float3(1,1,1)); - float raw_dir_len = length(raw_dir); - float3 dom_dir = normalize(mul(mat, float3(1,1,1))); - if (abs(raw_dir_len) < 1e-3) { - dom_dir = light.direct.dir; - } else { - dom_dir = raw_dir; - } - dom_dir = normalize(dom_dir); + float3 dom_dir = getAverageSHDirection( + light.indirect.L01r, + light.indirect.L01g, + light.indirect.L01b, + light.direct.dir); light.indirect.diffuse_dominant_dir = dom_dir; #endif @@ -266,11 +264,14 @@ void GetLighting(v2f i, Pbr pbr, out LightData data) { data.indirect.diffuse = getIndirectDiffuse(i, pbr, data); data.indirect.specular = getIndirectSpecular(i, pbr.roughness_perceptual, view_dir, data.indirect.dir, data.indirect.diffuse); #if defined(_GLITTER) + float3 glitter_indirect_dir = getAverageSHDirection( + data.indirect.L01r, + data.indirect.L01g, + data.indirect.L01b, + data.indirect.dir); data.glitter = GetGlitterLighting(_Glitter_Amount, _Glitter_Roughness, i.uv01.xy, pbr.tbn, pbr.roughness, - pbr.normal, data.common.V, data.direct.H, data.indirect.H); - data.glitter.indirect_specular = getIndirectSpecular(i, _Glitter_IBL_Roughness, - view_dir, data.glitter.indirect_dir, data.indirect.diffuse); + pbr.normal, data.common.V, data.direct.H, glitter_indirect_dir); #endif data.common.ao = getAO(i); @@ -299,9 +300,9 @@ void GetLighting(v2f i, Pbr pbr, out LightData data) { data.indirect.specular = HSVtoRGB(tmpHSV); #if defined(_GLITTER) - tmpHSV = RGBtoHSV(data.glitter.indirect_specular); + tmpHSV = RGBtoHSV(data.indirect.L00); tmpHSV[2] = clamp(tmpHSV[2], 0, _Brightness_Clamp_Max); - data.glitter.indirect_specular = HSVtoRGB(tmpHSV); + data.indirect.L00 = HSVtoRGB(tmpHSV); #endif #if defined(_CLEARCOAT) |
