RT projector shadows: grain in penumbrae (fixture self-occlusion + 1 spp static noise) #104

Open
opened 2026-09-27 13:17:52 +00:00 by backspace119 · 0 comments
Owner

Symptom: with RenderVKProjectorShadows=2 (ray traced), surfaces near a projector show a fine diagonal hatch/grain. Example: a tree trunk about 1.5 m from a projector inside a small fixture. With shadow maps, or with RenderVKRTShadowSoftness=0, the same area is a clean solid shadow.

Cause (confirmed in-world):

  1. Area-light radius vs. fixture. The soft RT shadow samples a disc of radius RenderVKRTShadowSoftness (default 0.1 m) at the projector apex. SL projectors are point lights in fixtures built around a point: here the fixture wall right next to the light occludes part of that disc, so every receiver lands in a penumbra caused by the fixture itself. The near-plane cut-off (params.y) stops the ray at the apex plane, but jittered targets still cross the fixture's side walls.
  2. One ray per pixel, static IGN, no filter. projShadowRay (clean_draw_common.glsl) jitters the target with interleaved gradient noise from gl_FragCoord (fixed pattern, never changes per frame) and has no spatial or temporal filtering, so any penumbra shows the IGN diagonal pattern.

Fix plan:

  • Clamp the effective light radius per projector, e.g. min(softness, k * near_distance) (the near plane approximates the fixture's inner size), and/or cut the default (0.02–0.03 m). Keep the setting for users who want wider penumbrae.
  • Adaptive sampling: 1 ray first; in pixels near an edge (neighbour disagreement or first ray blocked close to the light), 4 stratified rays over the disc with blue noise, varying per frame.
  • Edge-aware (depth/normal) spatial denoise of the projector visibility term. Temporal accumulation once TAA exists (see the TAA epic).

Workaround now: RenderVKRTShadowSoftness = 0 (hard ray-traced shadows, no grain).

**Symptom:** with `RenderVKProjectorShadows=2` (ray traced), surfaces near a projector show a fine diagonal hatch/grain. Example: a tree trunk about 1.5 m from a projector inside a small fixture. With shadow maps, or with `RenderVKRTShadowSoftness=0`, the same area is a clean solid shadow. **Cause (confirmed in-world):** 1. **Area-light radius vs. fixture.** The soft RT shadow samples a disc of radius `RenderVKRTShadowSoftness` (default 0.1 m) at the projector apex. SL projectors are point lights in fixtures built around a point: here the fixture wall right next to the light occludes part of that disc, so every receiver lands in a penumbra caused by the fixture itself. The near-plane cut-off (`params.y`) stops the ray at the apex plane, but jittered targets still cross the fixture's side walls. 2. **One ray per pixel, static IGN, no filter.** `projShadowRay` (clean_draw_common.glsl) jitters the target with interleaved gradient noise from `gl_FragCoord` (fixed pattern, never changes per frame) and has no spatial or temporal filtering, so any penumbra shows the IGN diagonal pattern. **Fix plan:** - Clamp the effective light radius per projector, e.g. `min(softness, k * near_distance)` (the near plane approximates the fixture's inner size), and/or cut the default (0.02–0.03 m). Keep the setting for users who want wider penumbrae. - Adaptive sampling: 1 ray first; in pixels near an edge (neighbour disagreement or first ray blocked close to the light), 4 stratified rays over the disc with blue noise, varying per frame. - Edge-aware (depth/normal) spatial denoise of the projector visibility term. Temporal accumulation once TAA exists (see the TAA epic). Workaround now: `RenderVKRTShadowSoftness = 0` (hard ray-traced shadows, no grain).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
backspace119/Slipstream#104
No description provided.