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