bevy_render/mesh/
mod.rs

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