Skip to main content

bevy_render/mesh/
mod.rs

1pub mod allocator;
2#[cfg(feature = "morph")]
3pub mod morph;
4
5#[cfg(feature = "morph")]
6use crate::GpuResourceAppExt;
7use crate::{
8    render_asset::{AssetExtractionError, PrepareAssetError, RenderAsset, RenderAssetPlugin},
9    renderer::{RenderDevice, RenderQueue},
10    texture::GpuImage,
11    RenderApp,
12};
13use allocator::MeshAllocatorPlugin;
14use bevy_app::{App, Plugin};
15use bevy_asset::{AssetId, RenderAssetUsages};
16use bevy_camera::primitives::MeshAabb;
17use bevy_ecs::{
18    prelude::*,
19    system::{
20        lifetimeless::{SRes, SResMut},
21        SystemParamItem,
22    },
23};
24pub use bevy_mesh::*;
25use glam::Vec3;
26use wgpu::IndexFormat;
27
28#[cfg(feature = "morph")]
29use crate::mesh::morph::RenderMorphTargetAllocator;
30
31/// Makes sure that [`Mesh`]es are extracted and prepared for the GPU.
32/// Does *not* add the [`Mesh`] as an asset. Use [`MeshPlugin`] for that.
33pub struct MeshRenderAssetPlugin;
34
35impl Plugin for MeshRenderAssetPlugin {
36    fn build(&self, app: &mut App) {
37        app
38            // 'Mesh' must be prepared after 'Image' as meshes rely on the morph target image being ready
39            .add_plugins(RenderAssetPlugin::<RenderMesh, GpuImage>::default())
40            .add_plugins(MeshAllocatorPlugin);
41
42        let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
43            return;
44        };
45
46        render_app.init_resource::<MeshVertexBufferLayouts>();
47    }
48
49    fn finish(&self, app: &mut App) {
50        let Some(_render_app) = app.get_sub_app_mut(RenderApp) else {
51            return;
52        };
53
54        #[cfg(feature = "morph")]
55        _render_app.init_gpu_resource::<RenderMorphTargetAllocator>();
56    }
57}
58
59/// The render world representation of a [`Mesh`].
60#[derive(Debug, Clone)]
61pub struct RenderMesh {
62    /// The number of vertices in the mesh.
63    pub vertex_count: u32,
64
65    /// The 3D center of the mesh in model space.
66    pub aabb_center: Vec3,
67
68    /// Information about the mesh data buffers, including whether the mesh uses
69    /// indices or not.
70    pub buffer_info: RenderMeshBufferInfo,
71
72    /// Precomputed pipeline key bits for this mesh.
73    pub key_bits: BaseMeshPipelineKey,
74
75    /// A reference to the vertex buffer layout.
76    ///
77    /// Combined with [`RenderMesh::buffer_info`], this specifies the complete
78    /// layout of the buffers associated with this mesh.
79    pub layout: MeshVertexBufferLayoutRef,
80}
81
82impl RenderMesh {
83    /// Returns the primitive topology of this mesh (triangles, triangle strips,
84    /// etc.)
85    #[inline]
86    pub fn primitive_topology(&self) -> PrimitiveTopology {
87        self.key_bits.primitive_topology()
88    }
89
90    /// Returns true if this mesh uses an index buffer or false otherwise.
91    #[inline]
92    pub fn indexed(&self) -> bool {
93        matches!(self.buffer_info, RenderMeshBufferInfo::Indexed { .. })
94    }
95
96    #[inline]
97    pub fn index_format(&self) -> Option<IndexFormat> {
98        match self.buffer_info {
99            RenderMeshBufferInfo::Indexed { index_format, .. } => Some(index_format),
100            RenderMeshBufferInfo::NonIndexed => None,
101        }
102    }
103
104    #[inline]
105    pub fn has_morph_targets(&self) -> bool {
106        self.key_bits.contains(BaseMeshPipelineKey::MORPH_TARGETS)
107    }
108}
109
110/// The index/vertex buffer info of a [`RenderMesh`].
111#[derive(Debug, Clone)]
112pub enum RenderMeshBufferInfo {
113    Indexed {
114        count: u32,
115        index_format: IndexFormat,
116    },
117    NonIndexed,
118}
119
120impl RenderAsset for RenderMesh {
121    type SourceAsset = Mesh;
122
123    #[cfg(not(feature = "morph"))]
124    type Param = (
125        SRes<RenderDevice>,
126        SRes<RenderQueue>,
127        SResMut<MeshVertexBufferLayouts>,
128        (),
129    );
130    #[cfg(feature = "morph")]
131    type Param = (
132        SRes<RenderDevice>,
133        SRes<RenderQueue>,
134        SResMut<MeshVertexBufferLayouts>,
135        SResMut<RenderMorphTargetAllocator>,
136    );
137
138    #[inline]
139    fn asset_usage(mesh: &Self::SourceAsset) -> RenderAssetUsages {
140        mesh.asset_usage
141    }
142
143    fn take_gpu_data(
144        source: &mut Self::SourceAsset,
145        _previous_gpu_asset: Option<&Self>,
146    ) -> Result<Self::SourceAsset, AssetExtractionError> {
147        source
148            .take_gpu_data()
149            .map_err(|_| AssetExtractionError::AlreadyExtracted)
150    }
151
152    fn byte_len(mesh: &Self::SourceAsset) -> Option<usize> {
153        let mut vertex_size = 0;
154        for attribute_data in mesh.attributes() {
155            let vertex_format = attribute_data.0.format;
156            vertex_size += vertex_format.size() as usize;
157        }
158
159        let vertex_count = mesh.count_vertices();
160        let index_bytes = mesh.get_index_buffer_bytes().map(<[_]>::len).unwrap_or(0);
161        Some(vertex_size * vertex_count + index_bytes)
162    }
163
164    /// Converts the extracted mesh into a [`RenderMesh`].
165    fn prepare_asset(
166        mesh: Self::SourceAsset,
167        _mesh_id: AssetId<Self::SourceAsset>,
168        (
169            _render_device,
170            _render_queue,
171            mesh_vertex_buffer_layouts,
172            _render_morph_targets_allocator,
173        ): &mut SystemParamItem<Self::Param>,
174        _: Option<&Self>,
175    ) -> Result<Self, PrepareAssetError<Self::SourceAsset>> {
176        let (buffer_info, index_format) = match mesh.indices() {
177            Some(indices) => (
178                RenderMeshBufferInfo::Indexed {
179                    count: indices.len() as u32,
180                    index_format: indices.into(),
181                },
182                Some(indices.into()),
183            ),
184            None => (RenderMeshBufferInfo::NonIndexed, None),
185        };
186
187        let mesh_vertex_buffer_layout =
188            mesh.get_mesh_vertex_buffer_layout(mesh_vertex_buffer_layouts);
189
190        let key_bits = BaseMeshPipelineKey::from_primitive_topology_and_strip_index(
191            mesh.primitive_topology(),
192            index_format,
193        );
194        #[cfg(feature = "morph")]
195        let key_bits = if mesh.morph_targets().is_some() {
196            key_bits | BaseMeshPipelineKey::MORPH_TARGETS
197        } else {
198            key_bits
199        };
200
201        // Place the morph displacements in an image if necessary.
202        #[cfg(feature = "morph")]
203        if let Some(morph_targets) = mesh.morph_targets() {
204            _render_morph_targets_allocator.allocate(
205                _render_device,
206                _render_queue,
207                _mesh_id,
208                morph_targets,
209                mesh.count_vertices(),
210            );
211        }
212
213        Ok(RenderMesh {
214            vertex_count: mesh.count_vertices() as u32,
215            aabb_center: match mesh.compute_aabb() {
216                Some(aabb) => aabb.center.into(),
217                None => Vec3::ZERO,
218            },
219            buffer_info,
220            key_bits,
221            layout: mesh_vertex_buffer_layout,
222        })
223    }
224
225    fn unload_asset(
226        _mesh_id: AssetId<Self::SourceAsset>,
227        (_, _, _, _render_morph_targets_allocator): &mut SystemParamItem<Self::Param>,
228    ) {
229        // Free the morph target images if necessary.
230        #[cfg(feature = "morph")]
231        _render_morph_targets_allocator.free(_mesh_id);
232    }
233}