diff options
| author | yum <yum.food.vr@gmail.com> | 2026-07-20 17:39:35 -0700 |
|---|---|---|
| committer | yum <yum.food.vr@gmail.com> | 2026-07-20 17:39:35 -0700 |
| commit | b7d6ad400c41fcc0608e2dc15ec45d3692d82f16 (patch) | |
| tree | 44492271c9ea186eeda984424ee360a4d2aff760 /glitter.cginc | |
| parent | 0425eadf188ebac3c370942dd55f9ba8e0f5afa9 (diff) | |
More clanker adjustments to glitter
Diffstat (limited to 'glitter.cginc')
| -rw-r--r-- | glitter.cginc | 45 |
1 files changed, 37 insertions, 8 deletions
diff --git a/glitter.cginc b/glitter.cginc index 512be96..5475ec7 100644 --- a/glitter.cginc +++ b/glitter.cginc @@ -35,6 +35,12 @@ // Remaps [0, UINT_MAX] to [0, 1] #define UINT_TO_UNIT (1.0 / 4294967296.0) +#define GLITTER_AMOUNT_MAX 64.0 +#define GLITTER_REFERENCE_AMOUNT 0.5 +#define GLITTER_REFERENCE_N 8.0e6 +#define GLITTER_POPULATION_SCALE \ + (GLITTER_AMOUNT_MAX / GLITTER_REFERENCE_AMOUNT) + // Lambert azimuthal equal area projection float2 lambert(float3 v) { return v.xy / sqrt(1 + v.z); @@ -210,7 +216,7 @@ 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, int angular_cells, - float2 uv, float2x2 uv_J, float N, float filter_size, + float2 uv, float2x2 uv_J, float N, float amount, float filter_size, out float3 micro_normal) { float res = sqrt(N); float2 x_s = uv; @@ -219,6 +225,21 @@ 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); + // The paper normalizes both Gaussian kernels and the point population, so + // narrower kernels and smaller populations have taller individual peaks. + // That is desirable for an energy-preserving NDF, but makes roughness and + // density alter the apparent size of a glint. + // Preserve the peaks at the original defaults instead: roughness controls + // angular width, filter_size controls spatial width, and amount controls only + // how many flakes are active. + float angular_peak_scale = pow(glint_alpha / 0.01, 2.0); + float spatial_peak_scale = pow(filter_size / 0.7, 2.0); + // Scaling the maximum population and each point's weight together keeps the + // reference amount's population, peak, and average energy unchanged. + float profile_scale = GLITTER_POPULATION_SCALE + * angular_peak_scale * spatial_peak_scale; + float amount_fraction = saturate(amount / GLITTER_AMOUNT_MAX); + // 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, @@ -293,9 +314,12 @@ float D_Kemppinen(float3 h, float alpha, float glint_alpha, int angular_cells, 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 amount_r = Rand1D(i_s_neighbor, i_a_neighbor, l, 8u); + float active = smoothstep(max(0.0, amount_r - 0.02), + min(1.0, amount_r + 0.02), amount_fraction); - float w = roulette * normal(sigma_a, x_a - g_a) - * normal(sigma_s, x_s - g_s) / N; + float w = active * roulette * normal(sigma_a, x_a - g_a) + * normal(sigma_s, x_s - g_s) * profile_scale / N; D_filter += w; if (w > best_weight) { best_weight = w; @@ -303,8 +327,9 @@ float D_Kemppinen(float3 h, float alpha, float glint_alpha, int angular_cells, } } } - D_filter += w_lambda * compensation(x_a, sigma_a, res_a, i_a, - angular_step, angular_sample_count); + D_filter += amount_fraction * w_lambda * profile_scale + * 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)); @@ -327,13 +352,16 @@ LightGlitter GetGlitterLighting( float3 normal, float3 V, float3 direct_H, float3 indirect_dir) { LightGlitter g; float2x2 uv_J = uv_ellipsoid(transpose(float2x2(ddx(uv), ddy(uv)))); - float N = 8.0e5f * pow(10.0f, glitter_amount * 6.0f - 2.0f); + // Keep the procedural population fixed. `glitter_amount` independently + // controls the fraction of that population which is active in D_Kemppinen. + float N = GLITTER_REFERENCE_N * GLITTER_POPULATION_SCALE; // Direct 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, - glitter_angular_cells, uv, uv_J, N, glitter_filter_size, + glitter_angular_cells, uv, uv_J, N, glitter_amount, + glitter_filter_size, direct_micro_normal); // Indirect @@ -341,7 +369,8 @@ LightGlitter GetGlitterLighting( 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, - glitter_angular_cells, uv, uv_J, N, glitter_filter_size, + glitter_angular_cells, uv, uv_J, N, glitter_amount, + 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)); |
