Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add an optional component that generates hierarchical Z-buffers, in
preparation for GPU occlusion culling. Two-phase occlusion culling [1], which is generally considered the state-of-the-art occlusion culling technique. We already use two-phase occlusion culling for meshlets, but we don't for other 3D objects. Two-phase occlusion culling requires the construction of a *hierarchical Z-buffer*. This patch implements an opt-in set of passes to generate that and so is a step along the way to implementing two-phase occlusion culling, alongside GPU frustum culling (bevyengine#12889). This commit copies the hierarchical Z-buffer building code from meshlets into `bevy_core_pipeline`. Adding the new `HierarchicalDepthBuffer` component to a camera enables the feature. This code should be usable as-is for third-party plugins that might want to implement two-phase occlusion culling, but of course we would like to have two-phase occlusion culling implemented directly in Bevy in the near future. Two-phase occlusion culling will be implemented using the following procedure: 1. Render all meshes that would have been visible in the previous frame to the depth buffer (with no fragment shader), using the previous frame's hierarchical Z-buffer, the previous frame's view matrix (cf. bevyengine#12902), and each model's previous view input uniform. 2. Downsample the Z-buffer to produce a hierarchical Z-buffer ("early", in the language of this patch). 3. Perform occlusion culling of all meshes against the Hi-Z buffer, using a screen space AABB test. 4. If a prepass is in use, render it now, using the occlusion culling results from (3). Note that if *only* a depth prepass is in use, then we can avoid rendering meshes that we rendered in phase (1), since they're already in the depth buffer. 5. Render main passes, using the occlusion culling results from (3). 6. Downsample the Z-buffer to produce a hierarchical Z-buffer again ("late", in the language of this patch). This readies the Z-buffer for step (1) of the next frame. It differs from the hierarchical Z-buffer produced in (2) because it includes meshes that weren't visible last frame, but became visible this frame. This commit adds steps (1), (2), and (6) to the pipeline, when the `HierarchicalDepthBuffer` component is present. It doesn't add step (3), because step (3) depends on bevyengine#12889 which in turn depends on bevyengine#12773, and both of those patches are still in review. Unlike meshlets, we have to handle the case in which the depth buffer is multisampled. This is the source of most of the extra complexity, since we can't use the Vulkan extension [2] that allows us to easily resolve multisampled depth buffers using the min operation. At Jasmine's request, I haven't touched the meshlet code except to do some very minor refactoring; the code is generally copied in. [1]: https://medium.com/@mil_kru/two-pass-occlusion-culling-4100edcad501 [2]: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkSubpassDescriptionDepthStencilResolveKHR.html
- Loading branch information