bevy_render/mesh/
mod.rs

1use bevy_math::Vec3;
2pub use bevy_mesh::*;
3use morph::{MeshMorphWeights, MorphWeights};
4pub mod allocator;
5mod components;
6use crate::{
7    primitives::Aabb,
8    render_asset::{PrepareAssetError, RenderAsset, RenderAssetPlugin, RenderAssets},
9    render_resource::TextureView,
10    texture::GpuImage,
11    view::VisibilitySystems,
12    RenderApp,
13};
14use allocator::MeshAllocatorPlugin;
15use bevy_app::{App, Plugin, PostUpdate};
16use bevy_asset::{AssetApp, AssetEvents, AssetId, RenderAssetUsages};
17use bevy_ecs::{
18    prelude::*,
19    system::{
20        lifetimeless::{SRes, SResMut},
21        SystemParamItem,
22    },
23};
24pub use components::{mark_3d_meshes_as_changed_if_their_assets_changed, Mesh2d, Mesh3d, MeshTag};
25use wgpu::IndexFormat;
26
27/// Registers all [`MeshBuilder`] types.
28pub struct MeshBuildersPlugin;
29
30impl Plugin for MeshBuildersPlugin {
31    fn build(&self, app: &mut App) {
32        // 2D Mesh builders
33        app.register_type::<CircleMeshBuilder>()
34            .register_type::<CircularSectorMeshBuilder>()
35            .register_type::<CircularSegmentMeshBuilder>()
36            .register_type::<RegularPolygonMeshBuilder>()
37            .register_type::<EllipseMeshBuilder>()
38            .register_type::<AnnulusMeshBuilder>()
39            .register_type::<RhombusMeshBuilder>()
40            .register_type::<Triangle2dMeshBuilder>()
41            .register_type::<RectangleMeshBuilder>()
42            .register_type::<Capsule2dMeshBuilder>()
43            // 3D Mesh builders
44            .register_type::<Capsule3dMeshBuilder>()
45            .register_type::<ConeMeshBuilder>()
46            .register_type::<ConicalFrustumMeshBuilder>()
47            .register_type::<CuboidMeshBuilder>()
48            .register_type::<CylinderMeshBuilder>()
49            .register_type::<PlaneMeshBuilder>()
50            .register_type::<SphereMeshBuilder>()
51            .register_type::<TetrahedronMeshBuilder>()
52            .register_type::<TorusMeshBuilder>()
53            .register_type::<Triangle3dMeshBuilder>();
54    }
55}
56
57/// Adds the [`Mesh`] as an asset and makes sure that they are extracted and prepared for the GPU.
58pub struct MeshPlugin;
59
60impl Plugin for MeshPlugin {
61    fn build(&self, app: &mut App) {
62        app.init_asset::<Mesh>()
63            .init_asset::<skinning::SkinnedMeshInverseBindposes>()
64            .register_asset_reflect::<Mesh>()
65            .register_type::<Mesh3d>()
66            .register_type::<skinning::SkinnedMesh>()
67            .register_type::<Vec<Entity>>()
68            .add_plugins(MeshBuildersPlugin)
69            // 'Mesh' must be prepared after 'Image' as meshes rely on the morph target image being ready
70            .add_plugins(RenderAssetPlugin::<RenderMesh, GpuImage>::default())
71            .add_plugins(MeshAllocatorPlugin)
72            .add_systems(
73                PostUpdate,
74                mark_3d_meshes_as_changed_if_their_assets_changed
75                    .ambiguous_with(VisibilitySystems::CalculateBounds)
76                    .before(AssetEvents),
77            );
78
79        let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
80            return;
81        };
82
83        render_app.init_resource::<MeshVertexBufferLayouts>();
84    }
85}
86
87/// [Inherit weights](inherit_weights) from glTF mesh parent entity to direct
88/// bevy mesh child entities (ie: glTF primitive).
89pub struct MorphPlugin;
90impl Plugin for MorphPlugin {
91    fn build(&self, app: &mut App) {
92        app.register_type::<MorphWeights>()
93            .register_type::<MeshMorphWeights>()
94            .add_systems(PostUpdate, inherit_weights);
95    }
96}
97
98/// Bevy meshes are gltf primitives, [`MorphWeights`] on the bevy node entity
99/// should be inherited by children meshes.
100///
101/// Only direct children are updated, to fulfill the expectations of glTF spec.
102pub fn inherit_weights(
103    morph_nodes: Query<(&Children, &MorphWeights), (Without<Mesh3d>, Changed<MorphWeights>)>,
104    mut morph_primitives: Query<&mut MeshMorphWeights, With<Mesh3d>>,
105) {
106    for (children, parent_weights) in &morph_nodes {
107        let mut iter = morph_primitives.iter_many_mut(children);
108        while let Some(mut child_weight) = iter.fetch_next() {
109            child_weight.clear_weights();
110            child_weight.extend_weights(parent_weights.weights());
111        }
112    }
113}
114
115pub trait MeshAabb {
116    /// Compute the Axis-Aligned Bounding Box of the mesh vertices in model space
117    ///
118    /// Returns `None` if `self` doesn't have [`Mesh::ATTRIBUTE_POSITION`] of
119    /// type [`VertexAttributeValues::Float32x3`], or if `self` doesn't have any vertices.
120    fn compute_aabb(&self) -> Option<Aabb>;
121}
122
123impl MeshAabb for Mesh {
124    fn compute_aabb(&self) -> Option<Aabb> {
125        let Some(VertexAttributeValues::Float32x3(values)) =
126            self.attribute(Mesh::ATTRIBUTE_POSITION)
127        else {
128            return None;
129        };
130
131        Aabb::enclosing(values.iter().map(|p| Vec3::from_slice(p)))
132    }
133}
134
135/// The render world representation of a [`Mesh`].
136#[derive(Debug, Clone)]
137pub struct RenderMesh {
138    /// The number of vertices in the mesh.
139    pub vertex_count: u32,
140
141    /// Morph targets for the mesh, if present.
142    pub morph_targets: Option<TextureView>,
143
144    /// Information about the mesh data buffers, including whether the mesh uses
145    /// indices or not.
146    pub buffer_info: RenderMeshBufferInfo,
147
148    /// Precomputed pipeline key bits for this mesh.
149    pub key_bits: BaseMeshPipelineKey,
150
151    /// A reference to the vertex buffer layout.
152    ///
153    /// Combined with [`RenderMesh::buffer_info`], this specifies the complete
154    /// layout of the buffers associated with this mesh.
155    pub layout: MeshVertexBufferLayoutRef,
156}
157
158impl RenderMesh {
159    /// Returns the primitive topology of this mesh (triangles, triangle strips,
160    /// etc.)
161    #[inline]
162    pub fn primitive_topology(&self) -> PrimitiveTopology {
163        self.key_bits.primitive_topology()
164    }
165
166    /// Returns true if this mesh uses an index buffer or false otherwise.
167    #[inline]
168    pub fn indexed(&self) -> bool {
169        matches!(self.buffer_info, RenderMeshBufferInfo::Indexed { .. })
170    }
171}
172
173/// The index/vertex buffer info of a [`RenderMesh`].
174#[derive(Debug, Clone)]
175pub enum RenderMeshBufferInfo {
176    Indexed {
177        count: u32,
178        index_format: IndexFormat,
179    },
180    NonIndexed,
181}
182
183impl RenderAsset for RenderMesh {
184    type SourceAsset = Mesh;
185    type Param = (
186        SRes<RenderAssets<GpuImage>>,
187        SResMut<MeshVertexBufferLayouts>,
188    );
189
190    #[inline]
191    fn asset_usage(mesh: &Self::SourceAsset) -> RenderAssetUsages {
192        mesh.asset_usage
193    }
194
195    fn byte_len(mesh: &Self::SourceAsset) -> Option<usize> {
196        let mut vertex_size = 0;
197        for attribute_data in mesh.attributes() {
198            let vertex_format = attribute_data.0.format;
199            vertex_size += vertex_format.size() as usize;
200        }
201
202        let vertex_count = mesh.count_vertices();
203        let index_bytes = mesh.get_index_buffer_bytes().map(<[_]>::len).unwrap_or(0);
204        Some(vertex_size * vertex_count + index_bytes)
205    }
206
207    /// Converts the extracted mesh into a [`RenderMesh`].
208    fn prepare_asset(
209        mesh: Self::SourceAsset,
210        _: AssetId<Self::SourceAsset>,
211        (images, mesh_vertex_buffer_layouts): &mut SystemParamItem<Self::Param>,
212    ) -> Result<Self, PrepareAssetError<Self::SourceAsset>> {
213        let morph_targets = match mesh.morph_targets() {
214            Some(mt) => {
215                let Some(target_image) = images.get(mt) else {
216                    return Err(PrepareAssetError::RetryNextUpdate(mesh));
217                };
218                Some(target_image.texture_view.clone())
219            }
220            None => None,
221        };
222
223        let buffer_info = match mesh.indices() {
224            Some(indices) => RenderMeshBufferInfo::Indexed {
225                count: indices.len() as u32,
226                index_format: indices.into(),
227            },
228            None => RenderMeshBufferInfo::NonIndexed,
229        };
230
231        let mesh_vertex_buffer_layout =
232            mesh.get_mesh_vertex_buffer_layout(mesh_vertex_buffer_layouts);
233
234        let mut key_bits = BaseMeshPipelineKey::from_primitive_topology(mesh.primitive_topology());
235        key_bits.set(
236            BaseMeshPipelineKey::MORPH_TARGETS,
237            mesh.morph_targets().is_some(),
238        );
239
240        Ok(RenderMesh {
241            vertex_count: mesh.count_vertices() as u32,
242            buffer_info,
243            key_bits,
244            layout: mesh_vertex_buffer_layout,
245            morph_targets,
246        })
247    }
248}