diff options
| author | yum <yum.food.vr@gmail.com> | 2026-03-31 22:13:41 -0700 |
|---|---|---|
| committer | yum <yum.food.vr@gmail.com> | 2026-03-31 22:13:41 -0700 |
| commit | 11aa1cd90b748219ee00c3d6924cc40ca2a5f1f4 (patch) | |
| tree | 1a8dc14f79b1f868ff7a91bffe3f5eee83a7dc12 | |
| parent | 072fa8904087ad780ef09132e0e0717d0eecdb68 (diff) | |
Parameterize glitter angular neighbors visited & filter size
| -rwxr-xr-x | 3ner.shader | 2 | ||||
| -rw-r--r-- | glitter.cginc | 72 | ||||
| -rwxr-xr-x | globals.cginc | 2 | ||||
| -rwxr-xr-x | lighting.cginc | 5 |
4 files changed, 55 insertions, 26 deletions
diff --git a/3ner.shader b/3ner.shader index d5d7815..8558abf 100755 --- a/3ner.shader +++ b/3ner.shader @@ -701,6 +701,8 @@ 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 + [IntRange] _Glitter_Angular_Cells("Angular Cells", Range(1, 4)) = 4 + _Glitter_Filter_Size("Filter Size", Range(0.1, 2.0)) = 0.7 _Glitter_Tint("Tint", Color) = (1, 1, 1, 1) [HideInInspector] m_end_Glitter("Glitter", Float) = 0 //endex diff --git a/glitter.cginc b/glitter.cginc index 908c1ab..a9bbf8b 100644 --- a/glitter.cginc +++ b/glitter.cginc @@ -171,13 +171,15 @@ float3 disk_to_ndf_ggx(float2 v_disk, float alpha) { } // 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 D_Kemppinen(float3 h, float alpha, float glint_alpha, int angular_cells, + float2 uv, float2x2 uv_J, float N, float filter_size, + out float3 micro_normal) { float res = sqrt(N); float2 x_s = uv; float3 x_a_and_d = ndf_to_disk_ggx(h, alpha); float2 x_a = x_a_and_d.xy; float d = x_a_and_d.z; + int angular_sample_count = clamp(angular_cells, 1, 4); float lambda = QueryLod(res * uv_J, filter_size); @@ -185,7 +187,8 @@ float D_Kemppinen(float3 h, float alpha, float glint_alpha, float2 uv, float best_weight = 0; float2 best_g_a = x_a; - [loop] + [unroll] + //[loop] for (float m = 0; m < 2; m += 1) { float l = floor(lambda) + m; @@ -200,29 +203,48 @@ float D_Kemppinen(float3 h, float alpha, float glint_alpha, float2 uv, float2 base_i_a = floor(x_a * res_a) + 0.5; float2 i_a = clamp(base_i_a, 0.5, res_a - 0.5); + float2 angular_frac = frac(x_a * res_a) - 0.5; + float2 angular_step = lerp(float2(-1.0, -1.0), float2(1.0, 1.0), + step(0.0, angular_frac)); float2 base_i_s = floor(x_s * res_s) + 0.5; float2 i_s = clamp(base_i_s, 0.5, res_s - 0.5); - float2 g_s = (i_s + Rand2D(i_s, i_a, l, 1u) - .5) / res_s; - float2 g_a = (i_a + Rand2D(i_s, i_a, l, 2u) - .5) / res_a; - - float r = Rand1D(i_s, i_a, l, 4u); - float roulette = smoothstep(max(.0, r-.1), min(1.0, r+.1), w_lambda); - - float w = roulette * normal(sigma_a, x_a - g_a) - * normal(sigma_s, x_s - g_s) / N; - // This is hacky nonsense intended to improve the 1-sampling case. Original - // code is commented out below. - D_filter += w < 1 ? sqrt(w) * 2 : w; - //D_filter += w; - if (w > best_weight) { - best_weight = w; - best_g_a = g_a; + // This unroll actually does substantially improve benchmarks. + [unroll] + for (int angular_index = 0; angular_index < 4; ++angular_index) { + if (angular_index >= angular_sample_count) { + break; + } + + float2 angular_offset = 0.0; + if (angular_index == 1) { + angular_offset = float2(angular_step.x, 0.0); + } else if (angular_index == 2) { + angular_offset = float2(0.0, angular_step.y); + } else if (angular_index == 3) { + angular_offset = angular_step; + } + + float2 i_a_neighbor = clamp(i_a + angular_offset, 0.5, res_a - 0.5); + float2 g_s = (i_s + Rand2D(i_s, i_a_neighbor, l, 1u) - .5) / res_s; + float2 g_a = (i_a_neighbor + Rand2D(i_s, i_a_neighbor, l, 2u) - .5) / res_a; + + float r = Rand1D(i_s, i_a_neighbor, l, 4u); + float roulette = smoothstep(max(.0, r-.1), min(1.0, r+.1), w_lambda); + + float w = roulette * normal(sigma_a, x_a - g_a) + * normal(sigma_s, x_s - g_s) / N; + // This is hacky nonsense intended to improve the 1-sampling case. Original + // code is commented out below. + D_filter += w < 1 ? sqrt(w) * 2 : w; + //D_filter += w; + if (w > best_weight) { + best_weight = w; + best_g_a = g_a; + } } D_filter += w_lambda * compensation(x_a, sigma_a, res_a); - // This is also hacked in. - D_filter += w_lambda * compensation(x_s, sigma_s, res_s); } micro_normal = normalize(disk_to_ndf_ggx(best_g_a, alpha)); @@ -240,10 +262,10 @@ struct LightGlitter { // Glitter data getter to be run from lighting code. LightGlitter GetGlitterLighting( - float glitter_amount, float glitter_roughness, float2 uv, float3x3 tbn, float roughness, + float glitter_amount, float glitter_roughness, int glitter_angular_cells, + float glitter_filter_size, float2 uv, float3x3 tbn, float roughness, 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)))); float N = 8.0e5f * pow(10.0f, glitter_amount * 6.0f - 2.0f); @@ -251,14 +273,16 @@ LightGlitter GetGlitterLighting( float3 direct_H_tangent = mul(direct_H, transpose(tbn)); float3 direct_micro_normal; // unused g.direct_D = D_Kemppinen(direct_H_tangent, roughness, glitter_roughness, - uv, uv_J, N, glitter_filter_size, direct_micro_normal); + glitter_angular_cells, 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; // 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); + glitter_angular_cells, uv, uv_J, N, glitter_filter_size, + indirect_micro_normal); g.indirect_NoL = max(1e-4, dot(normal, indirect_dir)); g.indirect_LoH = max(1e-4, dot(indirect_dir, indirect_H)); diff --git a/globals.cginc b/globals.cginc index a62d9e5..b7d13dd 100755 --- a/globals.cginc +++ b/globals.cginc @@ -155,6 +155,8 @@ int _Details_UV_Channel; #if defined(_GLITTER) float _Glitter_Amount; float _Glitter_Roughness; +int _Glitter_Angular_Cells; +float _Glitter_Filter_Size; float3 _Glitter_Tint; #endif // _GLITTER diff --git a/lighting.cginc b/lighting.cginc index f4d210c..825671b 100755 --- a/lighting.cginc +++ b/lighting.cginc @@ -281,8 +281,9 @@ void GetLighting(v2f i, Pbr pbr, out LightData data) { 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, glitter_indirect_dir); + _Glitter_Amount, _Glitter_Roughness, _Glitter_Angular_Cells, + _Glitter_Filter_Size, i.uv01.xy, pbr.tbn, pbr.roughness, pbr.normal, + data.common.V, data.direct.H, glitter_indirect_dir); #endif data.common.spec_ao = getSpecularAO(i, pbr, data, reflect_dir); |
