bevy icon indicating copy to clipboard operation
bevy copied to clipboard

Implement opt-in sharp screen-space reflections for the deferred renderer.

Open pcwalton opened this issue 1 year ago • 7 comments

This commit implements screen-space reflections (SSR), which approximate real-time reflections based on raymarching through the depth buffer and copying samples from the final rendered frame. Numerous variations and refinements to screen-space reflections exist in the literature. This patch foregoes all of them in favor of implementing the bare minimum, so as to provide a flexible base on which to customize and build in the future.

For a general basic overview of screen-space reflections, see 1. The raymarching shader uses the basic algorithm of tracing forward in large steps (what I call a major trace), and then refining that trace in smaller increments via binary search (what I call a minor trace). No filtering, whether temporal or spatial, is performed at all; for this reason, SSR currently only operates on very shiny surfaces. No acceleration via the hierarchical Z-buffer is implemented (though note that #12899 will add the infrastructure for this). Reflections are traced at full resolution, which is often considered slow. All of these improvements and more can be follow-ups.

SSR is built on top of the deferred renderer and is currently only supported in that mode. Forward screen-space reflections are possible albeit uncommon (though e.g. Doom Eternal uses them); however, they require tracing from the previous frame, which would add complexity. This patch leaves the door open to implementing SSR in the forward rendering path but doesn't itself have such an implementation. Screen-space reflections are supported in WebGL 2.

To add screen-space reflections to a camera, use the ScreenSpaceReflectionsBundle bundle or the ScreenSpaceReflectionsSettings component. In addition to ScreenSpaceReflectionsSettings, DepthPrepass and DeferredPrepass must also be present for the reflections to show up. The ScreenSpaceReflectionsSettings component contains several settings that artists can tweak, and also comes with sensible defaults.

A new example, ssr, has been added. It's loosely based on the three.js ocean sample, but all the assets are original. Note that the three.js demo has no screen-space reflections and instead renders a mirror world.

Additionally, this patch fixes a random bug I ran across: that the "TONEMAP_METHOD_ACES_FITTED" #define is incorrectly supplied to the shader as "TONEMAP_METHOD_ACES_FITTED " (with an extra space) in some paths.

Screenshot 2024-04-13 174857


Changelog

Added

  • Screen-space reflections can be enabled for very smooth surfaces by adding the ScreenSpaceReflections component to a camera. Deferred rendering must be enabled for the reflections to appear.

pcwalton avatar Apr 14 '24 00:04 pcwalton

The generated examples/README.md is out of sync with the example metadata in Cargo.toml or the example readme template. Please run cargo run -p build-templated-pages -- update examples to update it, and commit the file change.

github-actions[bot] avatar Apr 14 '24 01:04 github-actions[bot]

This should be ready for review now.

pcwalton avatar Apr 14 '24 02:04 pcwalton

I renamed ScreenSpaceReflections to ScreenSpaceReflectionsSettings and added a bundle, ScreenSpaceReflectionsBundle.

pcwalton avatar Apr 14 '24 20:04 pcwalton

Don't have time for a review, but saw the request. Just wanted to note that specular occlusion should use SSR if it is available. I believe I cited some papers in the shader code that talk about how to use SSR with specular occlusion. This might be out of scope, but it popped in my head when I saw this.

aevyrie avatar Apr 18 '24 20:04 aevyrie

@aevyrie Yes, I agree. I think that should be a followup as it'll be a decent amount of code.

pcwalton avatar Apr 19 '24 05:04 pcwalton

The example crashes if any other prepasses are added to the camera, for example NormalPrepass.

 Incompatible bind group at index 0 in the current render pipeline
      note: Should be compatible an with an explicit bind group layout with label = `mesh_view_layout_depth_deferred`
      note: Assigned explicit bind group layout with label = `mesh_view_layout_depth_normal_deferred`

I believe the MeshPipelineViewLayoutKey of the ssr pipeline should be adjusted for those cases, unless I'm doing something wrong or this is intended.

chronicl avatar Apr 22 '24 14:04 chronicl

@chronicl Fixed, thanks!

pcwalton avatar Apr 23 '24 02:04 pcwalton

@JMS55

A bit surprised that the water reflection from the envmap is part of SSR, and not just part of the PBR shader, but maybe there's a good reason for that.

Unless I'm misunderstanding what you are saying. The envmap reflection is still handled by the PBR shader when SSR is not present and when it's present it's still done when the roughness is under a certain threshold.

IceSentry avatar May 03 '24 04:05 IceSentry

In the SSR example, disabling SSR turns off both the cube reflection, but also the reflection on the water from the env map, which surprises me.

JMS55 avatar May 03 '24 04:05 JMS55

The reason why SSR delays evaluation of the environment map until the SSR pass is that the specular part of the environment map is only taken into account if the ray misses (after all, the environment map is "infinitely" far away), and we don't know whether the ray is going to miss until we evaluate SSR.

In other words, SSR effectively doubles as raymarched occlusion for the environment map.

pcwalton avatar May 03 '24 04:05 pcwalton

Oh I guess doesn't have to be this PR, but it's probably better to use a compute shader for SSR.

JMS55 avatar May 03 '24 04:05 JMS55

Yeah, definitely not this PR. I'd much rather have it as-is and introduce a compute path later. We'll also want to reuse the depth pyramid once we have that.

IceSentry avatar May 03 '24 04:05 IceSentry

Will have to redo this later.

pcwalton avatar May 03 '24 06:05 pcwalton

Closing as I am burned out and have no motivation to get this landed anymore.

pcwalton avatar May 03 '24 07:05 pcwalton