Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_mesh/src/mesh.rs
9367 views
1
use bevy_transform::components::Transform;
2
pub use wgpu_types::PrimitiveTopology;
3
4
use super::{
5
skinning::{SkinnedMeshBounds, SkinnedMeshBoundsError},
6
triangle_area_normal, triangle_normal, FourIterators, Indices, MeshAttributeData,
7
MeshTrianglesError, MeshVertexAttribute, MeshVertexAttributeId, MeshVertexBufferLayout,
8
MeshVertexBufferLayoutRef, MeshVertexBufferLayouts, MeshWindingInvertError,
9
VertexAttributeValues, VertexBufferLayout,
10
};
11
#[cfg(feature = "serialize")]
12
use crate::SerializedMeshAttributeData;
13
use alloc::collections::BTreeMap;
14
#[cfg(feature = "morph")]
15
use bevy_asset::Handle;
16
use bevy_asset::{Asset, RenderAssetUsages};
17
#[cfg(feature = "morph")]
18
use bevy_image::Image;
19
use bevy_math::{bounding::Aabb3d, primitives::Triangle3d, *};
20
use bevy_platform::collections::{hash_map, HashMap};
21
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
22
use bytemuck::cast_slice;
23
use core::hash::{Hash, Hasher};
24
use core::ptr;
25
#[cfg(feature = "serialize")]
26
use serde::{Deserialize, Serialize};
27
use thiserror::Error;
28
use tracing::warn;
29
use wgpu_types::{VertexAttribute, VertexFormat, VertexStepMode};
30
31
pub const INDEX_BUFFER_ASSET_INDEX: u64 = 0;
32
pub const VERTEX_ATTRIBUTE_BUFFER_ID: u64 = 10;
33
34
/// Error from accessing mesh vertex attributes or indices
35
#[derive(Error, Debug, Clone)]
36
pub enum MeshAccessError {
37
#[error("The mesh vertex/index data has been extracted to the RenderWorld (via `Mesh::asset_usage`)")]
38
ExtractedToRenderWorld,
39
#[error("The requested mesh data wasn't found in this mesh")]
40
NotFound,
41
}
42
43
const MESH_EXTRACTED_ERROR: &str = "Mesh has been extracted to RenderWorld. To access vertex attributes, the mesh `asset_usage` must include `MAIN_WORLD`";
44
45
// storage for extractable data with access methods which return errors if the
46
// contents have already been extracted
47
#[derive(Debug, Clone, PartialEq, Reflect, Default)]
48
enum MeshExtractableData<T> {
49
Data(T),
50
#[default]
51
NoData,
52
ExtractedToRenderWorld,
53
}
54
55
impl<T> MeshExtractableData<T> {
56
// get a reference to internal data. returns error if data has been extracted, or if no
57
// data exists
58
fn as_ref(&self) -> Result<&T, MeshAccessError> {
59
match self {
60
MeshExtractableData::Data(data) => Ok(data),
61
MeshExtractableData::NoData => Err(MeshAccessError::NotFound),
62
MeshExtractableData::ExtractedToRenderWorld => {
63
Err(MeshAccessError::ExtractedToRenderWorld)
64
}
65
}
66
}
67
68
// get an optional reference to internal data. returns error if data has been extracted
69
fn as_ref_option(&self) -> Result<Option<&T>, MeshAccessError> {
70
match self {
71
MeshExtractableData::Data(data) => Ok(Some(data)),
72
MeshExtractableData::NoData => Ok(None),
73
MeshExtractableData::ExtractedToRenderWorld => {
74
Err(MeshAccessError::ExtractedToRenderWorld)
75
}
76
}
77
}
78
79
// get a mutable reference to internal data. returns error if data has been extracted,
80
// or if no data exists
81
fn as_mut(&mut self) -> Result<&mut T, MeshAccessError> {
82
match self {
83
MeshExtractableData::Data(data) => Ok(data),
84
MeshExtractableData::NoData => Err(MeshAccessError::NotFound),
85
MeshExtractableData::ExtractedToRenderWorld => {
86
Err(MeshAccessError::ExtractedToRenderWorld)
87
}
88
}
89
}
90
91
// get an optional mutable reference to internal data. returns error if data has been extracted
92
fn as_mut_option(&mut self) -> Result<Option<&mut T>, MeshAccessError> {
93
match self {
94
MeshExtractableData::Data(data) => Ok(Some(data)),
95
MeshExtractableData::NoData => Ok(None),
96
MeshExtractableData::ExtractedToRenderWorld => {
97
Err(MeshAccessError::ExtractedToRenderWorld)
98
}
99
}
100
}
101
102
// extract data and replace self with `ExtractedToRenderWorld`. returns error if
103
// data has been extracted
104
fn extract(&mut self) -> Result<MeshExtractableData<T>, MeshAccessError> {
105
match core::mem::replace(self, MeshExtractableData::ExtractedToRenderWorld) {
106
MeshExtractableData::ExtractedToRenderWorld => {
107
Err(MeshAccessError::ExtractedToRenderWorld)
108
}
109
not_extracted => Ok(not_extracted),
110
}
111
}
112
113
// replace internal data. returns the existing data, or an error if data has been extracted
114
fn replace(
115
&mut self,
116
data: impl Into<MeshExtractableData<T>>,
117
) -> Result<Option<T>, MeshAccessError> {
118
match core::mem::replace(self, data.into()) {
119
MeshExtractableData::ExtractedToRenderWorld => {
120
*self = MeshExtractableData::ExtractedToRenderWorld;
121
Err(MeshAccessError::ExtractedToRenderWorld)
122
}
123
MeshExtractableData::Data(t) => Ok(Some(t)),
124
MeshExtractableData::NoData => Ok(None),
125
}
126
}
127
}
128
129
impl<T> From<Option<T>> for MeshExtractableData<T> {
130
fn from(value: Option<T>) -> Self {
131
match value {
132
Some(data) => MeshExtractableData::Data(data),
133
None => MeshExtractableData::NoData,
134
}
135
}
136
}
137
138
/// A 3D object made out of vertices representing triangles, lines, or points,
139
/// with "attribute" values for each vertex.
140
///
141
/// Meshes can be automatically generated by a bevy `AssetLoader` (generally by loading a `Gltf` file),
142
/// or by converting a [primitive](bevy_math::primitives) using [`into`](Into).
143
/// It is also possible to create one manually. They can be edited after creation.
144
///
145
/// Meshes can be rendered with a [`Mesh2d`](crate::Mesh2d) and `MeshMaterial2d`
146
/// or [`Mesh3d`](crate::Mesh3d) and `MeshMaterial3d` for 2D and 3D respectively.
147
///
148
/// A [`Mesh`] in Bevy is equivalent to a "primitive" in the glTF format, for a
149
/// glTF Mesh representation, see `GltfMesh`.
150
///
151
/// ## Manual creation
152
///
153
/// The following function will construct a flat mesh, to be rendered with a
154
/// `StandardMaterial` or `ColorMaterial`:
155
///
156
/// ```
157
/// # use bevy_mesh::{Mesh, Indices, PrimitiveTopology};
158
/// # use bevy_asset::RenderAssetUsages;
159
/// fn create_simple_parallelogram() -> Mesh {
160
/// // Create a new mesh using a triangle list topology, where each set of 3 vertices composes a triangle.
161
/// Mesh::new(PrimitiveTopology::TriangleList, RenderAssetUsages::default())
162
/// // Add 4 vertices, each with its own position attribute (coordinate in
163
/// // 3D space), for each of the corners of the parallelogram.
164
/// .with_inserted_attribute(
165
/// Mesh::ATTRIBUTE_POSITION,
166
/// vec![[0.0, 0.0, 0.0], [1.0, 2.0, 0.0], [2.0, 2.0, 0.0], [1.0, 0.0, 0.0]]
167
/// )
168
/// // Assign a UV coordinate to each vertex.
169
/// .with_inserted_attribute(
170
/// Mesh::ATTRIBUTE_UV_0,
171
/// vec![[0.0, 1.0], [0.5, 0.0], [1.0, 0.0], [0.5, 1.0]]
172
/// )
173
/// // Assign normals (everything points outwards)
174
/// .with_inserted_attribute(
175
/// Mesh::ATTRIBUTE_NORMAL,
176
/// vec![[0.0, 0.0, 1.0], [0.0, 0.0, 1.0], [0.0, 0.0, 1.0], [0.0, 0.0, 1.0]]
177
/// )
178
/// // After defining all the vertices and their attributes, build each triangle using the
179
/// // indices of the vertices that make it up in a counter-clockwise order.
180
/// .with_inserted_indices(Indices::U32(vec![
181
/// // First triangle
182
/// 0, 3, 1,
183
/// // Second triangle
184
/// 1, 3, 2
185
/// ]))
186
/// }
187
/// ```
188
///
189
/// You can see how it looks like [here](https://github.com/bevyengine/bevy/blob/main/assets/docs/Mesh.png),
190
/// used in a [`Mesh3d`](crate::Mesh3d) with a square bevy logo texture, with added axis, points,
191
/// lines and text for clarity.
192
///
193
/// ## Other examples
194
///
195
/// For further visualization, explanation, and examples, see the built-in Bevy examples,
196
/// and the [implementation of the built-in shapes](https://github.com/bevyengine/bevy/tree/main/crates/bevy_mesh/src/primitives).
197
/// In particular, [generate_custom_mesh](https://github.com/bevyengine/bevy/blob/main/examples/3d/generate_custom_mesh.rs)
198
/// teaches you to access and modify the attributes of a [`Mesh`] after creating it.
199
///
200
/// ## Common points of confusion
201
///
202
/// - UV maps in Bevy start at the top-left, see [`ATTRIBUTE_UV_0`](Mesh::ATTRIBUTE_UV_0),
203
/// other APIs can have other conventions, `OpenGL` starts at bottom-left.
204
/// - It is possible and sometimes useful for multiple vertices to have the same
205
/// [position attribute](Mesh::ATTRIBUTE_POSITION) value,
206
/// it's a common technique in 3D modeling for complex UV mapping or other calculations.
207
/// - Bevy performs frustum culling based on the `Aabb` of meshes, which is calculated
208
/// and added automatically for new meshes only. If a mesh is modified, the entity's `Aabb`
209
/// needs to be updated manually or deleted so that it is re-calculated.
210
///
211
/// ## Use with `StandardMaterial`
212
///
213
/// To render correctly with `StandardMaterial`, a mesh needs to have properly defined:
214
/// - [`UVs`](Mesh::ATTRIBUTE_UV_0): Bevy needs to know how to map a texture onto the mesh
215
/// (also true for `ColorMaterial`).
216
/// - [`Normals`](Mesh::ATTRIBUTE_NORMAL): Bevy needs to know how light interacts with your mesh.
217
/// [0.0, 0.0, 1.0] is very common for simple flat meshes on the XY plane,
218
/// because simple meshes are smooth and they don't require complex light calculations.
219
/// - Vertex winding order: by default, `StandardMaterial.cull_mode` is `Some(Face::Back)`,
220
/// which means that Bevy would *only* render the "front" of each triangle, which
221
/// is the side of the triangle from where the vertices appear in a *counter-clockwise* order.
222
///
223
/// ## Remote Inspection
224
///
225
/// To transmit a [`Mesh`] between two running Bevy apps, e.g. through BRP, use [`SerializedMesh`].
226
/// This type is only meant for short-term transmission between same versions and should not be stored anywhere.
227
#[derive(Asset, Debug, Clone, Reflect, PartialEq)]
228
#[reflect(Clone)]
229
pub struct Mesh {
230
#[reflect(ignore, clone)]
231
primitive_topology: PrimitiveTopology,
232
/// `std::collections::BTreeMap` with all defined vertex attributes (Positions, Normals, ...)
233
/// for this mesh. Attribute ids to attribute values.
234
/// Uses a [`BTreeMap`] because, unlike `HashMap`, it has a defined iteration order,
235
/// which allows easy stable `VertexBuffers` (i.e. same buffer order)
236
#[reflect(ignore, clone)]
237
attributes: MeshExtractableData<BTreeMap<MeshVertexAttributeId, MeshAttributeData>>,
238
indices: MeshExtractableData<Indices>,
239
#[cfg(feature = "morph")]
240
morph_targets: MeshExtractableData<Handle<Image>>,
241
#[cfg(feature = "morph")]
242
morph_target_names: MeshExtractableData<Vec<String>>,
243
pub asset_usage: RenderAssetUsages,
244
/// Whether or not to build a BLAS for use with `bevy_solari` raytracing.
245
///
246
/// Note that this is _not_ whether the mesh is _compatible_ with `bevy_solari` raytracing.
247
/// This field just controls whether or not a BLAS gets built for this mesh, assuming that
248
/// the mesh is compatible.
249
///
250
/// The use case for this field is using lower-resolution proxy meshes for raytracing (to save on BLAS memory usage),
251
/// while using higher-resolution meshes for raster. You can set this field to true for the lower-resolution proxy mesh,
252
/// and to false for the high-resolution raster mesh.
253
///
254
/// Alternatively, you can use the same mesh for both raster and raytracing, with this field set to true.
255
///
256
/// Does nothing if not used with `bevy_solari`, or if the mesh is not compatible
257
/// with `bevy_solari` (see `bevy_solari`'s docs).
258
pub enable_raytracing: bool,
259
/// Precomputed min and max extents of the mesh position data. Used mainly for constructing `Aabb`s for frustum culling.
260
/// This data will be set if/when a mesh is extracted to the GPU
261
pub final_aabb: Option<Aabb3d>,
262
skinned_mesh_bounds: Option<SkinnedMeshBounds>,
263
}
264
265
impl Mesh {
266
/// Where the vertex is located in space. Use in conjunction with [`Mesh::insert_attribute`]
267
/// or [`Mesh::with_inserted_attribute`].
268
///
269
/// The format of this attribute is [`VertexFormat::Float32x3`].
270
pub const ATTRIBUTE_POSITION: MeshVertexAttribute =
271
MeshVertexAttribute::new("Vertex_Position", 0, VertexFormat::Float32x3);
272
273
/// The direction the vertex normal is facing in.
274
/// Use in conjunction with [`Mesh::insert_attribute`] or [`Mesh::with_inserted_attribute`].
275
///
276
/// The format of this attribute is [`VertexFormat::Float32x3`].
277
pub const ATTRIBUTE_NORMAL: MeshVertexAttribute =
278
MeshVertexAttribute::new("Vertex_Normal", 1, VertexFormat::Float32x3);
279
280
/// Texture coordinates for the vertex. Use in conjunction with [`Mesh::insert_attribute`]
281
/// or [`Mesh::with_inserted_attribute`].
282
///
283
/// Generally `[0.,0.]` is mapped to the top left of the texture, and `[1.,1.]` to the bottom-right.
284
///
285
/// By default values outside will be clamped per pixel not for the vertex,
286
/// "stretching" the borders of the texture.
287
/// This behavior can be useful in some cases, usually when the borders have only
288
/// one color, for example a logo, and you want to "extend" those borders.
289
///
290
/// For different mapping outside of `0..=1` range,
291
/// see [`ImageAddressMode`](bevy_image::ImageAddressMode).
292
///
293
/// The format of this attribute is [`VertexFormat::Float32x2`].
294
pub const ATTRIBUTE_UV_0: MeshVertexAttribute =
295
MeshVertexAttribute::new("Vertex_Uv", 2, VertexFormat::Float32x2);
296
297
/// Alternate texture coordinates for the vertex. Use in conjunction with
298
/// [`Mesh::insert_attribute`] or [`Mesh::with_inserted_attribute`].
299
///
300
/// Typically, these are used for lightmaps, textures that provide
301
/// precomputed illumination.
302
///
303
/// The format of this attribute is [`VertexFormat::Float32x2`].
304
pub const ATTRIBUTE_UV_1: MeshVertexAttribute =
305
MeshVertexAttribute::new("Vertex_Uv_1", 3, VertexFormat::Float32x2);
306
307
/// The direction of the vertex tangent. Used for normal mapping.
308
/// Usually generated with [`generate_tangents`](Mesh::generate_tangents) or
309
/// [`with_generated_tangents`](Mesh::with_generated_tangents).
310
///
311
/// The format of this attribute is [`VertexFormat::Float32x4`].
312
pub const ATTRIBUTE_TANGENT: MeshVertexAttribute =
313
MeshVertexAttribute::new("Vertex_Tangent", 4, VertexFormat::Float32x4);
314
315
/// Per vertex coloring. Use in conjunction with [`Mesh::insert_attribute`]
316
/// or [`Mesh::with_inserted_attribute`].
317
///
318
/// The format of this attribute is [`VertexFormat::Float32x4`].
319
pub const ATTRIBUTE_COLOR: MeshVertexAttribute =
320
MeshVertexAttribute::new("Vertex_Color", 5, VertexFormat::Float32x4);
321
322
/// Per vertex joint transform matrix weight. Use in conjunction with [`Mesh::insert_attribute`]
323
/// or [`Mesh::with_inserted_attribute`].
324
///
325
/// The format of this attribute is [`VertexFormat::Float32x4`].
326
pub const ATTRIBUTE_JOINT_WEIGHT: MeshVertexAttribute =
327
MeshVertexAttribute::new("Vertex_JointWeight", 6, VertexFormat::Float32x4);
328
329
/// Per vertex joint transform matrix index. Use in conjunction with [`Mesh::insert_attribute`]
330
/// or [`Mesh::with_inserted_attribute`].
331
///
332
/// The format of this attribute is [`VertexFormat::Uint16x4`].
333
pub const ATTRIBUTE_JOINT_INDEX: MeshVertexAttribute =
334
MeshVertexAttribute::new("Vertex_JointIndex", 7, VertexFormat::Uint16x4);
335
336
/// The first index that can be used for custom vertex attributes.
337
/// Only the attributes with an index below this are used by Bevy.
338
pub const FIRST_AVAILABLE_CUSTOM_ATTRIBUTE: u64 = 8;
339
340
/// Construct a new mesh. You need to provide a [`PrimitiveTopology`] so that the
341
/// renderer knows how to treat the vertex data. Most of the time this will be
342
/// [`PrimitiveTopology::TriangleList`].
343
pub fn new(primitive_topology: PrimitiveTopology, asset_usage: RenderAssetUsages) -> Self {
344
Mesh {
345
primitive_topology,
346
attributes: MeshExtractableData::Data(Default::default()),
347
indices: MeshExtractableData::NoData,
348
#[cfg(feature = "morph")]
349
morph_targets: MeshExtractableData::NoData,
350
#[cfg(feature = "morph")]
351
morph_target_names: MeshExtractableData::NoData,
352
asset_usage,
353
enable_raytracing: true,
354
final_aabb: None,
355
skinned_mesh_bounds: None,
356
}
357
}
358
359
/// Returns the topology of the mesh.
360
pub fn primitive_topology(&self) -> PrimitiveTopology {
361
self.primitive_topology
362
}
363
364
/// Sets the data for a vertex attribute (position, normal, etc.). The name will
365
/// often be one of the associated constants such as [`Mesh::ATTRIBUTE_POSITION`].
366
///
367
/// `Aabb` of entities with modified mesh are not updated automatically.
368
///
369
/// # Panics
370
/// Panics when the format of the values does not match the attribute's format.
371
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
372
/// this as an error use [`Mesh::try_insert_attribute`]
373
#[inline]
374
pub fn insert_attribute(
375
&mut self,
376
attribute: MeshVertexAttribute,
377
values: impl Into<VertexAttributeValues>,
378
) {
379
self.try_insert_attribute(attribute, values)
380
.expect(MESH_EXTRACTED_ERROR);
381
}
382
383
/// Sets the data for a vertex attribute (position, normal, etc.). The name will
384
/// often be one of the associated constants such as [`Mesh::ATTRIBUTE_POSITION`].
385
///
386
/// `Aabb` of entities with modified mesh are not updated automatically.
387
///
388
/// Returns an error if the mesh data has been extracted to `RenderWorld`.
389
///
390
/// # Panics
391
/// Panics when the format of the values does not match the attribute's format.
392
#[inline]
393
pub fn try_insert_attribute(
394
&mut self,
395
attribute: MeshVertexAttribute,
396
values: impl Into<VertexAttributeValues>,
397
) -> Result<(), MeshAccessError> {
398
let values = values.into();
399
let values_format = VertexFormat::from(&values);
400
if values_format != attribute.format {
401
panic!(
402
"Failed to insert attribute. Invalid attribute format for {}. Given format is {values_format:?} but expected {:?}",
403
attribute.name, attribute.format
404
);
405
}
406
407
self.attributes
408
.as_mut()?
409
.insert(attribute.id, MeshAttributeData { attribute, values });
410
Ok(())
411
}
412
413
/// Consumes the mesh and returns a mesh with data set for a vertex attribute (position, normal, etc.).
414
/// The name will often be one of the associated constants such as [`Mesh::ATTRIBUTE_POSITION`].
415
///
416
/// (Alternatively, you can use [`Mesh::insert_attribute`] to mutate an existing mesh in-place)
417
///
418
/// `Aabb` of entities with modified mesh are not updated automatically.
419
///
420
/// # Panics
421
/// Panics when the format of the values does not match the attribute's format.
422
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
423
/// this as an error use [`Mesh::try_with_inserted_attribute`]
424
#[must_use]
425
#[inline]
426
pub fn with_inserted_attribute(
427
mut self,
428
attribute: MeshVertexAttribute,
429
values: impl Into<VertexAttributeValues>,
430
) -> Self {
431
self.insert_attribute(attribute, values);
432
self
433
}
434
435
/// Consumes the mesh and returns a mesh with data set for a vertex attribute (position, normal, etc.).
436
/// The name will often be one of the associated constants such as [`Mesh::ATTRIBUTE_POSITION`].
437
///
438
/// (Alternatively, you can use [`Mesh::insert_attribute`] to mutate an existing mesh in-place)
439
///
440
/// `Aabb` of entities with modified mesh are not updated automatically.
441
///
442
/// Returns an error if the mesh data has been extracted to `RenderWorld`.
443
#[inline]
444
pub fn try_with_inserted_attribute(
445
mut self,
446
attribute: MeshVertexAttribute,
447
values: impl Into<VertexAttributeValues>,
448
) -> Result<Self, MeshAccessError> {
449
self.try_insert_attribute(attribute, values)?;
450
Ok(self)
451
}
452
453
/// Removes the data for a vertex attribute
454
///
455
/// # Panics
456
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
457
/// this as an error use [`Mesh::try_remove_attribute`]
458
pub fn remove_attribute(
459
&mut self,
460
attribute: impl Into<MeshVertexAttributeId>,
461
) -> Option<VertexAttributeValues> {
462
self.attributes
463
.as_mut()
464
.expect(MESH_EXTRACTED_ERROR)
465
.remove(&attribute.into())
466
.map(|data| data.values)
467
}
468
469
/// Removes the data for a vertex attribute
470
/// Returns an error if the mesh data has been extracted to `RenderWorld`or
471
/// if the attribute does not exist.
472
pub fn try_remove_attribute(
473
&mut self,
474
attribute: impl Into<MeshVertexAttributeId>,
475
) -> Result<VertexAttributeValues, MeshAccessError> {
476
Ok(self
477
.attributes
478
.as_mut()?
479
.remove(&attribute.into())
480
.ok_or(MeshAccessError::NotFound)?
481
.values)
482
}
483
484
/// Consumes the mesh and returns a mesh without the data for a vertex attribute
485
///
486
/// (Alternatively, you can use [`Mesh::remove_attribute`] to mutate an existing mesh in-place)
487
///
488
/// # Panics
489
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
490
/// this as an error use [`Mesh::try_with_removed_attribute`]
491
#[must_use]
492
pub fn with_removed_attribute(mut self, attribute: impl Into<MeshVertexAttributeId>) -> Self {
493
self.remove_attribute(attribute);
494
self
495
}
496
497
/// Consumes the mesh and returns a mesh without the data for a vertex attribute
498
///
499
/// (Alternatively, you can use [`Mesh::remove_attribute`] to mutate an existing mesh in-place)
500
///
501
/// Returns an error if the mesh data has been extracted to `RenderWorld`or
502
/// if the attribute does not exist.
503
pub fn try_with_removed_attribute(
504
mut self,
505
attribute: impl Into<MeshVertexAttributeId>,
506
) -> Result<Self, MeshAccessError> {
507
self.try_remove_attribute(attribute)?;
508
Ok(self)
509
}
510
511
/// Returns a bool indicating if the attribute is present in this mesh's vertex data.
512
///
513
/// # Panics
514
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
515
/// this as an error use [`Mesh::try_contains_attribute`]
516
#[inline]
517
pub fn contains_attribute(&self, id: impl Into<MeshVertexAttributeId>) -> bool {
518
self.attributes
519
.as_ref()
520
.expect(MESH_EXTRACTED_ERROR)
521
.contains_key(&id.into())
522
}
523
524
/// Returns a bool indicating if the attribute is present in this mesh's vertex data.
525
///
526
/// Returns an error if the mesh data has been extracted to `RenderWorld`.
527
#[inline]
528
pub fn try_contains_attribute(
529
&self,
530
id: impl Into<MeshVertexAttributeId>,
531
) -> Result<bool, MeshAccessError> {
532
Ok(self.attributes.as_ref()?.contains_key(&id.into()))
533
}
534
535
/// Retrieves the data currently set to the vertex attribute with the specified [`MeshVertexAttributeId`].
536
///
537
/// # Panics
538
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
539
/// this as an error use [`Mesh::try_attribute`] or [`Mesh::try_attribute_option`]
540
#[inline]
541
pub fn attribute(
542
&self,
543
id: impl Into<MeshVertexAttributeId>,
544
) -> Option<&VertexAttributeValues> {
545
self.try_attribute_option(id).expect(MESH_EXTRACTED_ERROR)
546
}
547
548
/// Retrieves the data currently set to the vertex attribute with the specified [`MeshVertexAttributeId`].
549
///
550
/// Returns an error if the mesh data has been extracted to `RenderWorld`or
551
/// if the attribute does not exist.
552
#[inline]
553
pub fn try_attribute(
554
&self,
555
id: impl Into<MeshVertexAttributeId>,
556
) -> Result<&VertexAttributeValues, MeshAccessError> {
557
self.try_attribute_option(id)?
558
.ok_or(MeshAccessError::NotFound)
559
}
560
561
/// Retrieves the data currently set to the vertex attribute with the specified [`MeshVertexAttributeId`].
562
///
563
/// Returns an error if the mesh data has been extracted to `RenderWorld`.
564
#[inline]
565
pub fn try_attribute_option(
566
&self,
567
id: impl Into<MeshVertexAttributeId>,
568
) -> Result<Option<&VertexAttributeValues>, MeshAccessError> {
569
Ok(self
570
.attributes
571
.as_ref()?
572
.get(&id.into())
573
.map(|data| &data.values))
574
}
575
576
/// Retrieves the full data currently set to the vertex attribute with the specified [`MeshVertexAttributeId`].
577
#[inline]
578
pub(crate) fn try_attribute_data(
579
&self,
580
id: impl Into<MeshVertexAttributeId>,
581
) -> Result<Option<&MeshAttributeData>, MeshAccessError> {
582
Ok(self.attributes.as_ref()?.get(&id.into()))
583
}
584
585
/// Retrieves the data currently set to the vertex attribute with the specified `name` mutably.
586
///
587
/// # Panics
588
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
589
/// this as an error use [`Mesh::try_attribute_mut`]
590
#[inline]
591
pub fn attribute_mut(
592
&mut self,
593
id: impl Into<MeshVertexAttributeId>,
594
) -> Option<&mut VertexAttributeValues> {
595
self.try_attribute_mut_option(id)
596
.expect(MESH_EXTRACTED_ERROR)
597
}
598
599
/// Retrieves the data currently set to the vertex attribute with the specified `name` mutably.
600
///
601
/// Returns an error if the mesh data has been extracted to `RenderWorld`or
602
/// if the attribute does not exist.
603
#[inline]
604
pub fn try_attribute_mut(
605
&mut self,
606
id: impl Into<MeshVertexAttributeId>,
607
) -> Result<&mut VertexAttributeValues, MeshAccessError> {
608
self.try_attribute_mut_option(id)?
609
.ok_or(MeshAccessError::NotFound)
610
}
611
612
/// Retrieves the data currently set to the vertex attribute with the specified `name` mutably.
613
///
614
/// Returns an error if the mesh data has been extracted to `RenderWorld`.
615
#[inline]
616
pub fn try_attribute_mut_option(
617
&mut self,
618
id: impl Into<MeshVertexAttributeId>,
619
) -> Result<Option<&mut VertexAttributeValues>, MeshAccessError> {
620
Ok(self
621
.attributes
622
.as_mut()?
623
.get_mut(&id.into())
624
.map(|data| &mut data.values))
625
}
626
627
/// Returns an iterator that yields references to the data of each vertex attribute.
628
///
629
/// # Panics
630
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
631
/// this as an error use [`Mesh::try_attributes`]
632
pub fn attributes(
633
&self,
634
) -> impl Iterator<Item = (&MeshVertexAttribute, &VertexAttributeValues)> {
635
self.try_attributes().expect(MESH_EXTRACTED_ERROR)
636
}
637
638
/// Returns an iterator that yields references to the data of each vertex attribute.
639
/// Returns an error if data has been extracted to `RenderWorld`
640
pub fn try_attributes(
641
&self,
642
) -> Result<impl Iterator<Item = (&MeshVertexAttribute, &VertexAttributeValues)>, MeshAccessError>
643
{
644
Ok(self
645
.attributes
646
.as_ref()?
647
.values()
648
.map(|data| (&data.attribute, &data.values)))
649
}
650
651
/// Returns an iterator that yields mutable references to the data of each vertex attribute.
652
///
653
/// # Panics
654
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
655
/// this as an error use [`Mesh::try_attributes_mut`]
656
pub fn attributes_mut(
657
&mut self,
658
) -> impl Iterator<Item = (&MeshVertexAttribute, &mut VertexAttributeValues)> {
659
self.try_attributes_mut().expect(MESH_EXTRACTED_ERROR)
660
}
661
662
/// Returns an iterator that yields mutable references to the data of each vertex attribute.
663
///
664
/// Returns an error if the mesh data has been extracted to `RenderWorld`.
665
pub fn try_attributes_mut(
666
&mut self,
667
) -> Result<
668
impl Iterator<Item = (&MeshVertexAttribute, &mut VertexAttributeValues)>,
669
MeshAccessError,
670
> {
671
Ok(self
672
.attributes
673
.as_mut()?
674
.values_mut()
675
.map(|data| (&data.attribute, &mut data.values)))
676
}
677
678
/// Sets the vertex indices of the mesh. They describe how triangles are constructed out of the
679
/// vertex attributes and are therefore only useful for the [`PrimitiveTopology`] variants
680
/// that use triangles.
681
///
682
/// # Panics
683
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
684
/// this as an error use [`Mesh::try_insert_indices`]
685
#[inline]
686
pub fn insert_indices(&mut self, indices: Indices) {
687
self.indices
688
.replace(Some(indices))
689
.expect(MESH_EXTRACTED_ERROR);
690
}
691
692
/// Sets the vertex indices of the mesh. They describe how triangles are constructed out of the
693
/// vertex attributes and are therefore only useful for the [`PrimitiveTopology`] variants
694
/// that use triangles.
695
///
696
/// Returns an error if the mesh data has been extracted to `RenderWorld`.
697
#[inline]
698
pub fn try_insert_indices(&mut self, indices: Indices) -> Result<(), MeshAccessError> {
699
self.indices.replace(Some(indices))?;
700
Ok(())
701
}
702
703
/// Consumes the mesh and returns a mesh with the given vertex indices. They describe how triangles
704
/// are constructed out of the vertex attributes and are therefore only useful for the
705
/// [`PrimitiveTopology`] variants that use triangles.
706
///
707
/// (Alternatively, you can use [`Mesh::insert_indices`] to mutate an existing mesh in-place)
708
///
709
/// # Panics
710
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
711
/// this as an error use [`Mesh::try_with_inserted_indices`]
712
#[must_use]
713
#[inline]
714
pub fn with_inserted_indices(mut self, indices: Indices) -> Self {
715
self.insert_indices(indices);
716
self
717
}
718
719
/// Consumes the mesh and returns a mesh with the given vertex indices. They describe how triangles
720
/// are constructed out of the vertex attributes and are therefore only useful for the
721
/// [`PrimitiveTopology`] variants that use triangles.
722
///
723
/// (Alternatively, you can use [`Mesh::try_insert_indices`] to mutate an existing mesh in-place)
724
///
725
/// Returns an error if the mesh data has been extracted to `RenderWorld`.
726
#[inline]
727
pub fn try_with_inserted_indices(mut self, indices: Indices) -> Result<Self, MeshAccessError> {
728
self.try_insert_indices(indices)?;
729
Ok(self)
730
}
731
732
/// Retrieves the vertex `indices` of the mesh, returns None if not found.
733
///
734
/// # Panics
735
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
736
/// this as an error use [`Mesh::try_indices`]
737
#[inline]
738
pub fn indices(&self) -> Option<&Indices> {
739
self.indices.as_ref_option().expect(MESH_EXTRACTED_ERROR)
740
}
741
742
/// Retrieves the vertex `indices` of the mesh.
743
///
744
/// Returns an error if the mesh data has been extracted to `RenderWorld`or
745
/// if the attribute does not exist.
746
#[inline]
747
pub fn try_indices(&self) -> Result<&Indices, MeshAccessError> {
748
self.indices.as_ref()
749
}
750
751
/// Retrieves the vertex `indices` of the mesh, returns None if not found.
752
///
753
/// Returns an error if the mesh data has been extracted to `RenderWorld`.
754
#[inline]
755
pub fn try_indices_option(&self) -> Result<Option<&Indices>, MeshAccessError> {
756
self.indices.as_ref_option()
757
}
758
759
/// Retrieves the vertex `indices` of the mesh mutably.
760
#[inline]
761
pub fn indices_mut(&mut self) -> Option<&mut Indices> {
762
self.try_indices_mut_option().expect(MESH_EXTRACTED_ERROR)
763
}
764
765
/// Retrieves the vertex `indices` of the mesh mutably.
766
///
767
/// Returns an error if the mesh data has been extracted to `RenderWorld`.
768
#[inline]
769
pub fn try_indices_mut(&mut self) -> Result<&mut Indices, MeshAccessError> {
770
self.indices.as_mut()
771
}
772
773
/// Retrieves the vertex `indices` of the mesh mutably.
774
///
775
/// Returns an error if the mesh data has been extracted to `RenderWorld`.
776
#[inline]
777
pub fn try_indices_mut_option(&mut self) -> Result<Option<&mut Indices>, MeshAccessError> {
778
self.indices.as_mut_option()
779
}
780
781
/// Removes the vertex `indices` from the mesh and returns them.
782
///
783
/// # Panics
784
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
785
/// this as an error use [`Mesh::try_remove_indices`]
786
#[inline]
787
pub fn remove_indices(&mut self) -> Option<Indices> {
788
self.try_remove_indices().expect(MESH_EXTRACTED_ERROR)
789
}
790
791
/// Removes the vertex `indices` from the mesh and returns them.
792
///
793
/// Returns an error if the mesh data has been extracted to `RenderWorld`.
794
#[inline]
795
pub fn try_remove_indices(&mut self) -> Result<Option<Indices>, MeshAccessError> {
796
self.indices.replace(None)
797
}
798
799
/// Consumes the mesh and returns a mesh without the vertex `indices` of the mesh.
800
///
801
/// (Alternatively, you can use [`Mesh::remove_indices`] to mutate an existing mesh in-place)
802
///
803
/// # Panics
804
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
805
/// this as an error use [`Mesh::try_with_removed_indices`]
806
#[must_use]
807
pub fn with_removed_indices(mut self) -> Self {
808
self.remove_indices();
809
self
810
}
811
812
/// Consumes the mesh and returns a mesh without the vertex `indices` of the mesh.
813
///
814
/// (Alternatively, you can use [`Mesh::try_remove_indices`] to mutate an existing mesh in-place)
815
///
816
/// Returns an error if the mesh data has been extracted to `RenderWorld`.
817
pub fn try_with_removed_indices(mut self) -> Result<Self, MeshAccessError> {
818
self.try_remove_indices()?;
819
Ok(self)
820
}
821
822
/// Returns the size of a vertex in bytes.
823
///
824
/// # Panics
825
/// Panics when the mesh data has already been extracted to `RenderWorld`.
826
pub fn get_vertex_size(&self) -> u64 {
827
self.attributes
828
.as_ref()
829
.expect(MESH_EXTRACTED_ERROR)
830
.values()
831
.map(|data| data.attribute.format.size())
832
.sum()
833
}
834
835
/// Returns the size required for the vertex buffer in bytes.
836
///
837
/// # Panics
838
/// Panics when the mesh data has already been extracted to `RenderWorld`.
839
pub fn get_vertex_buffer_size(&self) -> usize {
840
let vertex_size = self.get_vertex_size() as usize;
841
let vertex_count = self.count_vertices();
842
vertex_count * vertex_size
843
}
844
845
/// Computes and returns the index data of the mesh as bytes.
846
/// This is used to transform the index data into a GPU friendly format.
847
///
848
/// # Panics
849
/// Panics when the mesh data has already been extracted to `RenderWorld`.
850
pub fn get_index_buffer_bytes(&self) -> Option<&[u8]> {
851
let mesh_indices = self.indices.as_ref_option().expect(MESH_EXTRACTED_ERROR);
852
853
mesh_indices.as_ref().map(|indices| match &indices {
854
Indices::U16(indices) => cast_slice(&indices[..]),
855
Indices::U32(indices) => cast_slice(&indices[..]),
856
})
857
}
858
859
/// Get this `Mesh`'s [`MeshVertexBufferLayout`], used in `SpecializedMeshPipeline`.
860
///
861
/// # Panics
862
/// Panics when the mesh data has already been extracted to `RenderWorld`.
863
pub fn get_mesh_vertex_buffer_layout(
864
&self,
865
mesh_vertex_buffer_layouts: &mut MeshVertexBufferLayouts,
866
) -> MeshVertexBufferLayoutRef {
867
let mesh_attributes = self.attributes.as_ref().expect(MESH_EXTRACTED_ERROR);
868
869
let mut attributes = Vec::with_capacity(mesh_attributes.len());
870
let mut attribute_ids = Vec::with_capacity(mesh_attributes.len());
871
let mut accumulated_offset = 0;
872
for (index, data) in mesh_attributes.values().enumerate() {
873
attribute_ids.push(data.attribute.id);
874
attributes.push(VertexAttribute {
875
offset: accumulated_offset,
876
format: data.attribute.format,
877
shader_location: index as u32,
878
});
879
accumulated_offset += data.attribute.format.size();
880
}
881
882
let layout = MeshVertexBufferLayout {
883
layout: VertexBufferLayout {
884
array_stride: accumulated_offset,
885
step_mode: VertexStepMode::Vertex,
886
attributes,
887
},
888
attribute_ids,
889
};
890
mesh_vertex_buffer_layouts.insert(layout)
891
}
892
893
/// Counts all vertices of the mesh.
894
///
895
/// If the attributes have different vertex counts, the smallest is returned.
896
///
897
/// # Panics
898
/// Panics when the mesh data has already been extracted to `RenderWorld`.
899
pub fn count_vertices(&self) -> usize {
900
let mut vertex_count: Option<usize> = None;
901
let mesh_attributes = self.attributes.as_ref().expect(MESH_EXTRACTED_ERROR);
902
903
for (attribute_id, attribute_data) in mesh_attributes {
904
let attribute_len = attribute_data.values.len();
905
if let Some(previous_vertex_count) = vertex_count {
906
if previous_vertex_count != attribute_len {
907
let name = mesh_attributes
908
.get(attribute_id)
909
.map(|data| data.attribute.name.to_string())
910
.unwrap_or_else(|| format!("{attribute_id:?}"));
911
912
warn!("{name} has a different vertex count ({attribute_len}) than other attributes ({previous_vertex_count}) in this mesh, \
913
all attributes will be truncated to match the smallest.");
914
vertex_count = Some(core::cmp::min(previous_vertex_count, attribute_len));
915
}
916
} else {
917
vertex_count = Some(attribute_len);
918
}
919
}
920
921
vertex_count.unwrap_or(0)
922
}
923
924
/// Computes and returns the vertex data of the mesh as bytes.
925
/// Therefore the attributes are located in the order of their [`MeshVertexAttribute::id`].
926
/// This is used to transform the vertex data into a GPU friendly format.
927
///
928
/// If the vertex attributes have different lengths, they are all truncated to
929
/// the length of the smallest.
930
///
931
/// This is a convenience method which allocates a Vec.
932
/// Prefer pre-allocating and using [`Mesh::write_packed_vertex_buffer_data`] when possible.
933
///
934
/// # Panics
935
/// Panics when the mesh data has already been extracted to `RenderWorld`.
936
pub fn create_packed_vertex_buffer_data(&self) -> Vec<u8> {
937
let mut attributes_interleaved_buffer = vec![0; self.get_vertex_buffer_size()];
938
self.write_packed_vertex_buffer_data(&mut attributes_interleaved_buffer);
939
attributes_interleaved_buffer
940
}
941
942
/// Computes and write the vertex data of the mesh into a mutable byte slice.
943
/// The attributes are located in the order of their [`MeshVertexAttribute::id`].
944
/// This is used to transform the vertex data into a GPU friendly format.
945
///
946
/// If the vertex attributes have different lengths, they are all truncated to
947
/// the length of the smallest.
948
///
949
/// # Panics
950
/// Panics when the mesh data has already been extracted to `RenderWorld`.
951
pub fn write_packed_vertex_buffer_data(&self, slice: &mut [u8]) {
952
let mesh_attributes = self.attributes.as_ref().expect(MESH_EXTRACTED_ERROR);
953
954
let vertex_size = self.get_vertex_size() as usize;
955
let vertex_count = self.count_vertices();
956
// bundle into interleaved buffers
957
let mut attribute_offset = 0;
958
for attribute_data in mesh_attributes.values() {
959
let attribute_size = attribute_data.attribute.format.size() as usize;
960
let attributes_bytes = attribute_data.values.get_bytes();
961
for (vertex_index, attribute_bytes) in attributes_bytes
962
.chunks_exact(attribute_size)
963
.take(vertex_count)
964
.enumerate()
965
{
966
let offset = vertex_index * vertex_size + attribute_offset;
967
slice[offset..offset + attribute_size].copy_from_slice(attribute_bytes);
968
}
969
970
attribute_offset += attribute_size;
971
}
972
}
973
974
/// Duplicates the vertex attributes so that no vertices are shared.
975
///
976
/// This can dramatically increase the vertex count, so make sure this is what you want.
977
/// Does nothing if no [Indices] are set.
978
///
979
/// # Panics
980
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
981
/// this as an error use [`Mesh::try_duplicate_vertices`]
982
pub fn duplicate_vertices(&mut self) {
983
self.try_duplicate_vertices().expect(MESH_EXTRACTED_ERROR);
984
}
985
986
/// Duplicates the vertex attributes so that no vertices are shared.
987
///
988
/// This can dramatically increase the vertex count, so make sure this is what you want.
989
/// Does nothing if no [Indices] are set.
990
///
991
/// Returns an error if the mesh data has been extracted to `RenderWorld`.
992
pub fn try_duplicate_vertices(&mut self) -> Result<(), MeshAccessError> {
993
fn duplicate<T: Copy>(values: &[T], indices: impl Iterator<Item = usize>) -> Vec<T> {
994
indices.map(|i| values[i]).collect()
995
}
996
997
let Some(indices) = self.indices.replace(None)? else {
998
return Ok(());
999
};
1000
1001
let mesh_attributes = self.attributes.as_mut()?;
1002
1003
for attributes in mesh_attributes.values_mut() {
1004
let indices = indices.iter();
1005
#[expect(
1006
clippy::match_same_arms,
1007
reason = "Although the `vec` binding on some match arms may have different types, each variant has different semantics; thus it's not guaranteed that they will use the same type forever."
1008
)]
1009
match &mut attributes.values {
1010
VertexAttributeValues::Float32(vec) => *vec = duplicate(vec, indices),
1011
VertexAttributeValues::Sint32(vec) => *vec = duplicate(vec, indices),
1012
VertexAttributeValues::Uint32(vec) => *vec = duplicate(vec, indices),
1013
VertexAttributeValues::Float32x2(vec) => *vec = duplicate(vec, indices),
1014
VertexAttributeValues::Sint32x2(vec) => *vec = duplicate(vec, indices),
1015
VertexAttributeValues::Uint32x2(vec) => *vec = duplicate(vec, indices),
1016
VertexAttributeValues::Float32x3(vec) => *vec = duplicate(vec, indices),
1017
VertexAttributeValues::Sint32x3(vec) => *vec = duplicate(vec, indices),
1018
VertexAttributeValues::Uint32x3(vec) => *vec = duplicate(vec, indices),
1019
VertexAttributeValues::Sint32x4(vec) => *vec = duplicate(vec, indices),
1020
VertexAttributeValues::Uint32x4(vec) => *vec = duplicate(vec, indices),
1021
VertexAttributeValues::Float32x4(vec) => *vec = duplicate(vec, indices),
1022
VertexAttributeValues::Sint16x2(vec) => *vec = duplicate(vec, indices),
1023
VertexAttributeValues::Snorm16x2(vec) => *vec = duplicate(vec, indices),
1024
VertexAttributeValues::Uint16x2(vec) => *vec = duplicate(vec, indices),
1025
VertexAttributeValues::Unorm16x2(vec) => *vec = duplicate(vec, indices),
1026
VertexAttributeValues::Sint16x4(vec) => *vec = duplicate(vec, indices),
1027
VertexAttributeValues::Snorm16x4(vec) => *vec = duplicate(vec, indices),
1028
VertexAttributeValues::Uint16x4(vec) => *vec = duplicate(vec, indices),
1029
VertexAttributeValues::Unorm16x4(vec) => *vec = duplicate(vec, indices),
1030
VertexAttributeValues::Sint8x2(vec) => *vec = duplicate(vec, indices),
1031
VertexAttributeValues::Snorm8x2(vec) => *vec = duplicate(vec, indices),
1032
VertexAttributeValues::Uint8x2(vec) => *vec = duplicate(vec, indices),
1033
VertexAttributeValues::Unorm8x2(vec) => *vec = duplicate(vec, indices),
1034
VertexAttributeValues::Sint8x4(vec) => *vec = duplicate(vec, indices),
1035
VertexAttributeValues::Snorm8x4(vec) => *vec = duplicate(vec, indices),
1036
VertexAttributeValues::Uint8x4(vec) => *vec = duplicate(vec, indices),
1037
VertexAttributeValues::Unorm8x4(vec) => *vec = duplicate(vec, indices),
1038
}
1039
}
1040
1041
Ok(())
1042
}
1043
1044
/// Consumes the mesh and returns a mesh with no shared vertices.
1045
///
1046
/// This can dramatically increase the vertex count, so make sure this is what you want.
1047
/// Does nothing if no [`Indices`] are set.
1048
///
1049
/// (Alternatively, you can use [`Mesh::duplicate_vertices`] to mutate an existing mesh in-place)
1050
///
1051
/// # Panics
1052
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1053
/// this as an error use [`Mesh::try_with_duplicated_vertices`]
1054
#[must_use]
1055
pub fn with_duplicated_vertices(mut self) -> Self {
1056
self.duplicate_vertices();
1057
self
1058
}
1059
1060
/// Consumes the mesh and returns a mesh with no shared vertices.
1061
///
1062
/// This can dramatically increase the vertex count, so make sure this is what you want.
1063
/// Does nothing if no [`Indices`] are set.
1064
///
1065
/// (Alternatively, you can use [`Mesh::try_duplicate_vertices`] to mutate an existing mesh in-place)
1066
///
1067
/// Returns an error if the mesh data has been extracted to `RenderWorld`.
1068
pub fn try_with_duplicated_vertices(mut self) -> Result<Self, MeshAccessError> {
1069
self.try_duplicate_vertices()?;
1070
Ok(self)
1071
}
1072
1073
/// Remove duplicate vertices and create the index pointing to the unique vertices.
1074
///
1075
/// Returns an error if the mesh data has been extracted to `RenderWorld`.
1076
/// Returns an error if the mesh already has [`Indices`] set, even if there
1077
/// are duplicate vertices. If deduplication is needed with indices already set,
1078
/// consider calling [`Mesh::duplicate_vertices`] and then this function.
1079
pub fn merge_duplicate_vertices(&mut self) -> Result<(), MeshMergeDuplicateVerticesError> {
1080
match self.try_indices() {
1081
Ok(_) => return Err(MeshMergeDuplicateVerticesError::IndicesAlreadySet),
1082
Err(err) => match err {
1083
MeshAccessError::ExtractedToRenderWorld => return Err(err.into()),
1084
MeshAccessError::NotFound => (),
1085
},
1086
}
1087
1088
#[derive(Copy, Clone)]
1089
struct VertexRef<'a> {
1090
mesh_attributes: &'a BTreeMap<MeshVertexAttributeId, MeshAttributeData>,
1091
i: usize,
1092
}
1093
impl<'a> VertexRef<'a> {
1094
fn push_to(&self, target: &mut BTreeMap<MeshVertexAttributeId, MeshAttributeData>) {
1095
for (key, this_attribute_data) in self.mesh_attributes.iter() {
1096
let target_attribute_data = target.get_mut(key).unwrap(); // ok to unwrap, all keys added to new_attributes below
1097
target_attribute_data
1098
.values
1099
.push_from(&this_attribute_data.values, self.i);
1100
}
1101
}
1102
}
1103
impl<'a> PartialEq for VertexRef<'a> {
1104
fn eq(&self, other: &Self) -> bool {
1105
assert!(ptr::eq(self.mesh_attributes, other.mesh_attributes));
1106
for values in self.mesh_attributes.values() {
1107
if values.values.get_bytes_at(self.i) != values.values.get_bytes_at(other.i) {
1108
return false;
1109
}
1110
}
1111
true
1112
}
1113
}
1114
impl<'a> Eq for VertexRef<'a> {}
1115
impl<'a> Hash for VertexRef<'a> {
1116
fn hash<H: Hasher>(&self, state: &mut H) {
1117
for values in self.mesh_attributes.values() {
1118
values.values.get_bytes_at(self.i).hash(state);
1119
}
1120
}
1121
}
1122
1123
let old_attributes = self.attributes.as_ref()?;
1124
1125
let mut new_attributes: BTreeMap<MeshVertexAttributeId, MeshAttributeData> = self
1126
.attributes
1127
.as_ref()?
1128
.iter()
1129
.map(|(k, v)| {
1130
(
1131
*k,
1132
MeshAttributeData {
1133
attribute: v.attribute,
1134
values: VertexAttributeValues::new(VertexFormat::from(&v.values)),
1135
},
1136
)
1137
})
1138
.collect();
1139
1140
let mut vertex_to_new_index: HashMap<VertexRef, u32> = HashMap::new();
1141
let mut indices = Vec::with_capacity(self.count_vertices());
1142
for i in 0..self.count_vertices() {
1143
let len: u32 = vertex_to_new_index
1144
.len()
1145
.try_into()
1146
.expect("The number of vertices exceeds u32::MAX");
1147
let vertex_ref = VertexRef {
1148
mesh_attributes: old_attributes,
1149
i,
1150
};
1151
let j = match vertex_to_new_index.entry(vertex_ref) {
1152
hash_map::Entry::Occupied(e) => *e.get(),
1153
hash_map::Entry::Vacant(e) => {
1154
e.insert(len);
1155
vertex_ref.push_to(&mut new_attributes);
1156
len
1157
}
1158
};
1159
indices.push(j);
1160
}
1161
drop(vertex_to_new_index);
1162
1163
for v in new_attributes.values_mut() {
1164
v.values.shrink_to_fit();
1165
}
1166
1167
self.attributes = MeshExtractableData::Data(new_attributes);
1168
self.indices = MeshExtractableData::Data(Indices::U32(indices));
1169
1170
Ok(())
1171
}
1172
1173
/// Consumes the mesh and returns a mesh with merged vertices.
1174
///
1175
/// (Alternatively, you can use [`Mesh::merge_duplicate_vertices`] to mutate an existing mesh in-place)
1176
///
1177
/// Returns an error if the mesh data has been extracted to `RenderWorld`.
1178
/// Returns an error if the mesh already has [`Indices`] set, even if there
1179
/// are duplicate vertices. If deduplication is needed with indices already set,
1180
/// consider calling [`Mesh::duplicate_vertices`] and then this function.
1181
pub fn with_merge_duplicate_vertices(
1182
mut self,
1183
) -> Result<Self, MeshMergeDuplicateVerticesError> {
1184
self.merge_duplicate_vertices()?;
1185
Ok(self)
1186
}
1187
1188
/// Inverts the winding of the indices such that all counter-clockwise triangles are now
1189
/// clockwise and vice versa.
1190
/// For lines, their start and end indices are flipped.
1191
///
1192
/// Does nothing if no [`Indices`] are set.
1193
/// If this operation succeeded, an [`Ok`] result is returned.
1194
pub fn invert_winding(&mut self) -> Result<(), MeshWindingInvertError> {
1195
fn invert<I>(
1196
indices: &mut [I],
1197
topology: PrimitiveTopology,
1198
) -> Result<(), MeshWindingInvertError> {
1199
match topology {
1200
PrimitiveTopology::TriangleList => {
1201
// Early return if the index count doesn't match
1202
if !indices.len().is_multiple_of(3) {
1203
return Err(MeshWindingInvertError::AbruptIndicesEnd);
1204
}
1205
for chunk in indices.chunks_mut(3) {
1206
// This currently can only be optimized away with unsafe, rework this when `feature(slice_as_chunks)` gets stable.
1207
let [_, b, c] = chunk else {
1208
return Err(MeshWindingInvertError::AbruptIndicesEnd);
1209
};
1210
core::mem::swap(b, c);
1211
}
1212
Ok(())
1213
}
1214
PrimitiveTopology::LineList => {
1215
// Early return if the index count doesn't match
1216
if !indices.len().is_multiple_of(2) {
1217
return Err(MeshWindingInvertError::AbruptIndicesEnd);
1218
}
1219
indices.reverse();
1220
Ok(())
1221
}
1222
PrimitiveTopology::TriangleStrip | PrimitiveTopology::LineStrip => {
1223
indices.reverse();
1224
Ok(())
1225
}
1226
_ => Err(MeshWindingInvertError::WrongTopology),
1227
}
1228
}
1229
1230
let mesh_indices = self.indices.as_mut_option()?;
1231
1232
match mesh_indices {
1233
Some(Indices::U16(vec)) => invert(vec, self.primitive_topology),
1234
Some(Indices::U32(vec)) => invert(vec, self.primitive_topology),
1235
None => Ok(()),
1236
}
1237
}
1238
1239
/// Consumes the mesh and returns a mesh with inverted winding of the indices such
1240
/// that all counter-clockwise triangles are now clockwise and vice versa.
1241
///
1242
/// Does nothing if no [`Indices`] are set.
1243
pub fn with_inverted_winding(mut self) -> Result<Self, MeshWindingInvertError> {
1244
self.invert_winding().map(|_| self)
1245
}
1246
1247
/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of a mesh.
1248
/// If the mesh is indexed, this defaults to smooth normals. Otherwise, it defaults to flat
1249
/// normals.
1250
///
1251
/// # Panics
1252
/// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1253
/// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].=
1254
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1255
/// this as an error use [`Mesh::try_compute_normals`]
1256
pub fn compute_normals(&mut self) {
1257
self.try_compute_normals().expect(MESH_EXTRACTED_ERROR);
1258
}
1259
1260
/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of a mesh.
1261
/// If the mesh is indexed, this defaults to smooth normals. Otherwise, it defaults to flat
1262
/// normals.
1263
///
1264
/// # Panics
1265
/// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1266
/// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].=
1267
pub fn try_compute_normals(&mut self) -> Result<(), MeshAccessError> {
1268
assert!(
1269
matches!(self.primitive_topology, PrimitiveTopology::TriangleList),
1270
"`compute_normals` can only work on `TriangleList`s"
1271
);
1272
if self.try_indices_option()?.is_none() {
1273
self.try_compute_flat_normals()
1274
} else {
1275
self.try_compute_smooth_normals()
1276
}
1277
}
1278
1279
/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of a mesh.
1280
///
1281
/// # Panics
1282
/// Panics if [`Indices`] are set or [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1283
/// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1284
/// Consider calling [`Mesh::duplicate_vertices`] or exporting your mesh with normal
1285
/// attributes.
1286
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1287
/// this as an error use [`Mesh::try_compute_flat_normals`]
1288
///
1289
/// FIXME: This should handle more cases since this is called as a part of gltf
1290
/// mesh loading where we can't really blame users for loading meshes that might
1291
/// not conform to the limitations here!
1292
pub fn compute_flat_normals(&mut self) {
1293
self.try_compute_flat_normals().expect(MESH_EXTRACTED_ERROR);
1294
}
1295
1296
/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of a mesh.
1297
///
1298
/// # Panics
1299
/// Panics if [`Indices`] are set or [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1300
/// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1301
/// Consider calling [`Mesh::duplicate_vertices`] or exporting your mesh with normal
1302
/// attributes.
1303
///
1304
/// FIXME: This should handle more cases since this is called as a part of gltf
1305
/// mesh loading where we can't really blame users for loading meshes that might
1306
/// not conform to the limitations here!
1307
pub fn try_compute_flat_normals(&mut self) -> Result<(), MeshAccessError> {
1308
assert!(
1309
self.try_indices_option()?.is_none(),
1310
"`compute_flat_normals` can't work on indexed geometry. Consider calling either `Mesh::compute_smooth_normals` or `Mesh::duplicate_vertices` followed by `Mesh::compute_flat_normals`."
1311
);
1312
assert!(
1313
matches!(self.primitive_topology, PrimitiveTopology::TriangleList),
1314
"`compute_flat_normals` can only work on `TriangleList`s"
1315
);
1316
1317
let positions = self
1318
.try_attribute(Mesh::ATTRIBUTE_POSITION)?
1319
.as_float3()
1320
.expect("`Mesh::ATTRIBUTE_POSITION` vertex attributes should be of type `float3`");
1321
1322
let normals: Vec<_> = positions
1323
.chunks_exact(3)
1324
.map(|p| triangle_normal(p[0], p[1], p[2]))
1325
.flat_map(|normal| [normal; 3])
1326
.collect();
1327
1328
self.try_insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals)
1329
}
1330
1331
/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of an indexed mesh, smoothing normals for shared
1332
/// vertices.
1333
///
1334
/// This method weights normals by the angles of the corners of connected triangles, thus
1335
/// eliminating triangle area and count as factors in the final normal. This does make it
1336
/// somewhat slower than [`Mesh::compute_area_weighted_normals`] which does not need to
1337
/// greedily normalize each triangle's normal or calculate corner angles.
1338
///
1339
/// If you would rather have the computed normals be weighted by triangle area, see
1340
/// [`Mesh::compute_area_weighted_normals`] instead. If you need to weight them in some other
1341
/// way, see [`Mesh::compute_custom_smooth_normals`].
1342
///
1343
/// # Panics
1344
/// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1345
/// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1346
/// Panics if the mesh does not have indices defined.
1347
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1348
/// this as an error use [`Mesh::try_compute_smooth_normals`]
1349
pub fn compute_smooth_normals(&mut self) {
1350
self.try_compute_smooth_normals()
1351
.expect(MESH_EXTRACTED_ERROR);
1352
}
1353
1354
/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of an indexed mesh, smoothing normals for shared
1355
/// vertices.
1356
///
1357
/// This method weights normals by the angles of the corners of connected triangles, thus
1358
/// eliminating triangle area and count as factors in the final normal. This does make it
1359
/// somewhat slower than [`Mesh::compute_area_weighted_normals`] which does not need to
1360
/// greedily normalize each triangle's normal or calculate corner angles.
1361
///
1362
/// If you would rather have the computed normals be weighted by triangle area, see
1363
/// [`Mesh::compute_area_weighted_normals`] instead. If you need to weight them in some other
1364
/// way, see [`Mesh::compute_custom_smooth_normals`].
1365
///
1366
/// # Panics
1367
/// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1368
/// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1369
/// Panics if the mesh does not have indices defined.
1370
pub fn try_compute_smooth_normals(&mut self) -> Result<(), MeshAccessError> {
1371
self.try_compute_custom_smooth_normals(|[a, b, c], positions, normals| {
1372
let pa = Vec3::from(positions[a]);
1373
let pb = Vec3::from(positions[b]);
1374
let pc = Vec3::from(positions[c]);
1375
1376
let ab = pb - pa;
1377
let ba = pa - pb;
1378
let bc = pc - pb;
1379
let cb = pb - pc;
1380
let ca = pa - pc;
1381
let ac = pc - pa;
1382
1383
const EPS: f32 = f32::EPSILON;
1384
let weight_a = if ab.length_squared() * ac.length_squared() > EPS {
1385
ab.angle_between(ac)
1386
} else {
1387
0.0
1388
};
1389
let weight_b = if ba.length_squared() * bc.length_squared() > EPS {
1390
ba.angle_between(bc)
1391
} else {
1392
0.0
1393
};
1394
let weight_c = if ca.length_squared() * cb.length_squared() > EPS {
1395
ca.angle_between(cb)
1396
} else {
1397
0.0
1398
};
1399
1400
let normal = Vec3::from(triangle_normal(positions[a], positions[b], positions[c]));
1401
1402
normals[a] += normal * weight_a;
1403
normals[b] += normal * weight_b;
1404
normals[c] += normal * weight_c;
1405
})
1406
}
1407
1408
/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of an indexed mesh, smoothing normals for shared
1409
/// vertices.
1410
///
1411
/// This method weights normals by the area of each triangle containing the vertex. Thus,
1412
/// larger triangles will skew the normals of their vertices towards their own normal more
1413
/// than smaller triangles will.
1414
///
1415
/// This method is actually somewhat faster than [`Mesh::compute_smooth_normals`] because an
1416
/// intermediate result of triangle normal calculation is already scaled by the triangle's area.
1417
///
1418
/// If you would rather have the computed normals be influenced only by the angles of connected
1419
/// edges, see [`Mesh::compute_smooth_normals`] instead. If you need to weight them in some
1420
/// other way, see [`Mesh::compute_custom_smooth_normals`].
1421
///
1422
/// # Panics
1423
/// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1424
/// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1425
/// Panics if the mesh does not have indices defined.
1426
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1427
/// this as an error use [`Mesh::try_compute_area_weighted_normals`]
1428
pub fn compute_area_weighted_normals(&mut self) {
1429
self.try_compute_area_weighted_normals()
1430
.expect(MESH_EXTRACTED_ERROR);
1431
}
1432
1433
/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of an indexed mesh, smoothing normals for shared
1434
/// vertices.
1435
///
1436
/// This method weights normals by the area of each triangle containing the vertex. Thus,
1437
/// larger triangles will skew the normals of their vertices towards their own normal more
1438
/// than smaller triangles will.
1439
///
1440
/// This method is actually somewhat faster than [`Mesh::compute_smooth_normals`] because an
1441
/// intermediate result of triangle normal calculation is already scaled by the triangle's area.
1442
///
1443
/// If you would rather have the computed normals be influenced only by the angles of connected
1444
/// edges, see [`Mesh::compute_smooth_normals`] instead. If you need to weight them in some
1445
/// other way, see [`Mesh::compute_custom_smooth_normals`].
1446
///
1447
/// # Panics
1448
/// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1449
/// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1450
/// Panics if the mesh does not have indices defined.
1451
pub fn try_compute_area_weighted_normals(&mut self) -> Result<(), MeshAccessError> {
1452
self.try_compute_custom_smooth_normals(|[a, b, c], positions, normals| {
1453
let normal = Vec3::from(triangle_area_normal(
1454
positions[a],
1455
positions[b],
1456
positions[c],
1457
));
1458
[a, b, c].into_iter().for_each(|pos| {
1459
normals[pos] += normal;
1460
});
1461
})
1462
}
1463
1464
/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of an indexed mesh, smoothing normals for shared
1465
/// vertices.
1466
///
1467
/// This method allows you to customize how normals are weighted via the `per_triangle` parameter,
1468
/// which must be a function or closure that accepts 3 parameters:
1469
/// - The indices of the three vertices of the triangle as a `[usize; 3]`.
1470
/// - A reference to the values of the [`Mesh::ATTRIBUTE_POSITION`] of the mesh (`&[[f32; 3]]`).
1471
/// - A mutable reference to the sums of all normals so far.
1472
///
1473
/// See also the standard methods included in Bevy for calculating smooth normals:
1474
/// - [`Mesh::compute_smooth_normals`]
1475
/// - [`Mesh::compute_area_weighted_normals`]
1476
///
1477
/// An example that would weight each connected triangle's normal equally, thus skewing normals
1478
/// towards the planes divided into the most triangles:
1479
/// ```
1480
/// # use bevy_asset::RenderAssetUsages;
1481
/// # use bevy_mesh::{Mesh, PrimitiveTopology, Meshable, MeshBuilder};
1482
/// # use bevy_math::{Vec3, primitives::Cuboid};
1483
/// # let mut mesh = Cuboid::default().mesh().build();
1484
/// mesh.compute_custom_smooth_normals(|[a, b, c], positions, normals| {
1485
/// let normal = Vec3::from(bevy_mesh::triangle_normal(positions[a], positions[b], positions[c]));
1486
/// for idx in [a, b, c] {
1487
/// normals[idx] += normal;
1488
/// }
1489
/// });
1490
/// ```
1491
///
1492
/// # Panics
1493
/// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1494
/// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1495
/// Panics if the mesh does not have indices defined.
1496
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1497
/// this as an error use [`Mesh::try_compute_custom_smooth_normals`]
1498
//
1499
// FIXME: This should handle more cases since this is called as a part of gltf
1500
// mesh loading where we can't really blame users for loading meshes that might
1501
// not conform to the limitations here!
1502
//
1503
// When fixed, also update "Panics" sections of
1504
// - [Mesh::compute_smooth_normals]
1505
// - [Mesh::with_computed_smooth_normals]
1506
// - [Mesh::compute_area_weighted_normals]
1507
// - [Mesh::with_computed_area_weighted_normals]
1508
pub fn compute_custom_smooth_normals(
1509
&mut self,
1510
per_triangle: impl FnMut([usize; 3], &[[f32; 3]], &mut [Vec3]),
1511
) {
1512
self.try_compute_custom_smooth_normals(per_triangle)
1513
.expect(MESH_EXTRACTED_ERROR);
1514
}
1515
1516
/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of an indexed mesh, smoothing normals for shared
1517
/// vertices.
1518
///
1519
/// This method allows you to customize how normals are weighted via the `per_triangle` parameter,
1520
/// which must be a function or closure that accepts 3 parameters:
1521
/// - The indices of the three vertices of the triangle as a `[usize; 3]`.
1522
/// - A reference to the values of the [`Mesh::ATTRIBUTE_POSITION`] of the mesh (`&[[f32; 3]]`).
1523
/// - A mutable reference to the sums of all normals so far.
1524
///
1525
/// See also the standard methods included in Bevy for calculating smooth normals:
1526
/// - [`Mesh::compute_smooth_normals`]
1527
/// - [`Mesh::compute_area_weighted_normals`]
1528
///
1529
/// An example that would weight each connected triangle's normal equally, thus skewing normals
1530
/// towards the planes divided into the most triangles:
1531
/// ```
1532
/// # use bevy_asset::RenderAssetUsages;
1533
/// # use bevy_mesh::{Mesh, PrimitiveTopology, Meshable, MeshBuilder};
1534
/// # use bevy_math::{Vec3, primitives::Cuboid};
1535
/// # let mut mesh = Cuboid::default().mesh().build();
1536
/// mesh.compute_custom_smooth_normals(|[a, b, c], positions, normals| {
1537
/// let normal = Vec3::from(bevy_mesh::triangle_normal(positions[a], positions[b], positions[c]));
1538
/// for idx in [a, b, c] {
1539
/// normals[idx] += normal;
1540
/// }
1541
/// });
1542
/// ```
1543
///
1544
/// # Panics
1545
/// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1546
/// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1547
/// Panics if the mesh does not have indices defined.
1548
//
1549
// FIXME: This should handle more cases since this is called as a part of gltf
1550
// mesh loading where we can't really blame users for loading meshes that might
1551
// not conform to the limitations here!
1552
//
1553
// When fixed, also update "Panics" sections of
1554
// - [Mesh::compute_smooth_normals]
1555
// - [Mesh::with_computed_smooth_normals]
1556
// - [Mesh::compute_area_weighted_normals]
1557
// - [Mesh::with_computed_area_weighted_normals]
1558
pub fn try_compute_custom_smooth_normals(
1559
&mut self,
1560
mut per_triangle: impl FnMut([usize; 3], &[[f32; 3]], &mut [Vec3]),
1561
) -> Result<(), MeshAccessError> {
1562
assert!(
1563
matches!(self.primitive_topology, PrimitiveTopology::TriangleList),
1564
"smooth normals can only be computed on `TriangleList`s"
1565
);
1566
assert!(
1567
self.try_indices_option()?.is_some(),
1568
"smooth normals can only be computed on indexed meshes"
1569
);
1570
1571
let positions = self
1572
.try_attribute(Mesh::ATTRIBUTE_POSITION)?
1573
.as_float3()
1574
.expect("`Mesh::ATTRIBUTE_POSITION` vertex attributes should be of type `float3`");
1575
1576
let mut normals = vec![Vec3::ZERO; positions.len()];
1577
1578
self.try_indices()?
1579
.iter()
1580
.collect::<Vec<usize>>()
1581
.chunks_exact(3)
1582
.for_each(|face| per_triangle([face[0], face[1], face[2]], positions, &mut normals));
1583
1584
for normal in &mut normals {
1585
*normal = normal.try_normalize().unwrap_or(Vec3::ZERO);
1586
}
1587
1588
self.try_insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals)
1589
}
1590
1591
/// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
1592
/// If the mesh is indexed, this defaults to smooth normals. Otherwise, it defaults to flat
1593
/// normals.
1594
///
1595
/// (Alternatively, you can use [`Mesh::compute_normals`] to mutate an existing mesh in-place)
1596
///
1597
/// # Panics
1598
/// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1599
/// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1600
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1601
/// this as an error use [`Mesh::try_with_computed_normals`]
1602
#[must_use]
1603
pub fn with_computed_normals(self) -> Self {
1604
self.try_with_computed_normals()
1605
.expect(MESH_EXTRACTED_ERROR)
1606
}
1607
1608
/// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
1609
/// If the mesh is indexed, this defaults to smooth normals. Otherwise, it defaults to flat
1610
/// normals.
1611
///
1612
/// (Alternatively, you can use [`Mesh::compute_normals`] to mutate an existing mesh in-place)
1613
///
1614
/// # Panics
1615
/// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1616
/// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1617
pub fn try_with_computed_normals(mut self) -> Result<Self, MeshAccessError> {
1618
self.try_compute_normals()?;
1619
Ok(self)
1620
}
1621
1622
/// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
1623
///
1624
/// (Alternatively, you can use [`Mesh::compute_flat_normals`] to mutate an existing mesh in-place)
1625
///
1626
/// # Panics
1627
/// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1628
/// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1629
/// Panics if the mesh has indices defined
1630
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1631
/// this as an error use [`Mesh::try_with_computed_flat_normals`]
1632
pub fn with_computed_flat_normals(mut self) -> Self {
1633
self.compute_flat_normals();
1634
self
1635
}
1636
1637
/// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
1638
///
1639
/// (Alternatively, you can use [`Mesh::compute_flat_normals`] to mutate an existing mesh in-place)
1640
///
1641
/// # Panics
1642
/// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1643
/// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1644
/// Panics if the mesh has indices defined
1645
pub fn try_with_computed_flat_normals(mut self) -> Result<Self, MeshAccessError> {
1646
self.try_compute_flat_normals()?;
1647
Ok(self)
1648
}
1649
1650
/// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
1651
///
1652
/// (Alternatively, you can use [`Mesh::compute_smooth_normals`] to mutate an existing mesh in-place)
1653
///
1654
/// This method weights normals by the angles of triangle corners connected to each vertex. If
1655
/// you would rather have the computed normals be weighted by triangle area, see
1656
/// [`Mesh::with_computed_area_weighted_normals`] instead.
1657
///
1658
/// # Panics
1659
/// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1660
/// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1661
/// Panics if the mesh does not have indices defined.
1662
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1663
/// this as an error use [`Mesh::try_with_computed_smooth_normals`]
1664
pub fn with_computed_smooth_normals(mut self) -> Self {
1665
self.compute_smooth_normals();
1666
self
1667
}
1668
/// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
1669
///
1670
/// (Alternatively, you can use [`Mesh::compute_smooth_normals`] to mutate an existing mesh in-place)
1671
///
1672
/// This method weights normals by the angles of triangle corners connected to each vertex. If
1673
/// you would rather have the computed normals be weighted by triangle area, see
1674
/// [`Mesh::with_computed_area_weighted_normals`] instead.
1675
///
1676
/// # Panics
1677
/// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1678
/// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1679
/// Panics if the mesh does not have indices defined.
1680
pub fn try_with_computed_smooth_normals(mut self) -> Result<Self, MeshAccessError> {
1681
self.try_compute_smooth_normals()?;
1682
Ok(self)
1683
}
1684
1685
/// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
1686
///
1687
/// (Alternatively, you can use [`Mesh::compute_area_weighted_normals`] to mutate an existing mesh in-place)
1688
///
1689
/// This method weights normals by the area of each triangle containing the vertex. Thus,
1690
/// larger triangles will skew the normals of their vertices towards their own normal more
1691
/// than smaller triangles will. If you would rather have the computed normals be influenced
1692
/// only by the angles of connected edges, see [`Mesh::with_computed_smooth_normals`] instead.
1693
///
1694
/// # Panics
1695
/// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1696
/// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1697
/// Panics if the mesh does not have indices defined.
1698
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1699
/// this as an error use [`Mesh::try_with_computed_area_weighted_normals`]
1700
pub fn with_computed_area_weighted_normals(mut self) -> Self {
1701
self.compute_area_weighted_normals();
1702
self
1703
}
1704
1705
/// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
1706
///
1707
/// (Alternatively, you can use [`Mesh::compute_area_weighted_normals`] to mutate an existing mesh in-place)
1708
///
1709
/// This method weights normals by the area of each triangle containing the vertex. Thus,
1710
/// larger triangles will skew the normals of their vertices towards their own normal more
1711
/// than smaller triangles will. If you would rather have the computed normals be influenced
1712
/// only by the angles of connected edges, see [`Mesh::with_computed_smooth_normals`] instead.
1713
///
1714
/// # Panics
1715
/// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1716
/// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1717
/// Panics if the mesh does not have indices defined.
1718
pub fn try_with_computed_area_weighted_normals(mut self) -> Result<Self, MeshAccessError> {
1719
self.try_compute_area_weighted_normals()?;
1720
Ok(self)
1721
}
1722
1723
/// Generate tangents for the mesh using the `mikktspace` algorithm.
1724
///
1725
/// Sets the [`Mesh::ATTRIBUTE_TANGENT`] attribute if successful.
1726
/// Requires a [`PrimitiveTopology::TriangleList`] topology and the [`Mesh::ATTRIBUTE_POSITION`], [`Mesh::ATTRIBUTE_NORMAL`] and [`Mesh::ATTRIBUTE_UV_0`] attributes set.
1727
#[cfg(feature = "bevy_mikktspace")]
1728
pub fn generate_tangents(&mut self) -> Result<(), super::GenerateTangentsError> {
1729
let tangents = super::generate_tangents_for_mesh(self)?;
1730
self.try_insert_attribute(Mesh::ATTRIBUTE_TANGENT, tangents)?;
1731
Ok(())
1732
}
1733
1734
/// Consumes the mesh and returns a mesh with tangents generated using the `mikktspace` algorithm.
1735
///
1736
/// The resulting mesh will have the [`Mesh::ATTRIBUTE_TANGENT`] attribute if successful.
1737
///
1738
/// (Alternatively, you can use [`Mesh::generate_tangents`] to mutate an existing mesh in-place)
1739
///
1740
/// Requires a [`PrimitiveTopology::TriangleList`] topology and the [`Mesh::ATTRIBUTE_POSITION`], [`Mesh::ATTRIBUTE_NORMAL`] and [`Mesh::ATTRIBUTE_UV_0`] attributes set.
1741
#[cfg(feature = "bevy_mikktspace")]
1742
pub fn with_generated_tangents(mut self) -> Result<Mesh, super::GenerateTangentsError> {
1743
self.generate_tangents()?;
1744
Ok(self)
1745
}
1746
1747
/// Merges the [`Mesh`] data of `other` with `self`. The attributes and indices of `other` will be appended to `self`.
1748
///
1749
/// Note that attributes of `other` that don't exist on `self` will be ignored.
1750
///
1751
/// `Aabb` of entities with modified mesh are not updated automatically.
1752
///
1753
/// # Errors
1754
///
1755
/// If any of the following conditions are not met, this function errors:
1756
/// * All of the vertex attributes that have the same attribute id, must also
1757
/// have the same attribute type.
1758
/// For example two attributes with the same id, but where one is a
1759
/// [`VertexAttributeValues::Float32`] and the other is a
1760
/// [`VertexAttributeValues::Float32x3`], would be invalid.
1761
/// * Both meshes must have the same primitive topology.
1762
pub fn merge(&mut self, other: &Mesh) -> Result<(), MeshMergeError> {
1763
use VertexAttributeValues::*;
1764
1765
// Check if the meshes `primitive_topology` field is the same,
1766
// as if that is not the case, the resulting mesh could (and most likely would)
1767
// be invalid.
1768
if self.primitive_topology != other.primitive_topology {
1769
return Err(MeshMergeError::IncompatiblePrimitiveTopology {
1770
self_primitive_topology: self.primitive_topology,
1771
other_primitive_topology: other.primitive_topology,
1772
});
1773
}
1774
1775
// The indices of `other` should start after the last vertex of `self`.
1776
let index_offset = self.count_vertices();
1777
1778
// Extend attributes of `self` with attributes of `other`.
1779
for (attribute, values) in self.try_attributes_mut()? {
1780
if let Some(other_values) = other.try_attribute_option(attribute.id)? {
1781
#[expect(
1782
clippy::match_same_arms,
1783
reason = "Although the bindings on some match arms may have different types, each variant has different semantics; thus it's not guaranteed that they will use the same type forever."
1784
)]
1785
match (values, other_values) {
1786
(Float32(vec1), Float32(vec2)) => vec1.extend(vec2),
1787
(Sint32(vec1), Sint32(vec2)) => vec1.extend(vec2),
1788
(Uint32(vec1), Uint32(vec2)) => vec1.extend(vec2),
1789
(Float32x2(vec1), Float32x2(vec2)) => vec1.extend(vec2),
1790
(Sint32x2(vec1), Sint32x2(vec2)) => vec1.extend(vec2),
1791
(Uint32x2(vec1), Uint32x2(vec2)) => vec1.extend(vec2),
1792
(Float32x3(vec1), Float32x3(vec2)) => vec1.extend(vec2),
1793
(Sint32x3(vec1), Sint32x3(vec2)) => vec1.extend(vec2),
1794
(Uint32x3(vec1), Uint32x3(vec2)) => vec1.extend(vec2),
1795
(Sint32x4(vec1), Sint32x4(vec2)) => vec1.extend(vec2),
1796
(Uint32x4(vec1), Uint32x4(vec2)) => vec1.extend(vec2),
1797
(Float32x4(vec1), Float32x4(vec2)) => vec1.extend(vec2),
1798
(Sint16x2(vec1), Sint16x2(vec2)) => vec1.extend(vec2),
1799
(Snorm16x2(vec1), Snorm16x2(vec2)) => vec1.extend(vec2),
1800
(Uint16x2(vec1), Uint16x2(vec2)) => vec1.extend(vec2),
1801
(Unorm16x2(vec1), Unorm16x2(vec2)) => vec1.extend(vec2),
1802
(Sint16x4(vec1), Sint16x4(vec2)) => vec1.extend(vec2),
1803
(Snorm16x4(vec1), Snorm16x4(vec2)) => vec1.extend(vec2),
1804
(Uint16x4(vec1), Uint16x4(vec2)) => vec1.extend(vec2),
1805
(Unorm16x4(vec1), Unorm16x4(vec2)) => vec1.extend(vec2),
1806
(Sint8x2(vec1), Sint8x2(vec2)) => vec1.extend(vec2),
1807
(Snorm8x2(vec1), Snorm8x2(vec2)) => vec1.extend(vec2),
1808
(Uint8x2(vec1), Uint8x2(vec2)) => vec1.extend(vec2),
1809
(Unorm8x2(vec1), Unorm8x2(vec2)) => vec1.extend(vec2),
1810
(Sint8x4(vec1), Sint8x4(vec2)) => vec1.extend(vec2),
1811
(Snorm8x4(vec1), Snorm8x4(vec2)) => vec1.extend(vec2),
1812
(Uint8x4(vec1), Uint8x4(vec2)) => vec1.extend(vec2),
1813
(Unorm8x4(vec1), Unorm8x4(vec2)) => vec1.extend(vec2),
1814
_ => {
1815
return Err(MeshMergeError::IncompatibleVertexAttributes {
1816
self_attribute: *attribute,
1817
other_attribute: other
1818
.try_attribute_data(attribute.id)?
1819
.map(|data| data.attribute),
1820
})
1821
}
1822
}
1823
}
1824
}
1825
1826
// Extend indices of `self` with indices of `other`.
1827
if let (Some(indices), Some(other_indices)) =
1828
(self.try_indices_mut_option()?, other.try_indices_option()?)
1829
{
1830
indices.extend(other_indices.iter().map(|i| (i + index_offset) as u32));
1831
}
1832
Ok(())
1833
}
1834
1835
/// Transforms the vertex positions, normals, and tangents of the mesh by the given [`Transform`].
1836
///
1837
/// `Aabb` of entities with modified mesh are not updated automatically.
1838
///
1839
/// # Panics
1840
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1841
/// this as an error use [`Mesh::try_transformed_by`]
1842
pub fn transformed_by(mut self, transform: Transform) -> Self {
1843
self.transform_by(transform);
1844
self
1845
}
1846
1847
/// Transforms the vertex positions, normals, and tangents of the mesh by the given [`Transform`].
1848
///
1849
/// `Aabb` of entities with modified mesh are not updated automatically.
1850
pub fn try_transformed_by(mut self, transform: Transform) -> Result<Self, MeshAccessError> {
1851
self.try_transform_by(transform)?;
1852
Ok(self)
1853
}
1854
1855
/// Transforms the vertex positions, normals, and tangents of the mesh in place by the given [`Transform`].
1856
///
1857
/// `Aabb` of entities with modified mesh are not updated automatically.
1858
///
1859
/// # Panics
1860
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1861
/// this as an error use [`Mesh::try_transform_by`]
1862
pub fn transform_by(&mut self, transform: Transform) {
1863
self.try_transform_by(transform)
1864
.expect(MESH_EXTRACTED_ERROR);
1865
}
1866
1867
/// Transforms the vertex positions, normals, and tangents of the mesh in place by the given [`Transform`].
1868
///
1869
/// `Aabb` of entities with modified mesh are not updated automatically.
1870
pub fn try_transform_by(&mut self, transform: Transform) -> Result<(), MeshAccessError> {
1871
// Needed when transforming normals and tangents
1872
let scale_recip = 1. / transform.scale;
1873
debug_assert!(
1874
transform.scale.yzx() * transform.scale.zxy() != Vec3::ZERO,
1875
"mesh transform scale cannot be zero on more than one axis"
1876
);
1877
1878
if let Some(VertexAttributeValues::Float32x3(positions)) =
1879
self.try_attribute_mut_option(Mesh::ATTRIBUTE_POSITION)?
1880
{
1881
// Apply scale, rotation, and translation to vertex positions
1882
positions
1883
.iter_mut()
1884
.for_each(|pos| *pos = transform.transform_point(Vec3::from_slice(pos)).to_array());
1885
}
1886
1887
// No need to transform normals or tangents if rotation is near identity and scale is uniform
1888
if transform.rotation.is_near_identity()
1889
&& transform.scale.x == transform.scale.y
1890
&& transform.scale.y == transform.scale.z
1891
{
1892
return Ok(());
1893
}
1894
1895
if let Some(VertexAttributeValues::Float32x3(normals)) =
1896
self.try_attribute_mut_option(Mesh::ATTRIBUTE_NORMAL)?
1897
{
1898
// Transform normals, taking into account non-uniform scaling and rotation
1899
normals.iter_mut().for_each(|normal| {
1900
*normal = (transform.rotation
1901
* scale_normal(Vec3::from_array(*normal), scale_recip))
1902
.to_array();
1903
});
1904
}
1905
1906
if let Some(VertexAttributeValues::Float32x4(tangents)) =
1907
self.try_attribute_mut_option(Mesh::ATTRIBUTE_TANGENT)?
1908
{
1909
// Transform tangents, taking into account non-uniform scaling and rotation
1910
tangents.iter_mut().for_each(|tangent| {
1911
let handedness = tangent[3];
1912
let scaled_tangent = Vec3::from_slice(tangent) * transform.scale;
1913
*tangent = (transform.rotation * scaled_tangent.normalize_or_zero())
1914
.extend(handedness)
1915
.to_array();
1916
});
1917
}
1918
1919
Ok(())
1920
}
1921
1922
/// Translates the vertex positions of the mesh by the given [`Vec3`].
1923
///
1924
/// `Aabb` of entities with modified mesh are not updated automatically.
1925
///
1926
/// # Panics
1927
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1928
/// this as an error use [`Mesh::try_translated_by`]
1929
pub fn translated_by(mut self, translation: Vec3) -> Self {
1930
self.translate_by(translation);
1931
self
1932
}
1933
1934
/// Translates the vertex positions of the mesh by the given [`Vec3`].
1935
///
1936
/// `Aabb` of entities with modified mesh are not updated automatically.
1937
pub fn try_translated_by(mut self, translation: Vec3) -> Result<Self, MeshAccessError> {
1938
self.try_translate_by(translation)?;
1939
Ok(self)
1940
}
1941
1942
/// Translates the vertex positions of the mesh in place by the given [`Vec3`].
1943
///
1944
/// `Aabb` of entities with modified mesh are not updated automatically.
1945
///
1946
/// # Panics
1947
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1948
/// this as an error use [`Mesh::try_translate_by`]
1949
pub fn translate_by(&mut self, translation: Vec3) {
1950
self.try_translate_by(translation)
1951
.expect(MESH_EXTRACTED_ERROR);
1952
}
1953
1954
/// Translates the vertex positions of the mesh in place by the given [`Vec3`].
1955
///
1956
/// `Aabb` of entities with modified mesh are not updated automatically.
1957
pub fn try_translate_by(&mut self, translation: Vec3) -> Result<(), MeshAccessError> {
1958
if translation == Vec3::ZERO {
1959
return Ok(());
1960
}
1961
1962
if let Some(VertexAttributeValues::Float32x3(positions)) =
1963
self.try_attribute_mut_option(Mesh::ATTRIBUTE_POSITION)?
1964
{
1965
// Apply translation to vertex positions
1966
positions
1967
.iter_mut()
1968
.for_each(|pos| *pos = (Vec3::from_slice(pos) + translation).to_array());
1969
}
1970
1971
Ok(())
1972
}
1973
1974
/// Rotates the vertex positions, normals, and tangents of the mesh by the given [`Quat`].
1975
///
1976
/// `Aabb` of entities with modified mesh are not updated automatically.
1977
///
1978
/// # Panics
1979
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1980
/// this as an error use [`Mesh::try_rotated_by`]
1981
pub fn rotated_by(mut self, rotation: Quat) -> Self {
1982
self.try_rotate_by(rotation).expect(MESH_EXTRACTED_ERROR);
1983
self
1984
}
1985
1986
/// Rotates the vertex positions, normals, and tangents of the mesh by the given [`Quat`].
1987
///
1988
/// `Aabb` of entities with modified mesh are not updated automatically.
1989
pub fn try_rotated_by(mut self, rotation: Quat) -> Result<Self, MeshAccessError> {
1990
self.try_rotate_by(rotation)?;
1991
Ok(self)
1992
}
1993
1994
/// Rotates the vertex positions, normals, and tangents of the mesh in place by the given [`Quat`].
1995
///
1996
/// `Aabb` of entities with modified mesh are not updated automatically.
1997
///
1998
/// # Panics
1999
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2000
/// this as an error use [`Mesh::try_rotate_by`]
2001
pub fn rotate_by(&mut self, rotation: Quat) {
2002
self.try_rotate_by(rotation).expect(MESH_EXTRACTED_ERROR);
2003
}
2004
2005
/// Rotates the vertex positions, normals, and tangents of the mesh in place by the given [`Quat`].
2006
///
2007
/// `Aabb` of entities with modified mesh are not updated automatically.
2008
pub fn try_rotate_by(&mut self, rotation: Quat) -> Result<(), MeshAccessError> {
2009
if let Some(VertexAttributeValues::Float32x3(positions)) =
2010
self.try_attribute_mut_option(Mesh::ATTRIBUTE_POSITION)?
2011
{
2012
// Apply rotation to vertex positions
2013
positions
2014
.iter_mut()
2015
.for_each(|pos| *pos = (rotation * Vec3::from_slice(pos)).to_array());
2016
}
2017
2018
// No need to transform normals or tangents if rotation is near identity
2019
if rotation.is_near_identity() {
2020
return Ok(());
2021
}
2022
2023
if let Some(VertexAttributeValues::Float32x3(normals)) =
2024
self.try_attribute_mut_option(Mesh::ATTRIBUTE_NORMAL)?
2025
{
2026
// Transform normals
2027
normals.iter_mut().for_each(|normal| {
2028
*normal = (rotation * Vec3::from_slice(normal).normalize_or_zero()).to_array();
2029
});
2030
}
2031
2032
if let Some(VertexAttributeValues::Float32x4(tangents)) =
2033
self.try_attribute_mut_option(Mesh::ATTRIBUTE_TANGENT)?
2034
{
2035
// Transform tangents
2036
tangents.iter_mut().for_each(|tangent| {
2037
let handedness = tangent[3];
2038
*tangent = (rotation * Vec3::from_slice(tangent).normalize_or_zero())
2039
.extend(handedness)
2040
.to_array();
2041
});
2042
}
2043
2044
Ok(())
2045
}
2046
2047
/// Scales the vertex positions, normals, and tangents of the mesh by the given [`Vec3`].
2048
///
2049
/// `Aabb` of entities with modified mesh are not updated automatically.
2050
///
2051
/// # Panics
2052
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2053
/// this as an error use [`Mesh::try_scaled_by`]
2054
pub fn scaled_by(mut self, scale: Vec3) -> Self {
2055
self.scale_by(scale);
2056
self
2057
}
2058
2059
/// Scales the vertex positions, normals, and tangents of the mesh by the given [`Vec3`].
2060
///
2061
/// `Aabb` of entities with modified mesh are not updated automatically.
2062
pub fn try_scaled_by(mut self, scale: Vec3) -> Result<Self, MeshAccessError> {
2063
self.try_scale_by(scale)?;
2064
Ok(self)
2065
}
2066
2067
/// Scales the vertex positions, normals, and tangents of the mesh in place by the given [`Vec3`].
2068
///
2069
/// `Aabb` of entities with modified mesh are not updated automatically.
2070
///
2071
/// # Panics
2072
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2073
/// this as an error use [`Mesh::try_scale_by`]
2074
pub fn scale_by(&mut self, scale: Vec3) {
2075
self.try_scale_by(scale).expect(MESH_EXTRACTED_ERROR);
2076
}
2077
2078
/// Scales the vertex positions, normals, and tangents of the mesh in place by the given [`Vec3`].
2079
///
2080
/// `Aabb` of entities with modified mesh are not updated automatically.
2081
pub fn try_scale_by(&mut self, scale: Vec3) -> Result<(), MeshAccessError> {
2082
// Needed when transforming normals and tangents
2083
let scale_recip = 1. / scale;
2084
debug_assert!(
2085
scale.yzx() * scale.zxy() != Vec3::ZERO,
2086
"mesh transform scale cannot be zero on more than one axis"
2087
);
2088
2089
if let Some(VertexAttributeValues::Float32x3(positions)) =
2090
self.try_attribute_mut_option(Mesh::ATTRIBUTE_POSITION)?
2091
{
2092
// Apply scale to vertex positions
2093
positions
2094
.iter_mut()
2095
.for_each(|pos| *pos = (scale * Vec3::from_slice(pos)).to_array());
2096
}
2097
2098
// No need to transform normals or tangents if scale is uniform
2099
if scale.x == scale.y && scale.y == scale.z {
2100
return Ok(());
2101
}
2102
2103
if let Some(VertexAttributeValues::Float32x3(normals)) =
2104
self.try_attribute_mut_option(Mesh::ATTRIBUTE_NORMAL)?
2105
{
2106
// Transform normals, taking into account non-uniform scaling
2107
normals.iter_mut().for_each(|normal| {
2108
*normal = scale_normal(Vec3::from_array(*normal), scale_recip).to_array();
2109
});
2110
}
2111
2112
if let Some(VertexAttributeValues::Float32x4(tangents)) =
2113
self.try_attribute_mut_option(Mesh::ATTRIBUTE_TANGENT)?
2114
{
2115
// Transform tangents, taking into account non-uniform scaling
2116
tangents.iter_mut().for_each(|tangent| {
2117
let handedness = tangent[3];
2118
let scaled_tangent = Vec3::from_slice(tangent) * scale;
2119
*tangent = scaled_tangent
2120
.normalize_or_zero()
2121
.extend(handedness)
2122
.to_array();
2123
});
2124
}
2125
2126
Ok(())
2127
}
2128
2129
/// Normalize joint weights so they sum to 1.
2130
///
2131
/// # Panics
2132
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2133
/// this as an error use [`Mesh::try_normalize_joint_weights`]
2134
pub fn normalize_joint_weights(&mut self) {
2135
self.try_normalize_joint_weights()
2136
.expect(MESH_EXTRACTED_ERROR);
2137
}
2138
2139
/// Normalize joint weights so they sum to 1.
2140
pub fn try_normalize_joint_weights(&mut self) -> Result<(), MeshAccessError> {
2141
if let Some(VertexAttributeValues::Float32x4(joints)) =
2142
self.try_attribute_mut_option(Self::ATTRIBUTE_JOINT_WEIGHT)?
2143
{
2144
for weights in joints.iter_mut() {
2145
// force negative weights to zero
2146
weights.iter_mut().for_each(|w| *w = w.max(0.0));
2147
2148
let sum: f32 = weights.iter().sum();
2149
if sum == 0.0 {
2150
// all-zero weights are invalid
2151
weights[0] = 1.0;
2152
} else {
2153
let recip = sum.recip();
2154
for weight in weights.iter_mut() {
2155
*weight *= recip;
2156
}
2157
}
2158
}
2159
}
2160
2161
Ok(())
2162
}
2163
2164
/// Get a list of this Mesh's [triangles] as an iterator if possible.
2165
///
2166
/// Returns an error if any of the following conditions are met (see [`MeshTrianglesError`]):
2167
/// * The Mesh's [primitive topology] is not `TriangleList` or `TriangleStrip`.
2168
/// * The Mesh is missing position or index data.
2169
/// * The Mesh's position data has the wrong format (not `Float32x3`).
2170
///
2171
/// [primitive topology]: PrimitiveTopology
2172
/// [triangles]: Triangle3d
2173
pub fn triangles(&self) -> Result<impl Iterator<Item = Triangle3d> + '_, MeshTrianglesError> {
2174
let position_data = self.try_attribute(Mesh::ATTRIBUTE_POSITION)?;
2175
2176
let Some(vertices) = position_data.as_float3() else {
2177
return Err(MeshTrianglesError::PositionsFormat);
2178
};
2179
2180
let indices = self.try_indices()?;
2181
2182
match self.primitive_topology {
2183
PrimitiveTopology::TriangleList => {
2184
// When indices reference out-of-bounds vertex data, the triangle is omitted.
2185
// This implicitly truncates the indices to a multiple of 3.
2186
let iterator = match indices {
2187
Indices::U16(vec) => FourIterators::First(
2188
vec.as_slice()
2189
.chunks_exact(3)
2190
.flat_map(move |indices| indices_to_triangle(vertices, indices)),
2191
),
2192
Indices::U32(vec) => FourIterators::Second(
2193
vec.as_slice()
2194
.chunks_exact(3)
2195
.flat_map(move |indices| indices_to_triangle(vertices, indices)),
2196
),
2197
};
2198
2199
return Ok(iterator);
2200
}
2201
2202
PrimitiveTopology::TriangleStrip => {
2203
// When indices reference out-of-bounds vertex data, the triangle is omitted.
2204
// If there aren't enough indices to make a triangle, then an empty vector will be
2205
// returned.
2206
let iterator = match indices {
2207
Indices::U16(vec) => {
2208
FourIterators::Third(vec.as_slice().windows(3).enumerate().flat_map(
2209
move |(i, indices)| {
2210
if i % 2 == 0 {
2211
indices_to_triangle(vertices, indices)
2212
} else {
2213
indices_to_triangle(
2214
vertices,
2215
&[indices[1], indices[0], indices[2]],
2216
)
2217
}
2218
},
2219
))
2220
}
2221
Indices::U32(vec) => {
2222
FourIterators::Fourth(vec.as_slice().windows(3).enumerate().flat_map(
2223
move |(i, indices)| {
2224
if i % 2 == 0 {
2225
indices_to_triangle(vertices, indices)
2226
} else {
2227
indices_to_triangle(
2228
vertices,
2229
&[indices[1], indices[0], indices[2]],
2230
)
2231
}
2232
},
2233
))
2234
}
2235
};
2236
2237
return Ok(iterator);
2238
}
2239
2240
_ => {
2241
return Err(MeshTrianglesError::WrongTopology);
2242
}
2243
};
2244
2245
fn indices_to_triangle<T: TryInto<usize> + Copy>(
2246
vertices: &[[f32; 3]],
2247
indices: &[T],
2248
) -> Option<Triangle3d> {
2249
let vert0: Vec3 = Vec3::from(*vertices.get(indices[0].try_into().ok()?)?);
2250
let vert1: Vec3 = Vec3::from(*vertices.get(indices[1].try_into().ok()?)?);
2251
let vert2: Vec3 = Vec3::from(*vertices.get(indices[2].try_into().ok()?)?);
2252
Some(Triangle3d {
2253
vertices: [vert0, vert1, vert2],
2254
})
2255
}
2256
}
2257
2258
/// Extracts the mesh vertex, index and morph target data for GPU upload.
2259
/// This function is called internally in render world extraction, it is
2260
/// unlikely to be useful outside of that context.
2261
///
2262
/// Returns an error if the mesh data has been extracted to `RenderWorld`.
2263
pub fn take_gpu_data(&mut self) -> Result<Self, MeshAccessError> {
2264
let attributes = self.attributes.extract()?;
2265
let indices = self.indices.extract()?;
2266
#[cfg(feature = "morph")]
2267
let morph_targets = self.morph_targets.extract()?;
2268
#[cfg(feature = "morph")]
2269
let morph_target_names = self.morph_target_names.extract()?;
2270
2271
// store the aabb extents as they cannot be computed after extraction
2272
if let Some(MeshAttributeData {
2273
values: VertexAttributeValues::Float32x3(position_values),
2274
..
2275
}) = attributes
2276
.as_ref_option()?
2277
.and_then(|attrs| attrs.get(&Self::ATTRIBUTE_POSITION.id))
2278
&& !position_values.is_empty()
2279
{
2280
let mut iter = position_values.iter().map(|p| Vec3::from_slice(p));
2281
let mut min = iter.next().unwrap();
2282
let mut max = min;
2283
for v in iter {
2284
min = Vec3::min(min, v);
2285
max = Vec3::max(max, v);
2286
}
2287
self.final_aabb = Some(Aabb3d::from_min_max(min, max));
2288
}
2289
2290
Ok(Self {
2291
attributes,
2292
indices,
2293
#[cfg(feature = "morph")]
2294
morph_targets,
2295
#[cfg(feature = "morph")]
2296
morph_target_names,
2297
..self.clone()
2298
})
2299
}
2300
2301
/// Get this mesh's [`SkinnedMeshBounds`].
2302
pub fn skinned_mesh_bounds(&self) -> Option<&SkinnedMeshBounds> {
2303
self.skinned_mesh_bounds.as_ref()
2304
}
2305
2306
/// Set this mesh's [`SkinnedMeshBounds`].
2307
pub fn set_skinned_mesh_bounds(&mut self, skinned_mesh_bounds: Option<SkinnedMeshBounds>) {
2308
self.skinned_mesh_bounds = skinned_mesh_bounds;
2309
}
2310
2311
/// Consumes the mesh and returns a mesh with the given [`SkinnedMeshBounds`].
2312
pub fn with_skinned_mesh_bounds(
2313
mut self,
2314
skinned_mesh_bounds: Option<SkinnedMeshBounds>,
2315
) -> Self {
2316
self.set_skinned_mesh_bounds(skinned_mesh_bounds);
2317
self
2318
}
2319
2320
/// Generate [`SkinnedMeshBounds`] for this mesh.
2321
pub fn generate_skinned_mesh_bounds(&mut self) -> Result<(), SkinnedMeshBoundsError> {
2322
self.skinned_mesh_bounds = Some(SkinnedMeshBounds::from_mesh(self)?);
2323
Ok(())
2324
}
2325
2326
/// Consumes the mesh and returns a mesh with generated [`SkinnedMeshBounds`].
2327
pub fn with_generated_skinned_mesh_bounds(mut self) -> Result<Self, SkinnedMeshBoundsError> {
2328
self.generate_skinned_mesh_bounds()?;
2329
Ok(self)
2330
}
2331
}
2332
2333
#[cfg(feature = "morph")]
2334
impl Mesh {
2335
/// Whether this mesh has morph targets.
2336
///
2337
/// # Panics
2338
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2339
/// this as an error use [`Mesh::try_has_morph_targets`]
2340
pub fn has_morph_targets(&self) -> bool {
2341
self.try_has_morph_targets().expect(MESH_EXTRACTED_ERROR)
2342
}
2343
2344
/// Whether this mesh has morph targets.
2345
pub fn try_has_morph_targets(&self) -> Result<bool, MeshAccessError> {
2346
Ok(self.morph_targets.as_ref_option()?.is_some())
2347
}
2348
2349
/// Set [morph targets] image for this mesh. This requires a "morph target image". See [`MorphTargetImage`](crate::morph::MorphTargetImage) for info.
2350
///
2351
/// [morph targets]: https://en.wikipedia.org/wiki/Morph_target_animation
2352
///
2353
/// # Panics
2354
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2355
/// this as an error use [`Mesh::try_set_morph_targets`]
2356
pub fn set_morph_targets(&mut self, morph_targets: Handle<Image>) {
2357
self.try_set_morph_targets(morph_targets)
2358
.expect(MESH_EXTRACTED_ERROR);
2359
}
2360
2361
/// Set [morph targets] image for this mesh. This requires a "morph target image". See [`MorphTargetImage`](crate::morph::MorphTargetImage) for info.
2362
///
2363
/// [morph targets]: https://en.wikipedia.org/wiki/Morph_target_animation
2364
pub fn try_set_morph_targets(
2365
&mut self,
2366
morph_targets: Handle<Image>,
2367
) -> Result<(), MeshAccessError> {
2368
self.morph_targets.replace(Some(morph_targets))?;
2369
Ok(())
2370
}
2371
2372
/// Retrieve the morph targets for this mesh, or None if there are no morph targets.
2373
/// # Panics
2374
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2375
/// this as an error use [`Mesh::try_morph_targets`]
2376
pub fn morph_targets(&self) -> Option<&Handle<Image>> {
2377
self.morph_targets
2378
.as_ref_option()
2379
.expect(MESH_EXTRACTED_ERROR)
2380
}
2381
2382
/// Retrieve the morph targets for this mesh, or None if there are no morph targets.
2383
///
2384
/// Returns an error if the mesh data has been extracted to `RenderWorld`or
2385
/// if the morph targets do not exist.
2386
pub fn try_morph_targets(&self) -> Result<&Handle<Image>, MeshAccessError> {
2387
self.morph_targets.as_ref()
2388
}
2389
2390
/// Consumes the mesh and returns a mesh with the given [morph targets].
2391
///
2392
/// This requires a "morph target image". See [`MorphTargetImage`](crate::morph::MorphTargetImage) for info.
2393
///
2394
/// (Alternatively, you can use [`Mesh::set_morph_targets`] to mutate an existing mesh in-place)
2395
///
2396
/// [morph targets]: https://en.wikipedia.org/wiki/Morph_target_animation
2397
///
2398
/// # Panics
2399
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2400
/// this as an error use [`Mesh::try_with_morph_targets`]
2401
#[must_use]
2402
pub fn with_morph_targets(mut self, morph_targets: Handle<Image>) -> Self {
2403
self.set_morph_targets(morph_targets);
2404
self
2405
}
2406
2407
/// Consumes the mesh and returns a mesh with the given [morph targets].
2408
///
2409
/// This requires a "morph target image". See [`MorphTargetImage`](crate::morph::MorphTargetImage) for info.
2410
///
2411
/// (Alternatively, you can use [`Mesh::set_morph_targets`] to mutate an existing mesh in-place)
2412
///
2413
/// [morph targets]: https://en.wikipedia.org/wiki/Morph_target_animation
2414
///
2415
/// Returns an error if the mesh data has been extracted to `RenderWorld`.
2416
pub fn try_with_morph_targets(
2417
mut self,
2418
morph_targets: Handle<Image>,
2419
) -> Result<Self, MeshAccessError> {
2420
self.try_set_morph_targets(morph_targets)?;
2421
Ok(self)
2422
}
2423
2424
/// Sets the names of each morph target. This should correspond to the order of the morph targets in `set_morph_targets`.
2425
///
2426
/// # Panics
2427
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2428
/// this as an error use [`Mesh::try_set_morph_target_names`]
2429
pub fn set_morph_target_names(&mut self, names: Vec<String>) {
2430
self.try_set_morph_target_names(names)
2431
.expect(MESH_EXTRACTED_ERROR);
2432
}
2433
2434
/// Sets the names of each morph target. This should correspond to the order of the morph targets in `set_morph_targets`.
2435
///
2436
/// Returns an error if the mesh data has been extracted to `RenderWorld`.
2437
pub fn try_set_morph_target_names(
2438
&mut self,
2439
names: Vec<String>,
2440
) -> Result<(), MeshAccessError> {
2441
self.morph_target_names.replace(Some(names))?;
2442
Ok(())
2443
}
2444
2445
/// Consumes the mesh and returns a mesh with morph target names.
2446
/// Names should correspond to the order of the morph targets in `set_morph_targets`.
2447
///
2448
/// (Alternatively, you can use [`Mesh::set_morph_target_names`] to mutate an existing mesh in-place)
2449
///
2450
/// # Panics
2451
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2452
/// this as an error use [`Mesh::try_set_morph_target_names`]
2453
#[must_use]
2454
pub fn with_morph_target_names(self, names: Vec<String>) -> Self {
2455
self.try_with_morph_target_names(names)
2456
.expect(MESH_EXTRACTED_ERROR)
2457
}
2458
2459
/// Consumes the mesh and returns a mesh with morph target names.
2460
/// Names should correspond to the order of the morph targets in `set_morph_targets`.
2461
///
2462
/// (Alternatively, you can use [`Mesh::set_morph_target_names`] to mutate an existing mesh in-place)
2463
///
2464
/// Returns an error if the mesh data has been extracted to `RenderWorld`.
2465
pub fn try_with_morph_target_names(
2466
mut self,
2467
names: Vec<String>,
2468
) -> Result<Self, MeshAccessError> {
2469
self.try_set_morph_target_names(names)?;
2470
Ok(self)
2471
}
2472
2473
/// Gets a list of all morph target names, if they exist.
2474
///
2475
/// # Panics
2476
/// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2477
/// this as an error use [`Mesh::try_morph_target_names`]
2478
pub fn morph_target_names(&self) -> Option<&[String]> {
2479
self.try_morph_target_names().expect(MESH_EXTRACTED_ERROR)
2480
}
2481
2482
/// Gets a list of all morph target names, if they exist.
2483
///
2484
/// Returns an error if the mesh data has been extracted to `RenderWorld`or
2485
/// if the morph targets do not exist.
2486
pub fn try_morph_target_names(&self) -> Result<Option<&[String]>, MeshAccessError> {
2487
Ok(self
2488
.morph_target_names
2489
.as_ref_option()?
2490
.map(core::ops::Deref::deref))
2491
}
2492
}
2493
2494
/// An enum to define which UV attribute to use for a texture.
2495
///
2496
/// It only supports two UV attributes, [`Mesh::ATTRIBUTE_UV_0`] and
2497
/// [`Mesh::ATTRIBUTE_UV_1`].
2498
/// The default is [`UvChannel::Uv0`].
2499
#[derive(Reflect, Default, Debug, Clone, PartialEq, Eq)]
2500
#[reflect(Default, Debug, Clone, PartialEq)]
2501
pub enum UvChannel {
2502
#[default]
2503
Uv0,
2504
Uv1,
2505
}
2506
2507
/// Correctly scales and renormalizes an already normalized `normal` by the scale determined by its reciprocal `scale_recip`
2508
pub(crate) fn scale_normal(normal: Vec3, scale_recip: Vec3) -> Vec3 {
2509
// This is basically just `normal * scale_recip` but with the added rule that `0. * anything == 0.`
2510
// This is necessary because components of `scale_recip` may be infinities, which do not multiply to zero
2511
let n = Vec3::select(normal.cmpeq(Vec3::ZERO), Vec3::ZERO, normal * scale_recip);
2512
2513
// If n is finite, no component of `scale_recip` was infinite or the normal was perpendicular to the scale
2514
// else the scale had at least one zero-component and the normal needs to point along the direction of that component
2515
if n.is_finite() {
2516
n.normalize_or_zero()
2517
} else {
2518
Vec3::select(n.abs().cmpeq(Vec3::INFINITY), n.signum(), Vec3::ZERO).normalize()
2519
}
2520
}
2521
2522
impl core::ops::Mul<Mesh> for Transform {
2523
type Output = Mesh;
2524
2525
fn mul(self, rhs: Mesh) -> Self::Output {
2526
rhs.transformed_by(self)
2527
}
2528
}
2529
2530
/// A version of [`Mesh`] suitable for serializing for short-term transfer.
2531
///
2532
/// [`Mesh`] does not implement [`Serialize`] / [`Deserialize`] because it is made with the renderer in mind.
2533
/// It is not a general-purpose mesh implementation, and its internals are subject to frequent change.
2534
/// As such, storing a [`Mesh`] on disk is highly discouraged.
2535
///
2536
/// But there are still some valid use cases for serializing a [`Mesh`], namely transferring meshes between processes.
2537
/// To support this, you can create a [`SerializedMesh`] from a [`Mesh`] with [`SerializedMesh::from_mesh`],
2538
/// and then deserialize it with [`SerializedMesh::deserialize`]. The caveats are:
2539
/// - The mesh representation is not valid across different versions of Bevy.
2540
/// - This conversion is lossy. Only the following information is preserved:
2541
/// - Primitive topology
2542
/// - Vertex attributes
2543
/// - Indices
2544
/// - Custom attributes that were not specified with [`MeshDeserializer::add_custom_vertex_attribute`] will be ignored while deserializing.
2545
#[cfg(feature = "serialize")]
2546
#[derive(Debug, Clone, Serialize, Deserialize)]
2547
pub struct SerializedMesh {
2548
primitive_topology: PrimitiveTopology,
2549
attributes: Vec<(MeshVertexAttributeId, SerializedMeshAttributeData)>,
2550
indices: Option<Indices>,
2551
}
2552
2553
#[cfg(feature = "serialize")]
2554
impl SerializedMesh {
2555
/// Create a [`SerializedMesh`] from a [`Mesh`]. See the documentation for [`SerializedMesh`] for caveats.
2556
pub fn from_mesh(mut mesh: Mesh) -> Self {
2557
Self {
2558
primitive_topology: mesh.primitive_topology,
2559
attributes: mesh
2560
.attributes
2561
.replace(None)
2562
.expect(MESH_EXTRACTED_ERROR)
2563
.unwrap()
2564
.into_iter()
2565
.map(|(id, data)| {
2566
(
2567
id,
2568
SerializedMeshAttributeData::from_mesh_attribute_data(data),
2569
)
2570
})
2571
.collect(),
2572
indices: mesh.indices.replace(None).expect(MESH_EXTRACTED_ERROR),
2573
}
2574
}
2575
2576
/// Create a [`Mesh`] from a [`SerializedMesh`]. See the documentation for [`SerializedMesh`] for caveats.
2577
///
2578
/// Use [`MeshDeserializer`] if you need to pass extra options to the deserialization process, such as specifying custom vertex attributes.
2579
pub fn into_mesh(self) -> Mesh {
2580
MeshDeserializer::default().deserialize(self)
2581
}
2582
}
2583
2584
/// Use to specify extra options when deserializing a [`SerializedMesh`] into a [`Mesh`].
2585
#[cfg(feature = "serialize")]
2586
pub struct MeshDeserializer {
2587
custom_vertex_attributes: HashMap<Box<str>, MeshVertexAttribute>,
2588
}
2589
2590
#[cfg(feature = "serialize")]
2591
impl Default for MeshDeserializer {
2592
fn default() -> Self {
2593
// Written like this so that the compiler can validate that we use all the built-in attributes.
2594
// If you just added a new attribute and got a compile error, please add it to this list :)
2595
const BUILTINS: [MeshVertexAttribute; Mesh::FIRST_AVAILABLE_CUSTOM_ATTRIBUTE as usize] = [
2596
Mesh::ATTRIBUTE_POSITION,
2597
Mesh::ATTRIBUTE_NORMAL,
2598
Mesh::ATTRIBUTE_UV_0,
2599
Mesh::ATTRIBUTE_UV_1,
2600
Mesh::ATTRIBUTE_TANGENT,
2601
Mesh::ATTRIBUTE_COLOR,
2602
Mesh::ATTRIBUTE_JOINT_WEIGHT,
2603
Mesh::ATTRIBUTE_JOINT_INDEX,
2604
];
2605
Self {
2606
custom_vertex_attributes: BUILTINS
2607
.into_iter()
2608
.map(|attribute| (attribute.name.into(), attribute))
2609
.collect(),
2610
}
2611
}
2612
}
2613
2614
#[cfg(feature = "serialize")]
2615
impl MeshDeserializer {
2616
/// Create a new [`MeshDeserializer`].
2617
pub fn new() -> Self {
2618
Self::default()
2619
}
2620
2621
/// Register a custom vertex attribute to the deserializer. Custom vertex attributes that were not added with this method will be ignored while deserializing.
2622
pub fn add_custom_vertex_attribute(
2623
&mut self,
2624
name: &str,
2625
attribute: MeshVertexAttribute,
2626
) -> &mut Self {
2627
self.custom_vertex_attributes.insert(name.into(), attribute);
2628
self
2629
}
2630
2631
/// Deserialize a [`SerializedMesh`] into a [`Mesh`].
2632
///
2633
/// See the documentation for [`SerializedMesh`] for caveats.
2634
pub fn deserialize(&self, serialized_mesh: SerializedMesh) -> Mesh {
2635
Mesh {
2636
attributes: MeshExtractableData::Data(
2637
serialized_mesh
2638
.attributes
2639
.into_iter()
2640
.filter_map(|(id, data)| {
2641
let attribute = data.attribute.clone();
2642
let Some(data) =
2643
data.try_into_mesh_attribute_data(&self.custom_vertex_attributes)
2644
else {
2645
warn!(
2646
"Deserialized mesh contains custom vertex attribute {attribute:?} that \
2647
was not specified with `MeshDeserializer::add_custom_vertex_attribute`. Ignoring."
2648
);
2649
return None;
2650
};
2651
Some((id, data))
2652
})
2653
.collect()),
2654
indices: serialized_mesh.indices.into(),
2655
..Mesh::new(serialized_mesh.primitive_topology, RenderAssetUsages::default())
2656
}
2657
}
2658
}
2659
2660
/// Error that can occur when calling [`Mesh::merge_duplicate_vertices`]
2661
#[derive(Error, Debug, Clone)]
2662
pub enum MeshMergeDuplicateVerticesError {
2663
#[error("Index attribute already set.")]
2664
IndicesAlreadySet,
2665
#[error("Mesh access error: {0}")]
2666
MeshAccessError(#[from] MeshAccessError),
2667
}
2668
2669
/// Error that can occur when calling [`Mesh::merge`].
2670
#[derive(Error, Debug, Clone)]
2671
pub enum MeshMergeError {
2672
#[error("Incompatible vertex attribute types: {} and {}", self_attribute.name, other_attribute.map(|a| a.name).unwrap_or("None"))]
2673
IncompatibleVertexAttributes {
2674
self_attribute: MeshVertexAttribute,
2675
other_attribute: Option<MeshVertexAttribute>,
2676
},
2677
#[error(
2678
"Incompatible primitive topologies: {:?} and {:?}",
2679
self_primitive_topology,
2680
other_primitive_topology
2681
)]
2682
IncompatiblePrimitiveTopology {
2683
self_primitive_topology: PrimitiveTopology,
2684
other_primitive_topology: PrimitiveTopology,
2685
},
2686
#[error("Mesh access error: {0}")]
2687
MeshAccessError(#[from] MeshAccessError),
2688
}
2689
2690
#[cfg(test)]
2691
mod tests {
2692
use super::Mesh;
2693
#[cfg(feature = "serialize")]
2694
use super::SerializedMesh;
2695
use crate::mesh::{Indices, MeshWindingInvertError, VertexAttributeValues};
2696
use crate::PrimitiveTopology;
2697
use bevy_asset::RenderAssetUsages;
2698
use bevy_math::bounding::Aabb3d;
2699
use bevy_math::primitives::Triangle3d;
2700
use bevy_math::Vec3;
2701
use bevy_transform::components::Transform;
2702
2703
#[test]
2704
#[should_panic]
2705
fn panic_invalid_format() {
2706
let _mesh = Mesh::new(
2707
PrimitiveTopology::TriangleList,
2708
RenderAssetUsages::default(),
2709
)
2710
.with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, vec![[0.0, 0.0, 0.0]]);
2711
}
2712
2713
#[test]
2714
fn transform_mesh() {
2715
let mesh = Mesh::new(
2716
PrimitiveTopology::TriangleList,
2717
RenderAssetUsages::default(),
2718
)
2719
.with_inserted_attribute(
2720
Mesh::ATTRIBUTE_POSITION,
2721
vec![[-1., -1., 2.], [1., -1., 2.], [0., 1., 2.]],
2722
)
2723
.with_inserted_attribute(
2724
Mesh::ATTRIBUTE_NORMAL,
2725
vec![
2726
Vec3::new(-1., -1., 1.).normalize().to_array(),
2727
Vec3::new(1., -1., 1.).normalize().to_array(),
2728
[0., 0., 1.],
2729
],
2730
)
2731
.with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, vec![[0., 0.], [1., 0.], [0.5, 1.]]);
2732
2733
let mesh = mesh.transformed_by(
2734
Transform::from_translation(Vec3::splat(-2.)).with_scale(Vec3::new(2., 0., -1.)),
2735
);
2736
2737
if let Some(VertexAttributeValues::Float32x3(positions)) =
2738
mesh.attribute(Mesh::ATTRIBUTE_POSITION)
2739
{
2740
// All positions are first scaled resulting in `vec![[-2, 0., -2.], [2., 0., -2.], [0., 0., -2.]]`
2741
// and then shifted by `-2.` along each axis
2742
assert_eq!(
2743
positions,
2744
&vec![[-4.0, -2.0, -4.0], [0.0, -2.0, -4.0], [-2.0, -2.0, -4.0]]
2745
);
2746
} else {
2747
panic!("Mesh does not have a position attribute");
2748
}
2749
2750
if let Some(VertexAttributeValues::Float32x3(normals)) =
2751
mesh.attribute(Mesh::ATTRIBUTE_NORMAL)
2752
{
2753
assert_eq!(normals, &vec![[0., -1., 0.], [0., -1., 0.], [0., 0., -1.]]);
2754
} else {
2755
panic!("Mesh does not have a normal attribute");
2756
}
2757
2758
if let Some(VertexAttributeValues::Float32x2(uvs)) = mesh.attribute(Mesh::ATTRIBUTE_UV_0) {
2759
assert_eq!(uvs, &vec![[0., 0.], [1., 0.], [0.5, 1.]]);
2760
} else {
2761
panic!("Mesh does not have a uv attribute");
2762
}
2763
}
2764
2765
#[test]
2766
fn point_list_mesh_invert_winding() {
2767
let mesh = Mesh::new(PrimitiveTopology::PointList, RenderAssetUsages::default())
2768
.with_inserted_indices(Indices::U32(vec![]));
2769
assert!(matches!(
2770
mesh.with_inverted_winding(),
2771
Err(MeshWindingInvertError::WrongTopology)
2772
));
2773
}
2774
2775
#[test]
2776
fn line_list_mesh_invert_winding() {
2777
let mesh = Mesh::new(PrimitiveTopology::LineList, RenderAssetUsages::default())
2778
.with_inserted_indices(Indices::U32(vec![0, 1, 1, 2, 2, 3]));
2779
let mesh = mesh.with_inverted_winding().unwrap();
2780
assert_eq!(
2781
mesh.indices().unwrap().iter().collect::<Vec<usize>>(),
2782
vec![3, 2, 2, 1, 1, 0]
2783
);
2784
}
2785
2786
#[test]
2787
fn line_list_mesh_invert_winding_fail() {
2788
let mesh = Mesh::new(PrimitiveTopology::LineList, RenderAssetUsages::default())
2789
.with_inserted_indices(Indices::U32(vec![0, 1, 1]));
2790
assert!(matches!(
2791
mesh.with_inverted_winding(),
2792
Err(MeshWindingInvertError::AbruptIndicesEnd)
2793
));
2794
}
2795
2796
#[test]
2797
fn line_strip_mesh_invert_winding() {
2798
let mesh = Mesh::new(PrimitiveTopology::LineStrip, RenderAssetUsages::default())
2799
.with_inserted_indices(Indices::U32(vec![0, 1, 2, 3]));
2800
let mesh = mesh.with_inverted_winding().unwrap();
2801
assert_eq!(
2802
mesh.indices().unwrap().iter().collect::<Vec<usize>>(),
2803
vec![3, 2, 1, 0]
2804
);
2805
}
2806
2807
#[test]
2808
fn triangle_list_mesh_invert_winding() {
2809
let mesh = Mesh::new(
2810
PrimitiveTopology::TriangleList,
2811
RenderAssetUsages::default(),
2812
)
2813
.with_inserted_indices(Indices::U32(vec![
2814
0, 3, 1, // First triangle
2815
1, 3, 2, // Second triangle
2816
]));
2817
let mesh = mesh.with_inverted_winding().unwrap();
2818
assert_eq!(
2819
mesh.indices().unwrap().iter().collect::<Vec<usize>>(),
2820
vec![
2821
0, 1, 3, // First triangle
2822
1, 2, 3, // Second triangle
2823
]
2824
);
2825
}
2826
2827
#[test]
2828
fn triangle_list_mesh_invert_winding_fail() {
2829
let mesh = Mesh::new(
2830
PrimitiveTopology::TriangleList,
2831
RenderAssetUsages::default(),
2832
)
2833
.with_inserted_indices(Indices::U32(vec![0, 3, 1, 2]));
2834
assert!(matches!(
2835
mesh.with_inverted_winding(),
2836
Err(MeshWindingInvertError::AbruptIndicesEnd)
2837
));
2838
}
2839
2840
#[test]
2841
fn triangle_strip_mesh_invert_winding() {
2842
let mesh = Mesh::new(
2843
PrimitiveTopology::TriangleStrip,
2844
RenderAssetUsages::default(),
2845
)
2846
.with_inserted_indices(Indices::U32(vec![0, 1, 2, 3]));
2847
let mesh = mesh.with_inverted_winding().unwrap();
2848
assert_eq!(
2849
mesh.indices().unwrap().iter().collect::<Vec<usize>>(),
2850
vec![3, 2, 1, 0]
2851
);
2852
}
2853
2854
#[test]
2855
fn compute_area_weighted_normals() {
2856
let mut mesh = Mesh::new(
2857
PrimitiveTopology::TriangleList,
2858
RenderAssetUsages::default(),
2859
);
2860
2861
// z y
2862
// | /
2863
// 3---2
2864
// | / \
2865
// 0-----1--x
2866
2867
mesh.insert_attribute(
2868
Mesh::ATTRIBUTE_POSITION,
2869
vec![[0., 0., 0.], [1., 0., 0.], [0., 1., 0.], [0., 0., 1.]],
2870
);
2871
mesh.insert_indices(Indices::U16(vec![0, 1, 2, 0, 2, 3]));
2872
mesh.compute_area_weighted_normals();
2873
let normals = mesh
2874
.attribute(Mesh::ATTRIBUTE_NORMAL)
2875
.unwrap()
2876
.as_float3()
2877
.unwrap();
2878
assert_eq!(4, normals.len());
2879
// 0
2880
assert_eq!(Vec3::new(1., 0., 1.).normalize().to_array(), normals[0]);
2881
// 1
2882
assert_eq!([0., 0., 1.], normals[1]);
2883
// 2
2884
assert_eq!(Vec3::new(1., 0., 1.).normalize().to_array(), normals[2]);
2885
// 3
2886
assert_eq!([1., 0., 0.], normals[3]);
2887
}
2888
2889
#[test]
2890
fn compute_area_weighted_normals_proportionate() {
2891
let mut mesh = Mesh::new(
2892
PrimitiveTopology::TriangleList,
2893
RenderAssetUsages::default(),
2894
);
2895
2896
// z y
2897
// | /
2898
// 3---2..
2899
// | / \
2900
// 0-------1---x
2901
2902
mesh.insert_attribute(
2903
Mesh::ATTRIBUTE_POSITION,
2904
vec![[0., 0., 0.], [2., 0., 0.], [0., 1., 0.], [0., 0., 1.]],
2905
);
2906
mesh.insert_indices(Indices::U16(vec![0, 1, 2, 0, 2, 3]));
2907
mesh.compute_area_weighted_normals();
2908
let normals = mesh
2909
.attribute(Mesh::ATTRIBUTE_NORMAL)
2910
.unwrap()
2911
.as_float3()
2912
.unwrap();
2913
assert_eq!(4, normals.len());
2914
// 0
2915
assert_eq!(Vec3::new(1., 0., 2.).normalize().to_array(), normals[0]);
2916
// 1
2917
assert_eq!([0., 0., 1.], normals[1]);
2918
// 2
2919
assert_eq!(Vec3::new(1., 0., 2.).normalize().to_array(), normals[2]);
2920
// 3
2921
assert_eq!([1., 0., 0.], normals[3]);
2922
}
2923
2924
#[test]
2925
fn compute_angle_weighted_normals() {
2926
// CuboidMeshBuilder duplicates vertices (even though it is indexed)
2927
2928
// 5---------4
2929
// /| /|
2930
// 1-+-------0 |
2931
// | 6-------|-7
2932
// |/ |/
2933
// 2---------3
2934
let verts = vec![
2935
[1.0, 1.0, 1.0],
2936
[-1.0, 1.0, 1.0],
2937
[-1.0, -1.0, 1.0],
2938
[1.0, -1.0, 1.0],
2939
[1.0, 1.0, -1.0],
2940
[-1.0, 1.0, -1.0],
2941
[-1.0, -1.0, -1.0],
2942
[1.0, -1.0, -1.0],
2943
];
2944
2945
let indices = Indices::U16(vec![
2946
0, 1, 2, 2, 3, 0, // front
2947
5, 4, 7, 7, 6, 5, // back
2948
1, 5, 6, 6, 2, 1, // left
2949
4, 0, 3, 3, 7, 4, // right
2950
4, 5, 1, 1, 0, 4, // top
2951
3, 2, 6, 6, 7, 3, // bottom
2952
]);
2953
let mut mesh = Mesh::new(
2954
PrimitiveTopology::TriangleList,
2955
RenderAssetUsages::default(),
2956
);
2957
mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, verts);
2958
mesh.insert_indices(indices);
2959
mesh.compute_smooth_normals();
2960
2961
let normals = mesh
2962
.attribute(Mesh::ATTRIBUTE_NORMAL)
2963
.unwrap()
2964
.as_float3()
2965
.unwrap();
2966
2967
for new in normals.iter().copied().flatten() {
2968
// std impl is unstable
2969
const FRAC_1_SQRT_3: f32 = 0.57735026;
2970
const MIN: f32 = FRAC_1_SQRT_3 - f32::EPSILON;
2971
const MAX: f32 = FRAC_1_SQRT_3 + f32::EPSILON;
2972
assert!(new.abs() >= MIN, "{new} < {MIN}");
2973
assert!(new.abs() <= MAX, "{new} > {MAX}");
2974
}
2975
}
2976
2977
#[test]
2978
fn triangles_from_triangle_list() {
2979
let mut mesh = Mesh::new(
2980
PrimitiveTopology::TriangleList,
2981
RenderAssetUsages::default(),
2982
);
2983
mesh.insert_attribute(
2984
Mesh::ATTRIBUTE_POSITION,
2985
vec![[0., 0., 0.], [1., 0., 0.], [1., 1., 0.], [0., 1., 0.]],
2986
);
2987
mesh.insert_indices(Indices::U32(vec![0, 1, 2, 2, 3, 0]));
2988
assert_eq!(
2989
vec![
2990
Triangle3d {
2991
vertices: [
2992
Vec3::new(0., 0., 0.),
2993
Vec3::new(1., 0., 0.),
2994
Vec3::new(1., 1., 0.),
2995
]
2996
},
2997
Triangle3d {
2998
vertices: [
2999
Vec3::new(1., 1., 0.),
3000
Vec3::new(0., 1., 0.),
3001
Vec3::new(0., 0., 0.),
3002
]
3003
}
3004
],
3005
mesh.triangles().unwrap().collect::<Vec<Triangle3d>>()
3006
);
3007
}
3008
3009
#[test]
3010
fn triangles_from_triangle_strip() {
3011
let mut mesh = Mesh::new(
3012
PrimitiveTopology::TriangleStrip,
3013
RenderAssetUsages::default(),
3014
);
3015
// Triangles: (0, 1, 2), (2, 1, 3), (2, 3, 4), (4, 3, 5)
3016
//
3017
// 4 - 5
3018
// | \ |
3019
// 2 - 3
3020
// | \ |
3021
// 0 - 1
3022
let positions: Vec<Vec3> = [
3023
[0., 0., 0.],
3024
[1., 0., 0.],
3025
[0., 1., 0.],
3026
[1., 1., 0.],
3027
[0., 2., 0.],
3028
[1., 2., 0.],
3029
]
3030
.into_iter()
3031
.map(Vec3::from_array)
3032
.collect();
3033
mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions.clone());
3034
mesh.insert_indices(Indices::U32(vec![0, 1, 2, 3, 4, 5]));
3035
assert_eq!(
3036
vec![
3037
Triangle3d {
3038
vertices: [positions[0], positions[1], positions[2]]
3039
},
3040
Triangle3d {
3041
vertices: [positions[2], positions[1], positions[3]]
3042
},
3043
Triangle3d {
3044
vertices: [positions[2], positions[3], positions[4]]
3045
},
3046
Triangle3d {
3047
vertices: [positions[4], positions[3], positions[5]]
3048
},
3049
],
3050
mesh.triangles().unwrap().collect::<Vec<Triangle3d>>()
3051
);
3052
}
3053
3054
#[test]
3055
fn take_gpu_data_calculates_aabb() {
3056
let mut mesh = Mesh::new(
3057
PrimitiveTopology::TriangleList,
3058
RenderAssetUsages::default(),
3059
);
3060
mesh.insert_attribute(
3061
Mesh::ATTRIBUTE_POSITION,
3062
vec![
3063
[-0.5, 0., 0.],
3064
[-1., 0., 0.],
3065
[-1., -1., 0.],
3066
[-0.5, -1., 0.],
3067
],
3068
);
3069
mesh.insert_indices(Indices::U32(vec![0, 1, 2, 2, 3, 0]));
3070
mesh = mesh.take_gpu_data().unwrap();
3071
assert_eq!(
3072
mesh.final_aabb,
3073
Some(Aabb3d::from_min_max([-1., -1., 0.], [-0.5, 0., 0.]))
3074
);
3075
}
3076
3077
#[cfg(feature = "serialize")]
3078
#[test]
3079
fn serialize_deserialize_mesh() {
3080
let mut mesh = Mesh::new(
3081
PrimitiveTopology::TriangleList,
3082
RenderAssetUsages::default(),
3083
);
3084
3085
mesh.insert_attribute(
3086
Mesh::ATTRIBUTE_POSITION,
3087
vec![[0., 0., 0.], [2., 0., 0.], [0., 1., 0.], [0., 0., 1.]],
3088
);
3089
mesh.insert_indices(Indices::U16(vec![0, 1, 2, 0, 2, 3]));
3090
3091
let serialized_mesh = SerializedMesh::from_mesh(mesh.clone());
3092
let serialized_string = serde_json::to_string(&serialized_mesh).unwrap();
3093
let serialized_mesh_from_string: SerializedMesh =
3094
serde_json::from_str(&serialized_string).unwrap();
3095
let deserialized_mesh = serialized_mesh_from_string.into_mesh();
3096
assert_eq!(mesh, deserialized_mesh);
3097
}
3098
3099
#[test]
3100
fn merge_duplicate_vertices() {
3101
let mut mesh = Mesh::new(
3102
PrimitiveTopology::TriangleList,
3103
RenderAssetUsages::default(),
3104
);
3105
// Quad made of two triangles.
3106
let positions = vec![
3107
[0.0, 0.0, 0.0],
3108
[1.0, 0.0, 0.0],
3109
[1.0, 1.0, 0.0],
3110
// This will be deduplicated.
3111
[1.0, 1.0, 0.0],
3112
[0.0, 1.0, 0.0],
3113
// Position is equal to the first one but UV is different so it won't be deduplicated.
3114
[0.0, 0.0, 0.0],
3115
];
3116
let uvs = vec![
3117
[0.0, 0.0],
3118
[1.0, 0.0],
3119
[1.0, 1.0],
3120
// This will be deduplicated.
3121
[1.0, 1.0],
3122
[0.0, 1.0],
3123
// Use different UV here so it won't be deduplicated.
3124
[0.0, 0.5],
3125
];
3126
mesh.insert_attribute(
3127
Mesh::ATTRIBUTE_POSITION,
3128
VertexAttributeValues::Float32x3(positions.clone()),
3129
);
3130
mesh.insert_attribute(
3131
Mesh::ATTRIBUTE_UV_0,
3132
VertexAttributeValues::Float32x2(uvs.clone()),
3133
);
3134
3135
let res = mesh.merge_duplicate_vertices();
3136
assert!(res.is_ok());
3137
assert_eq!(6, mesh.indices().unwrap().len());
3138
// Note we have 5 unique vertices, not 6.
3139
assert_eq!(5, mesh.attribute(Mesh::ATTRIBUTE_POSITION).unwrap().len());
3140
assert_eq!(5, mesh.attribute(Mesh::ATTRIBUTE_UV_0).unwrap().len());
3141
3142
// Duplicate back.
3143
mesh.duplicate_vertices();
3144
assert!(mesh.indices().is_none());
3145
let VertexAttributeValues::Float32x3(new_positions) =
3146
mesh.attribute(Mesh::ATTRIBUTE_POSITION).unwrap()
3147
else {
3148
panic!("Unexpected attribute type")
3149
};
3150
let VertexAttributeValues::Float32x2(new_uvs) =
3151
mesh.attribute(Mesh::ATTRIBUTE_UV_0).unwrap()
3152
else {
3153
panic!("Unexpected attribute type")
3154
};
3155
assert_eq!(&positions, new_positions);
3156
assert_eq!(&uvs, new_uvs);
3157
}
3158
}
3159
3160