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

Percentage Closer Filtering for shadows #3628

Closed
superdump opened this issue Jan 10, 2022 · 5 comments · Fixed by #12910
Closed

Percentage Closer Filtering for shadows #3628

superdump opened this issue Jan 10, 2022 · 5 comments · Fixed by #12910
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

  • bevy's shadows currently use 'hardware' 2x2 Percentage Closer Filtering resulting in anti-aliased edges of shadows. However, the filtering is insufficient for smooth shadow edges and more extensive/advanced filtering patterns can be used to producer smoother-looking shadows.
    • 'hardware' is in single quotes because apparently in modern GPUs there may not be dedicated silicon for this purpose, but rather the functionality is software in drivers that leverages more generic hardware acceleration functionality.

Background and Reference Material

  • Percentage Closer Filtering involves taking multiple samples from the shadow map and comparing with an interpolated mesh surface depth projected into the frame of reference of the light and calculating the percentage of samples in the depth buffer that are closer to the light (i.e. casting shadow) than the mesh surface.
  • Sampling from multiple shadow map texels away from the one that 'covers' the fragment on the mesh surface and using the same 'biased' (offset) fragment position easily produces shadow acne/self-shadowing even if some bias configuration works well for sampling texels close to the centre of the kernel.
  • Roughly-speaking, more samples are needed to gain more information in order to produce a smoother result. Sampling the same texels repeatedly doesn't help, so more samples roughly means sampling with a larger radius.
  • Percentage Closer Soft Shadows (a separate issue) scale both the occluder search radius and the filtering radius based on the distance to the light, and occluder, and the size of the light itself. This can result in large radius sampling kernels which easily produces artifacts due to self-shadowing
  • Regular grid sampling patterns produce filtering artifacts like banding.
  • Irregular sampling patterns such as blue noise or poisson disc require fewer samples for the same visual quality, don't produce the same banding artifacts, and performance can be scaled nicely (you can choose an arbitrary number of samples to take).
  • The Witness has a really nice and smooth PCF sampling and post-filtering (as in, filtering the results of sampling) algorithm (http://the-witness.net/news/2013/09/shadow-mapping-summary-part-1/) that is among the best I have seen for surfaces without much texture (combining textured surfaces and noisy shadows is less visually jarring than noisy shadows on flat shaded surfaces where the noise stands out). I think this would be a good default. It requires relatively few samples to look good too.
  • Randomly-rotated (using blue noise for the rotations) poisson disc / direct blue noise sampling would work well with Temporal Anti-Aliasing and would also require few samples, but is visually noisy without it.
  • Cubemaps are left-handed!!!
  • Biasing
    • Receiver Plane Depth Bias (Isidoro 2006, Page 36) - This can be used for 2D shadow maps and it is quite simple to implement and compute: https://developer.amd.com/wordpress/media/2012/10/Isidoro-ShadowMapping.pdf However, I do not know if it is possible to adapt this to be used for cube shadow maps for point lights so I went in search of alternatives.
    • Adaptive Bias for Shadow Maps (Dou et al 2014) - https://jcgt.org/published/0003/04/08/ This approach is very intuitive and works well. It assumes the mesh surface is locally flat, calculates the gradient of the surface to calculate an 'optimal' fragment depth at the surface at the offset position in light view x/y, and then uses an additional 'adaptive epsilon' that is based on the gradient of the depth projection being used to account for, if I recall correctly, the precision distribution in order to move the fragment position just closer to the light to avoid self-shadowing.
    • Adaptive Bias for Soft Shadows (Ehm et al. 2015) - https://w3-o.cs.hm.edu/users/nischwit/public_html/AdaptiveDepthBias_WSCG.pdf - included here as it details a good further enhancement to Adaptive Bias for Shadow Maps though its extension to Percentage Closer Soft Shadows is not relevant here.

Solution

  • https://github.com/superdump/bevy/tree/shadow-pcf
    • A large bunch of experiments to try to get both point and directional light shadow filtering to work well with large filter kernels
    • Implements left-handed cube maps. This was a long-and-hard-fought realisation as documentation for cubemaps is awful. They are left-handed and so we try to force them to work with right-handed projections, rather accept they are left-handed and go with it. It makes for much more comprehensible code that one can reason about!
    • Implements the above-mentioned techniques (receiver plane depth bias, adaptive bias for shadow maps, part of adaptive bias for soft shadows) and some regular-grid and blue noise sampling pattern techniques
  • https://github.com/superdump/bevy/tree/poisson-pcf
    • Implements the blue noise random rotated poisson disc and The Witness sampling techniques

Next Steps

  • Clean up the conversion of cube map handling to be left-handed and make a PR
  • Clean up Adaptive Depth Bias for Shadow Maps with the improvement to scale the adaptive epsilon by min(1 / dot(light dir, frag normal)^2, 100) as introduced in Adaptive Depth Bias for Soft Shadows, make this depth biasing an option, benchmark it, and make a PR
  • Clean up the The Witness PCF sampling approach, and make a PR
  • Investigate the value of direct blue noise sampling and blue noise random rotated poisson disc sampling and decide whether they are worth integrating now or should wait for reevaluation when we have Temporal Anti-Aliasing
@superdump superdump added A-Rendering Drawing game state to the screen C-Enhancement A new feature labels Jan 10, 2022
@superdump superdump changed the title Shadow filtering - https://github.com/superdump/bevy/tree/shadow-pcf and https://github.com/superdump/bevy/tree/poisson-pcf Shadow filtering Jan 10, 2022
@superdump superdump changed the title Shadow filtering Percentage Closer Filtering for shadows Jan 11, 2022
@superdump superdump self-assigned this Jan 16, 2022
@Suyashtnt
Copy link

Any updates to this? The last commit in that branch was nearly a year ago

@JMS55
Copy link
Contributor

JMS55 commented Mar 18, 2023

@superdump
Copy link
Contributor Author

@JMS55 yeah. I've been thinking that we should probably move to a shadow atlas and only render/update the tiles we need (each tile could be a directional light shadow map cascade, a spot light shadow map, or one face of a point light shadow 'cubemap'). Then we could prioritise which shadow maps to update (e.g. those with some lighting/occluder change that are closest to the camera?) and potentially support shadow mapping for many more spot/point light sources.

@JMS55 JMS55 removed this from the 0.11 milestone Jun 18, 2023
@JMS55
Copy link
Contributor

JMS55 commented Aug 1, 2023

A new biasing technique: "Oriented Depth Bias" section 4.2 http://www.jp.square-enix.com/tech/library/pdf/2023_FFXVIShadowTechPaper.pdf

github-merge-queue bot pushed a commit that referenced this issue Oct 7, 2023
# Objective

- Improve antialiasing for non-point light shadow edges.
- Very partially addresses
#3628.

## Solution

- Implements "The Witness"'s shadow map sampling technique.
  - Ported from @superdump's old branch, all credit to them :)
- Implements "Call of Duty: Advanced Warfare"'s stochastic shadow map
sampling technique when the velocity prepass is enabled, for use with
TAA.
- Uses interleaved gradient noise to generate a random angle, and then
averages 8 samples in a spiral pattern, rotated by the random angle.
- I also tried spatiotemporal blue noise, but it was far too noisy to be
filtered by TAA alone. In the future, we should try spatiotemporal blue
noise + a specialized shadow denoiser such as
https://gpuopen.com/fidelityfx-denoiser/#shadow. This approach would
also be useful for hybrid rasterized applications with raytraced
shadows.
- The COD presentation has an interesting temporal dithering of the
noise for use with temporal supersampling that we should revisit when we
get DLSS/FSR/other TSR.

---

## Changelog

* Added `ShadowFilteringMethod`. Improved directional light and
spotlight shadow edges to be less aliased.

## Migration Guide

* Shadows cast by directional lights or spotlights now have smoother
edges. To revert to the old behavior, add
`ShadowFilteringMethod::Hardware2x2` to your cameras.

---------

Co-authored-by: IceSentry <c.giguere42@gmail.com>
Co-authored-by: Daniel Chia <danstryder@gmail.com>
Co-authored-by: robtfm <50659922+robtfm@users.noreply.github.com>
Co-authored-by: Brandon Dyer <brandondyer64@gmail.com>
Co-authored-by: Edgar Geier <geieredgar@gmail.com>
Co-authored-by: Robert Swain <robert.swain@gmail.com>
Co-authored-by: Elabajaba <Elabajaba@users.noreply.github.com>
Co-authored-by: IceSentry <IceSentry@users.noreply.github.com>
regnarock pushed a commit to regnarock/bevy that referenced this issue Oct 13, 2023
# Objective

- Improve antialiasing for non-point light shadow edges.
- Very partially addresses
bevyengine#3628.

## Solution

- Implements "The Witness"'s shadow map sampling technique.
  - Ported from @superdump's old branch, all credit to them :)
- Implements "Call of Duty: Advanced Warfare"'s stochastic shadow map
sampling technique when the velocity prepass is enabled, for use with
TAA.
- Uses interleaved gradient noise to generate a random angle, and then
averages 8 samples in a spiral pattern, rotated by the random angle.
- I also tried spatiotemporal blue noise, but it was far too noisy to be
filtered by TAA alone. In the future, we should try spatiotemporal blue
noise + a specialized shadow denoiser such as
https://gpuopen.com/fidelityfx-denoiser/#shadow. This approach would
also be useful for hybrid rasterized applications with raytraced
shadows.
- The COD presentation has an interesting temporal dithering of the
noise for use with temporal supersampling that we should revisit when we
get DLSS/FSR/other TSR.

---

## Changelog

* Added `ShadowFilteringMethod`. Improved directional light and
spotlight shadow edges to be less aliased.

## Migration Guide

* Shadows cast by directional lights or spotlights now have smoother
edges. To revert to the old behavior, add
`ShadowFilteringMethod::Hardware2x2` to your cameras.

---------

Co-authored-by: IceSentry <c.giguere42@gmail.com>
Co-authored-by: Daniel Chia <danstryder@gmail.com>
Co-authored-by: robtfm <50659922+robtfm@users.noreply.github.com>
Co-authored-by: Brandon Dyer <brandondyer64@gmail.com>
Co-authored-by: Edgar Geier <geieredgar@gmail.com>
Co-authored-by: Robert Swain <robert.swain@gmail.com>
Co-authored-by: Elabajaba <Elabajaba@users.noreply.github.com>
Co-authored-by: IceSentry <IceSentry@users.noreply.github.com>
@superdump
Copy link
Contributor Author

The Witness (Castaño 13) and Call of Duty: Advanced Warfare (Jimenez 14) methods were implemented for directional and spot lights in Bevy 0.12. #10188 is still needed, and then also PCF for point light shadow maps.

ameknite pushed a commit to ameknite/bevy that referenced this issue Nov 6, 2023
# Objective

- Improve antialiasing for non-point light shadow edges.
- Very partially addresses
bevyengine#3628.

## Solution

- Implements "The Witness"'s shadow map sampling technique.
  - Ported from @superdump's old branch, all credit to them :)
- Implements "Call of Duty: Advanced Warfare"'s stochastic shadow map
sampling technique when the velocity prepass is enabled, for use with
TAA.
- Uses interleaved gradient noise to generate a random angle, and then
averages 8 samples in a spiral pattern, rotated by the random angle.
- I also tried spatiotemporal blue noise, but it was far too noisy to be
filtered by TAA alone. In the future, we should try spatiotemporal blue
noise + a specialized shadow denoiser such as
https://gpuopen.com/fidelityfx-denoiser/#shadow. This approach would
also be useful for hybrid rasterized applications with raytraced
shadows.
- The COD presentation has an interesting temporal dithering of the
noise for use with temporal supersampling that we should revisit when we
get DLSS/FSR/other TSR.

---

## Changelog

* Added `ShadowFilteringMethod`. Improved directional light and
spotlight shadow edges to be less aliased.

## Migration Guide

* Shadows cast by directional lights or spotlights now have smoother
edges. To revert to the old behavior, add
`ShadowFilteringMethod::Hardware2x2` to your cameras.

---------

Co-authored-by: IceSentry <c.giguere42@gmail.com>
Co-authored-by: Daniel Chia <danstryder@gmail.com>
Co-authored-by: robtfm <50659922+robtfm@users.noreply.github.com>
Co-authored-by: Brandon Dyer <brandondyer64@gmail.com>
Co-authored-by: Edgar Geier <geieredgar@gmail.com>
Co-authored-by: Robert Swain <robert.swain@gmail.com>
Co-authored-by: Elabajaba <Elabajaba@users.noreply.github.com>
Co-authored-by: IceSentry <IceSentry@users.noreply.github.com>
rdrpenguin04 pushed a commit to rdrpenguin04/bevy that referenced this issue Jan 9, 2024
# Objective

- Improve antialiasing for non-point light shadow edges.
- Very partially addresses
bevyengine#3628.

## Solution

- Implements "The Witness"'s shadow map sampling technique.
  - Ported from @superdump's old branch, all credit to them :)
- Implements "Call of Duty: Advanced Warfare"'s stochastic shadow map
sampling technique when the velocity prepass is enabled, for use with
TAA.
- Uses interleaved gradient noise to generate a random angle, and then
averages 8 samples in a spiral pattern, rotated by the random angle.
- I also tried spatiotemporal blue noise, but it was far too noisy to be
filtered by TAA alone. In the future, we should try spatiotemporal blue
noise + a specialized shadow denoiser such as
https://gpuopen.com/fidelityfx-denoiser/#shadow. This approach would
also be useful for hybrid rasterized applications with raytraced
shadows.
- The COD presentation has an interesting temporal dithering of the
noise for use with temporal supersampling that we should revisit when we
get DLSS/FSR/other TSR.

---

## Changelog

* Added `ShadowFilteringMethod`. Improved directional light and
spotlight shadow edges to be less aliased.

## Migration Guide

* Shadows cast by directional lights or spotlights now have smoother
edges. To revert to the old behavior, add
`ShadowFilteringMethod::Hardware2x2` to your cameras.

---------

Co-authored-by: IceSentry <c.giguere42@gmail.com>
Co-authored-by: Daniel Chia <danstryder@gmail.com>
Co-authored-by: robtfm <50659922+robtfm@users.noreply.github.com>
Co-authored-by: Brandon Dyer <brandondyer64@gmail.com>
Co-authored-by: Edgar Geier <geieredgar@gmail.com>
Co-authored-by: Robert Swain <robert.swain@gmail.com>
Co-authored-by: Elabajaba <Elabajaba@users.noreply.github.com>
Co-authored-by: IceSentry <IceSentry@users.noreply.github.com>
github-merge-queue bot pushed a commit that referenced this issue Apr 10, 2024
I ported the two existing PCF techniques to the cubemap domain as best I
could. Generally, the technique is to create a 2D orthonormal basis
using Gram-Schmidt normalization, then apply the technique over that
basis. The results look fine, though the shadow bias often needs
adjusting.

For comparison, Unity uses a 4-tap pattern for PCF on point lights of
(1, 1, 1), (-1, -1, 1), (-1, 1, -1), (1, -1, -1). I tried this but
didn't like the look, so I went with the design above, which ports the
2D techniques to the 3D domain. There's surprisingly little material on
point light PCF.

I've gone through every example using point lights and verified that the
shadow maps look fine, adjusting biases as necessary.

Fixes #3628.

---

## Changelog

### Added
* Shadows from point lights now support percentage-closer filtering
(PCF), and as a result look less aliased.

### Changed
* `ShadowFilteringMethod::Castano13` and
`ShadowFilteringMethod::Jimenez14` have been renamed to
`ShadowFilteringMethod::Gaussian` and `ShadowFilteringMethod::Temporal`
respectively.

## Migration Guide

* `ShadowFilteringMethod::Castano13` and
`ShadowFilteringMethod::Jimenez14` have been renamed to
`ShadowFilteringMethod::Gaussian` and `ShadowFilteringMethod::Temporal`
respectively.
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.

3 participants