bevy_render/mesh/
mod.rs

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