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