From 0425eadf188ebac3c370942dd55f9ba8e0f5afa9 Mon Sep 17 00:00:00 2001 From: yum Date: Mon, 20 Jul 2026 16:53:54 -0700 Subject: Clanker glitter cleanups GPT-5.6 sol medium. Asked it to spot any issues, gave it the Kemppinen et. al. paper and their source code as reference. --- glitter.cginc | 94 ++++++++++++++++++++++++++++++++++++++++++---------------- globals.cginc | 2 +- lighting.cginc | 6 +++- 3 files changed, 74 insertions(+), 28 deletions(-) diff --git a/glitter.cginc b/glitter.cginc index baf6200..512be96 100644 --- a/glitter.cginc +++ b/glitter.cginc @@ -170,11 +170,31 @@ float integrate_box(float2 x, float2 size, float2 mu, float2x2 sigma, sqrt(sigma[1][1]), lower_limit.y, upper_limit.y); } -float compensation(float2 x, float2x2 sigma, float res) { +float compensation(float2 x, float2x2 sigma, float res, float2 base_i, + float2 neighbor_step, int cell_count) { float containing = integrate_box(0.5, 0.5, x, sigma, 0.0, 1.0); - float2 sampled_cell_center = (floor(x * res) + 0.5) / res; - float explicitly_evaluated = - integrate_box(sampled_cell_center, 1.0 / res, x, sigma, 0, 1); + float explicitly_evaluated = 0.0; + + [loop] + for (int cell_index = 0; cell_index < 4; ++cell_index) { + if (cell_index >= cell_count) { + break; + } + + float2 cell_offset = 0.0; + if (cell_index == 1) { + cell_offset = float2(neighbor_step.x, 0.0); + } else if (cell_index == 2) { + cell_offset = float2(0.0, neighbor_step.y); + } else if (cell_index == 3) { + cell_offset = neighbor_step; + } + + float2 sampled_cell_center = (base_i + cell_offset) / res; + explicitly_evaluated += integrate_box(sampled_cell_center, 0.5 / res, + x, sigma, 0.0, 1.0); + } + return containing - explicitly_evaluated; } @@ -199,14 +219,16 @@ float D_Kemppinen(float3 h, float alpha, float glint_alpha, int angular_cells, float d = x_a_and_d.z; int angular_sample_count = clamp(angular_cells, 1, 4); - float lambda = QueryLod(res * uv_J, filter_size); + // Both the spatial and angular neighborhoods require at least a 2x2 grid. + float max_lod = floor(log2(res)) - 1.0; + float lambda = clamp(QueryLod(res * uv_J, filter_size), 1.0, + max_lod); float D_filter = 0; float best_weight = 0; float2 best_g_a = x_a; - [unroll] - //[loop] + [loop] for (float m = 0; m < 2; m += 1) { float l = floor(lambda) + m; @@ -224,12 +246,20 @@ float D_Kemppinen(float3 h, float alpha, float glint_alpha, int angular_cells, 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)); + // At the domain boundary, point inward so all four candidates remain + // distinct rather than accumulating the same random point repeatedly. + angular_step = lerp(angular_step, -angular_step, + step(i_a + angular_step, 0.0) + step(res_a, i_a + angular_step)); 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 spatial_frac = frac(x_s * res_s) - 0.5; + float2 spatial_step = lerp(float2(-1.0, -1.0), float2(1.0, 1.0), + step(0.0, spatial_frac)); + spatial_step = lerp(spatial_step, -spatial_step, + step(i_s + spatial_step, 0.0) + step(res_s, i_s + spatial_step)); - // This unroll actually does substantially improve benchmarks. - [unroll] + [loop] for (int angular_index = 0; angular_index < 4; ++angular_index) { if (angular_index >= angular_sample_count) { break; @@ -244,25 +274,37 @@ float D_Kemppinen(float3 h, float alpha, float glint_alpha, int angular_cells, 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; + float2 i_a_neighbor = i_a + angular_offset; + + [loop] + for (int spatial_index = 0; spatial_index < 4; ++spatial_index) { + float2 spatial_offset = 0.0; + if (spatial_index == 1) { + spatial_offset = float2(spatial_step.x, 0.0); + } else if (spatial_index == 2) { + spatial_offset = float2(0.0, spatial_step.y); + } else if (spatial_index == 3) { + spatial_offset = spatial_step; + } + + float2 i_s_neighbor = i_s + spatial_offset; + float2 g_s = (i_s_neighbor + Rand2D(i_s_neighbor, i_a_neighbor, l, 1u) - .5) / res_s; + float2 g_a = (i_a_neighbor + Rand2D(i_s_neighbor, i_a_neighbor, l, 2u) - .5) / res_a; + + float r = Rand1D(i_s_neighbor, 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; + 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); + D_filter += w_lambda * compensation(x_a, sigma_a, res_a, i_a, + angular_step, angular_sample_count); } micro_normal = normalize(disk_to_ndf_ggx(best_g_a, alpha)); diff --git a/globals.cginc b/globals.cginc index af0f367..efa8670 100755 --- a/globals.cginc +++ b/globals.cginc @@ -163,11 +163,11 @@ int _Glitter_Angular_Cells; float _Glitter_Filter_Size; float3 _Glitter_Tint; float _Glitter_UV_Channel; +float4 _Glitter_Mask_ST; #endif // _GLITTER #if defined(_GLITTER_MASK) texture2D _Glitter_Mask; -float4 _Glitter_Mask_ST; #endif // _GLITTER_MASK #if defined(_GLITTER_BASE_ROUGHNESS_OVERRIDE) diff --git a/lighting.cginc b/lighting.cginc index 8642c1d..db9cee0 100755 --- a/lighting.cginc +++ b/lighting.cginc @@ -286,8 +286,12 @@ void GetLighting(v2f i, Pbr pbr, out LightData data) { float glitter_roughness = pbr.roughness; #endif #if defined(_GLITTER_NORMAL_OVERRIDE) - float3 glitter_normal = _Glitter_Normal_Override.Sample(bilinear_clamp_s, i.uv01.xy) * 2 - 1; + float2 glitter_normal_uv = UV_SCOFF(i, _Glitter_Normal_Override_ST, + _Glitter_UV_Channel); + float3 glitter_normal = _Glitter_Normal_Override.Sample( + bilinear_clamp_s, glitter_normal_uv).xyz * 2 - 1; glitter_normal = glitter_normal.xzy * float3(-1, 1, -1); + glitter_normal = UnityObjectToWorldNormal(glitter_normal); float3x3 tbn = tbn_from_normal_tangent(glitter_normal, i.tangent); #else float3 glitter_normal = pbr.normal; -- cgit v1.2.3