summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryum <yum.food.vr@gmail.com>2026-07-20 16:53:54 -0700
committeryum <yum.food.vr@gmail.com>2026-07-20 16:53:55 -0700
commit0425eadf188ebac3c370942dd55f9ba8e0f5afa9 (patch)
treeb66eb5ce6981e88d91ca317c545783e3dad9fc2d
parentda12f242c6d8da930aa3c2e90fd21a637cd1f195 (diff)
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.
-rw-r--r--glitter.cginc94
-rwxr-xr-xglobals.cginc2
-rwxr-xr-xlighting.cginc6
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;