Add configurable shadow focus target for directional cascades - #355
Open
keithwill wants to merge 1 commit into
Open
Add configurable shadow focus target for directional cascades#355keithwill wants to merge 1 commit into
keithwill wants to merge 1 commit into
Conversation
Directional-light shadow cascades were always centered on the rendering camera's position, which assumes a first-person view. In a third-person game the player character is a distant focal point, so the character lands in a low-resolution far cascade (or falls out of the cascade range entirely) while the resolution is spent on empty ground in front of the camera. Add an optional per-camera Camera.ShadowFocus transform that cascades center on instead. It falls back to the camera's own position when unset or when the target's GameObject has been destroyed, so existing scenes and the editor's scene view (which builds a fresh temporary Camera) are unaffected. The CPU side places cascades around the focus point in DirectionalLight.GetShadowMatrix, while two shader sites select a cascade by distance: SampleDirectionalShadow in Lighting.glsl and VolDirShadow in VolumetricFog.shader. Both have to move together or selection disagrees with placement and cascade seams appear, so the resolved point is uploaded as a new _ShadowFocusPos uniform and both sites measure from it. The uniform is written before the no-directional-light early-out so it stays fresh every frame. Camera-relative values (view direction, fog distance, specular) keep using _WorldSpaceCameraPos. The point is resolved once per render into CameraSnapshot, so mutating the target mid-render can't desync placement from selection. Closest-N local shadow caster selection in SceneLightSystem.Reconcile uses the same point. Known limitation, unchanged by this: the cascade ortho depth range is a fixed +/- cascadeDistance * 0.5 slab around the snapped focus point rather than a fit to the scene's casters, so tall occluders toward the light can clip out of the map. This relocates that behaviour with the focus point; it does not fix it. Tests cover the resolver's fallbacks, that it tracks a moving target, that the cross-object Transform reference survives a scene save/load via Echo's intra-graph rewiring, that a cascade lands centered on its focus point to within half a texel, and that sub-texel movement of the focus produces an identical view matrix (the texel snapping that keeps shadow edges from shimmering). The BananaMan sample now demonstrates it: a player stand-in with props sits 25 units out on a large ground plane, the camera is third-person, and F toggles the focus between the player and the camera.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Directional-light shadow cascades were always centered on the rendering camera's position, which assumes a first-person view. In a third-person game the player character is a distant focal point, so the character lands in a low-resolution far cascade (or falls out of the cascade range entirely) while the resolution is spent on empty ground in front of the camera.
Add an optional per-camera Camera.ShadowFocus transform that cascades center on instead. It falls back to the camera's own position when unset or when the target's GameObject has been destroyed, so existing scenes and the editor's scene view (which builds a fresh temporary Camera) are unaffected.
The CPU side places cascades around the focus point in DirectionalLight.GetShadowMatrix, while two shader sites select a cascade by distance: SampleDirectionalShadow in Lighting.glsl and VolDirShadow in VolumetricFog.shader. Both have to move together or selection disagrees with placement and cascade seams appear, so the resolved point is uploaded as a new _ShadowFocusPos uniform and both sites measure from it. The uniform is written before the no-directional-light early-out so it stays fresh every frame. Camera-relative values (view direction, fog distance, specular) keep using _WorldSpaceCameraPos.
The point is resolved once per render into CameraSnapshot, so mutating the target mid-render can't desync placement from selection. Closest-N local shadow caster selection in SceneLightSystem.Reconcile uses the same point.
Known limitation, unchanged by this: the cascade ortho depth range is a fixed +/- cascadeDistance * 0.5 slab around the snapped focus point rather than a fit to the scene's casters, so tall occluders toward the light can clip out of the map. This relocates that behaviour with the focus point; it does not fix it.
Tests cover the resolver's fallbacks, that it tracks a moving target, that the cross-object Transform reference survives a scene save/load via Echo's intra-graph rewiring, that a cascade lands centered on its focus point to within half a texel, and that sub-texel movement of the focus produces an identical view matrix (the texel snapping that keeps shadow edges from shimmering).
The BananaMan sample now demonstrates it: a player stand-in with props sits 25 units out on a large ground plane, the camera is third-person, and F toggles the focus between the player and the camera.