Disable SSAO for meshes without depth writes - #25358
Conversation
Screen-space ambient occlusion may produce artifacts for meshes that do not contribute to the depth prepass. SSAO is sampled independently of whether the corresponding surface was written to the depth buffer, so regions not covered by the depth prepass may contain invalid or uninitialized data. This primarily affects transparent meshes and other cases where depth writes are disabled. Only enable SSAO when depth_write_enabled is true. Since depth-write behavior is derived from multiple pipeline properties, use the already resolved depth_write_enabled value rather than trying to infer it from individual material or pipeline flags.
|
Could you come up with a more realistic example? E.g. expand the SSAO example a bit with a flat plane, and some transparent and opaque cubes scattered around. It's hard to tell what this would look like from your screenshot. |
Thanks for the prompt response! I think this is actually a fairly realistic example - we do use near/far ranges like this. More importantly, the underlying problem is independent of the particular scene. In this example, the mesh does not contribute to the depth prepass at all, so the SSAO compute path simply does not have the data it relies on. The textures themselves are initialized - for example, the reconstructed normals may end up being zero - but those values do not represent meaningful depth or surface normals for this mesh, and the SSAO algorithm is not designed to operate on such input. With a sufficiently large near/far range, the floating-point errors involved in reconstructing the view-space data make the resulting artifact much more visible. The default infinite-far perspective projection happens to hide this particular manifestation of the problem. More fundamentally, I think applying SSAO to a mesh that did not contribute the depth/normal information SSAO relies on is simply incorrect, regardless of whether a particular scene makes the artifact visually obvious. I can try to expand the SSAO example with a plane and a mix of transparent and opaque cubes, but I am not quite sure what additional behavior we want that example to demonstrate. To me, the logical error here seems independent of the particular scene setup. |
|
Objective
Screen-space ambient occlusion can produce artifacts for meshes that do not contribute to the depth prepass. SSAO may still be sampled for these meshes even though no corresponding depth information was written, potentially causing invalid or uninitialized depth data to affect the result.
This primarily affects transparent meshes and other cases where depth writes are disabled.
Solution
Only enable screen-space ambient occlusion for meshes with depth writes enabled.
Since depth-write behavior depends on multiple pipeline properties, use the already resolved
depth_write_enabledvalue when configuring the mesh pipeline rather than inferring it from individual material or pipeline flags.Testing
cargo run --features free_camera --example ssao(modified)cargo run -p cicargo run --features free_camera --example ssao(modified)The example uses a finite perspective projection with a large near/far range to make the artifact clearly visible. Bevy's default perspective projection uses an infinite far plane, which causes the relevant shader values to approach infinity and effectively hides this particular artifact.
Showcase
Before:

Perspective
Orthographic
After:

Click to view example