Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cascaded Shadow Maps #3629

Closed
superdump opened this issue Jan 10, 2022 · 0 comments
Closed

Cascaded Shadow Maps #3629

superdump opened this issue Jan 10, 2022 · 0 comments
Assignees
Labels
A-Rendering Drawing game state to the screen C-Enhancement A new feature

Comments

@superdump
Copy link
Contributor

superdump commented Jan 10, 2022

Description

  • Directional light shadow maps have quality pretty heavily bound by the ratio of shadow map texels to screen fragments.
    • If the relative resolution of the directional light shadow map is low, then its texels cover multiple screen fragments when they are viewed using the light's projection. This means that multiple screen fragments read from the same shadow map texel which results in aliasing.
    • Using a large shadow map texture is both expensive to process and uses a lot of VRAM
    • In order to have a ratio of shadow map texels to screen fragments approaching 1:1 to get good visual quality when fragments are close to the camera, the ratio then becomes very large for fragments further away from the camera which means that a lot of VRAM has to be wasted to achieve good visual quality close to the camera.

Solution

  • Cascaded shadow maps - split the depth range over which shadows are visible into overlapping slices (cascades) with orthographic projections fit to cover the depth slice, with a far plane at least behind all visible geometry and a near plane ideally slightly closer to the light than the geometry that is closest to the light. When sampling fragments that fall in regions covered by two cascades, use a weighted blend of shadow samples from both cascades to transition smoothly from one to the next in order to minimise visible artifacts as the ratio of shadow map texels to screen fragments changes.
  • https://github.com/superdump/bevy/tree/cascade-shadow-maps
    • An implementation of the above that fits the cascade projections only to the visible geometry, and not also the near plane to the geometry that is not visible, but that is closer to the light source than the visible geometry.

Next Steps

  • Rebase the branch
  • Implement proper shadow projection fitting as documented in Foundations of Game Engine Development 2: Rendering by Eric Lengyel, which is a reference book I have been using for much of the frustum culling and some of the shadow mapping that I've implemented so far.
  • Make a PR
@superdump superdump changed the title Cascaded shadow maps - https://github.com/superdump/bevy/tree/cascade-shadow-maps Cascaded shadow maps Jan 10, 2022
@alice-i-cecile alice-i-cecile added A-Rendering Drawing game state to the screen C-Enhancement A new feature labels Jan 10, 2022
@superdump superdump changed the title Cascaded shadow maps Cascaded Shadow Maps Jan 11, 2022
@superdump superdump self-assigned this Jan 16, 2022
bors bot pushed a commit that referenced this issue Nov 4, 2022
… shadow map volume (not just direction) (#6384)

# Objective

This PR fixes #5789, by enabling movable (and scalable) directional light shadow volumes.

## Solution

This PR changes `ExtractedDirectionalLight` to hold a copy of the `DirectionalLight` entity's `GlobalTransform`, instead of just a `direction` vector. This allows the shadow map volume (as defined by the light's `shadow_projection` field) to be transformed honoring translation _and_ scale transforms, and not just rotation.

It also augments the texel size calculation (used to determine the `shadow_normal_bias`) so that it now takes into account the upper bound of the x/y/z scale of the `GlobalTransform`.

This change makes the directional light extraction code more consistent with point and spot lights (that already use `transform`), and allows easily moving and scaling the shadow volume along with a player entity based on camera distance/angle, immediately enabling more real world use cases until we have a more sophisticated adaptive implementation, such as the one described in #3629.

**Note:** While it was previously possible to update the projection achieving a similar effect, depending on the light direction and distance to the origin, the fact that the shadow map camera was always positioned at the origin with a hardcoded `Vec3::Y` up value meant you would get sub-optimal or inconsistent/incorrect results.

---

## Changelog

### Changed

- `DirectionalLight` shadow volumes now honor translation and scale transforms

## Migration Guide

- If your directional lights were positioned at the origin and not scaled (the default, most common scenario) no changes are needed on your part; it just works as before;
- If you previously had a system for dynamically updating directional light shadow projections, you might now be able to simplify your code by updating the directional light entity's transform instead;
- In the unlikely scenario that a scene with directional lights that previously rendered shadows correctly has missing shadows, make sure your directional lights are positioned at (0, 0, 0) and are not scaled to a size that's too large or too small.
@bors bors bot closed this as completed in c3a4682 Jan 25, 2023
ItsDoot pushed a commit to ItsDoot/bevy that referenced this issue Feb 1, 2023
… shadow map volume (not just direction) (bevyengine#6384)

# Objective

This PR fixes bevyengine#5789, by enabling movable (and scalable) directional light shadow volumes.

## Solution

This PR changes `ExtractedDirectionalLight` to hold a copy of the `DirectionalLight` entity's `GlobalTransform`, instead of just a `direction` vector. This allows the shadow map volume (as defined by the light's `shadow_projection` field) to be transformed honoring translation _and_ scale transforms, and not just rotation.

It also augments the texel size calculation (used to determine the `shadow_normal_bias`) so that it now takes into account the upper bound of the x/y/z scale of the `GlobalTransform`.

This change makes the directional light extraction code more consistent with point and spot lights (that already use `transform`), and allows easily moving and scaling the shadow volume along with a player entity based on camera distance/angle, immediately enabling more real world use cases until we have a more sophisticated adaptive implementation, such as the one described in bevyengine#3629.

**Note:** While it was previously possible to update the projection achieving a similar effect, depending on the light direction and distance to the origin, the fact that the shadow map camera was always positioned at the origin with a hardcoded `Vec3::Y` up value meant you would get sub-optimal or inconsistent/incorrect results.

---

## Changelog

### Changed

- `DirectionalLight` shadow volumes now honor translation and scale transforms

## Migration Guide

- If your directional lights were positioned at the origin and not scaled (the default, most common scenario) no changes are needed on your part; it just works as before;
- If you previously had a system for dynamically updating directional light shadow projections, you might now be able to simplify your code by updating the directional light entity's transform instead;
- In the unlikely scenario that a scene with directional lights that previously rendered shadows correctly has missing shadows, make sure your directional lights are positioned at (0, 0, 0) and are not scaled to a size that's too large or too small.
ItsDoot pushed a commit to ItsDoot/bevy that referenced this issue Feb 1, 2023
Co-authored-by: Robert Swain <robert.swain@gmail.com>

# Objective

Implements cascaded shadow maps for directional lights, which produces better quality shadows without needing excessively large shadow maps.

Fixes bevyengine#3629

Before
![image](https://user-images.githubusercontent.com/1222141/210061203-bbd965a4-8d11-4cec-9a88-67fc59d0819f.png)

After
![image](https://user-images.githubusercontent.com/1222141/210061334-2ff15334-e6d7-4a31-9314-f34a7805cac6.png)


## Solution

Rather than rendering a single shadow map for directional light, the view frustum is divided into a series of cascades, each of which gets its own shadow map. The correct cascade is then sampled for shadow determination.

---

## Changelog

Directional lights now use cascaded shadow maps for improved shadow quality.


## Migration Guide

You no longer have to manually specify a `shadow_projection` for a directional light, and these settings should be removed. If customization of how cascaded shadow maps work is desired, modify the `CascadeShadowConfig` component instead.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Rendering Drawing game state to the screen C-Enhancement A new feature
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

2 participants