bevy_render/experimental/occlusion_culling/mod.rs
1//! GPU occlusion culling.
2//!
3//! See [`OcclusionCulling`] for a detailed description of occlusion culling in
4//! Bevy.
5
6use bevy_app::{App, Plugin};
7use bevy_asset::{load_internal_asset, weak_handle, Handle};
8use bevy_ecs::{component::Component, entity::Entity, prelude::ReflectComponent};
9use bevy_reflect::{prelude::ReflectDefault, Reflect};
10
11use crate::{
12 extract_component::ExtractComponent,
13 render_resource::{Shader, TextureView},
14};
15
16/// The handle to the `mesh_preprocess_types.wgsl` compute shader.
17pub const MESH_PREPROCESS_TYPES_SHADER_HANDLE: Handle<Shader> =
18 weak_handle!("7bf7bdb1-ec53-4417-987f-9ec36533287c");
19
20/// Enables GPU occlusion culling.
21///
22/// See [`OcclusionCulling`] for a detailed description of occlusion culling in
23/// Bevy.
24pub struct OcclusionCullingPlugin;
25
26impl Plugin for OcclusionCullingPlugin {
27 fn build(&self, app: &mut App) {
28 load_internal_asset!(
29 app,
30 MESH_PREPROCESS_TYPES_SHADER_HANDLE,
31 "mesh_preprocess_types.wgsl",
32 Shader::from_wgsl
33 );
34 }
35}
36
37/// Add this component to a view in order to enable experimental GPU occlusion
38/// culling.
39///
40/// *Bevy's occlusion culling is currently marked as experimental.* There are
41/// known issues whereby, in rare circumstances, occlusion culling can result in
42/// meshes being culled that shouldn't be (i.e. meshes that turn invisible).
43/// Please try it out and report issues.
44///
45/// *Occlusion culling* allows Bevy to avoid rendering objects that are fully
46/// behind other opaque or alpha tested objects. This is different from, and
47/// complements, depth fragment rejection as the `DepthPrepass` enables. While
48/// depth rejection allows Bevy to avoid rendering *pixels* that are behind
49/// other objects, the GPU still has to examine those pixels to reject them,
50/// which requires transforming the vertices of the objects and performing
51/// skinning if the objects were skinned. Occlusion culling allows the GPU to go
52/// a step further, avoiding even transforming the vertices of objects that it
53/// can quickly prove to be behind other objects.
54///
55/// Occlusion culling inherently has some overhead, because Bevy must examine
56/// the objects' bounding boxes, and create an acceleration structure
57/// (hierarchical Z-buffer) to perform the occlusion tests. Therefore, occlusion
58/// culling is disabled by default. Only enable it if you measure it to be a
59/// speedup on your scene. Note that, because Bevy's occlusion culling runs on
60/// the GPU and is quite efficient, it's rare for occlusion culling to result in
61/// a significant slowdown.
62///
63/// Occlusion culling currently requires a `DepthPrepass`. If no depth prepass
64/// is present on the view, the [`OcclusionCulling`] component will be ignored.
65/// Additionally, occlusion culling is currently incompatible with deferred
66/// shading; including both `DeferredPrepass` and [`OcclusionCulling`] results
67/// in unspecified behavior.
68///
69/// The algorithm that Bevy uses is known as [*two-phase occlusion culling*].
70/// When you enable occlusion culling, Bevy splits the depth prepass into two:
71/// an *early* depth prepass and a *late* depth prepass. The early depth prepass
72/// renders all the meshes that were visible last frame to produce a
73/// conservative approximation of the depth buffer. Then, after producing an
74/// acceleration structure known as a hierarchical Z-buffer or depth pyramid,
75/// Bevy tests the bounding boxes of all meshes against that depth buffer. Those
76/// that can be quickly proven to be behind the geometry rendered during the
77/// early depth prepass are skipped entirely. The other potentially-visible
78/// meshes are rendered during the late prepass, and finally all the visible
79/// meshes are rendered as usual during the opaque, transparent, etc. passes.
80///
81/// Unlike other occlusion culling systems you may be familiar with, Bevy's
82/// occlusion culling is fully dynamic and requires no baking step. The CPU
83/// overhead is minimal. Large skinned meshes and other dynamic objects can
84/// occlude other objects.
85///
86/// [*two-phase occlusion culling*]:
87/// https://medium.com/@mil_kru/two-pass-occlusion-culling-4100edcad501
88#[derive(Component, ExtractComponent, Clone, Copy, Default, Reflect)]
89#[reflect(Component, Default, Clone)]
90pub struct OcclusionCulling;
91
92/// A render-world component that contains resources necessary to perform
93/// occlusion culling on any view other than a camera.
94///
95/// Bevy automatically places this component on views created for shadow
96/// mapping. You don't ordinarily need to add this component yourself.
97#[derive(Clone, Component)]
98pub struct OcclusionCullingSubview {
99 /// A texture view of the Z-buffer.
100 pub depth_texture_view: TextureView,
101 /// The size of the texture along both dimensions.
102 ///
103 /// Because [`OcclusionCullingSubview`] is only currently used for shadow
104 /// maps, they're guaranteed to have sizes equal to a power of two, so we
105 /// don't have to store the two dimensions individually here.
106 pub depth_texture_size: u32,
107}
108
109/// A render-world component placed on each camera that stores references to all
110/// entities other than cameras that need occlusion culling.
111///
112/// Bevy automatically places this component on cameras that are drawing
113/// shadows, when those shadows come from lights with occlusion culling enabled.
114/// You don't ordinarily need to add this component yourself.
115#[derive(Clone, Component)]
116pub struct OcclusionCullingSubviewEntities(pub Vec<Entity>);