fix(render): jitter the volumetric march per pixel (IGN); file #421 for the shadow transform buffer (Campaign VM VM5)
Fixed step-count volumetric ray marches (Low/Medium presets, e.g. 40 steps) sample the same t values at every pixel, so a shadow-cascade edge crossing lands at the same march step across a whole neighbourhood of pixels and reads as visible concentric banding around light shafts. Offset each pixel's march phase with interleaved gradient noise (Jimenez 2014, fract(52.9829189 * fract(dot(gl_FragCoord.xy, vec2(0.06711056, 0.00583715))))) instead of the fixed 0.5 sub-step center: t = (step + ign) / steps. This decorrelates the step boundaries across pixels, turning the banding into fine per-pixel noise that the existing quarter/half-res upsample already averages away. Pack-on only — atmospheric_volumetric is never used on the retail default path; extinction, colour, and early-outs are unchanged. Regenerated SPIR-V via tools/compile-shaders.ps1: only atmospheric_volumetric.frag.spv and shaders.manifest.json's source hash for that stage changed. Also files #421 (docs/ISSUES.md) for Campaign AR review finding F7: the directional-shadow pass's DirectionalShadowTransformBufferSet duplicates the main pass's N.5 instance SSBO instead of binding it, to be resolved once the planned GPU-culling step for shadow cascades lands. Updates the VM5 ledger row and outcome note in docs/plans/2026-08-22-visualmaster-campaign.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
6e76314b08
commit
b1e9912535
5 changed files with 42 additions and 3 deletions
|
|
@ -52,10 +52,19 @@ void main()
|
|||
vec3 sceneWorld = reconstructWorld(vUv, sceneDepth);
|
||||
int steps = clamp(int(uPackParams0.z + 0.5), 1, 64);
|
||||
float lit = 0.0;
|
||||
// Interleaved gradient noise (Jimenez, "Next Generation Post Processing
|
||||
// in Call of Duty: Advanced Warfare", 2014). Every pixel would otherwise
|
||||
// sample the same t values along its march, so shadow-cascade edge
|
||||
// crossings line up between neighbouring pixels and read as visible
|
||||
// concentric banding. Jittering the march's starting phase per pixel
|
||||
// decorrelates those step boundaries, turning the banding into fine
|
||||
// noise that the existing quarter/half-res upsample already averages
|
||||
// away.
|
||||
float ign = fract(52.9829189 * fract(dot(gl_FragCoord.xy, vec2(0.06711056, 0.00583715))));
|
||||
for (int step = 0; step < 64; ++step) {
|
||||
if (step >= steps)
|
||||
break;
|
||||
float t = (float(step) + 0.5) / float(steps);
|
||||
float t = (float(step) + ign) / float(steps);
|
||||
lit += directionalVisibility(mix(nearWorld, sceneWorld, t));
|
||||
}
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -92,7 +92,7 @@
|
|||
},
|
||||
{
|
||||
"stage": "frag",
|
||||
"sourceSha256": "8d6177707a95cf0230881bbfb7467c0591632eb67dce3c758596c83cafb14ffc",
|
||||
"sourceSha256": "0195fa5fdfb3850e090bed6f144981d454edfed526b79efe8dd5300b610b2f0f",
|
||||
"compiled": true
|
||||
}
|
||||
]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue