bevy_mesh/
mesh.rs

1use bevy_transform::components::Transform;
2pub use wgpu::PrimitiveTopology;
3
4use super::{
5    face_normal, generate_tangents_for_mesh, scale_normal, FourIterators, GenerateTangentsError,
6    Indices, MeshAttributeData, MeshTrianglesError, MeshVertexAttribute, MeshVertexAttributeId,
7    MeshVertexBufferLayout, MeshVertexBufferLayoutRef, MeshVertexBufferLayouts,
8    MeshWindingInvertError, VertexAttributeValues, VertexBufferLayout, VertexFormatSize,
9};
10use alloc::collections::BTreeMap;
11use bevy_asset::{Asset, Handle, RenderAssetUsages};
12use bevy_image::Image;
13use bevy_math::{primitives::Triangle3d, *};
14use bevy_reflect::Reflect;
15use bevy_utils::tracing::warn;
16use bytemuck::cast_slice;
17use wgpu::{VertexAttribute, VertexFormat, VertexStepMode};
18
19pub const INDEX_BUFFER_ASSET_INDEX: u64 = 0;
20pub const VERTEX_ATTRIBUTE_BUFFER_ID: u64 = 10;
21
22/// A 3D object made out of vertices representing triangles, lines, or points,
23/// with "attribute" values for each vertex.
24///
25/// Meshes can be automatically generated by a bevy `AssetLoader` (generally by loading a `Gltf` file),
26/// or by converting a [primitive](bevy_math::primitives) using [`into`](Into).
27/// It is also possible to create one manually. They can be edited after creation.
28///
29/// Meshes can be rendered with a `Mesh2d` and `MeshMaterial2d`
30/// or `Mesh3d` and `MeshMaterial3d` for 2D and 3D respectively.
31///
32/// A [`Mesh`] in Bevy is equivalent to a "primitive" in the glTF format, for a
33/// glTF Mesh representation, see `GltfMesh`.
34///
35/// ## Manual creation
36///
37/// The following function will construct a flat mesh, to be rendered with a
38/// `StandardMaterial` or `ColorMaterial`:
39///
40/// ```
41/// # use bevy_mesh::{Mesh, Indices, PrimitiveTopology};
42/// # use bevy_asset::RenderAssetUsages;
43/// fn create_simple_parallelogram() -> Mesh {
44///     // Create a new mesh using a triangle list topology, where each set of 3 vertices composes a triangle.
45///     Mesh::new(PrimitiveTopology::TriangleList, RenderAssetUsages::default())
46///         // Add 4 vertices, each with its own position attribute (coordinate in
47///         // 3D space), for each of the corners of the parallelogram.
48///         .with_inserted_attribute(
49///             Mesh::ATTRIBUTE_POSITION,
50///             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]]
51///         )
52///         // Assign a UV coordinate to each vertex.
53///         .with_inserted_attribute(
54///             Mesh::ATTRIBUTE_UV_0,
55///             vec![[0.0, 1.0], [0.5, 0.0], [1.0, 0.0], [0.5, 1.0]]
56///         )
57///         // Assign normals (everything points outwards)
58///         .with_inserted_attribute(
59///             Mesh::ATTRIBUTE_NORMAL,
60///             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]]
61///         )
62///         // After defining all the vertices and their attributes, build each triangle using the
63///         // indices of the vertices that make it up in a counter-clockwise order.
64///         .with_inserted_indices(Indices::U32(vec![
65///             // First triangle
66///             0, 3, 1,
67///             // Second triangle
68///             1, 3, 2
69///         ]))
70/// }
71/// ```
72///
73/// You can see how it looks like [here](https://github.com/bevyengine/bevy/blob/main/assets/docs/Mesh.png),
74/// used in a `Mesh3d` with a square bevy logo texture, with added axis, points,
75/// lines and text for clarity.
76///
77/// ## Other examples
78///
79/// For further visualization, explanation, and examples, see the built-in Bevy examples,
80/// and the [implementation of the built-in shapes](https://github.com/bevyengine/bevy/tree/main/crates/bevy_mesh/src/primitives).
81/// In particular, [generate_custom_mesh](https://github.com/bevyengine/bevy/blob/main/examples/3d/generate_custom_mesh.rs)
82/// teaches you to access and modify the attributes of a [`Mesh`] after creating it.
83///
84/// ## Common points of confusion
85///
86/// - UV maps in Bevy start at the top-left, see [`ATTRIBUTE_UV_0`](Mesh::ATTRIBUTE_UV_0),
87///     other APIs can have other conventions, `OpenGL` starts at bottom-left.
88/// - It is possible and sometimes useful for multiple vertices to have the same
89///     [position attribute](Mesh::ATTRIBUTE_POSITION) value,
90///     it's a common technique in 3D modeling for complex UV mapping or other calculations.
91/// - Bevy performs frustum culling based on the `Aabb` of meshes, which is calculated
92///     and added automatically for new meshes only. If a mesh is modified, the entity's `Aabb`
93///     needs to be updated manually or deleted so that it is re-calculated.
94///
95/// ## Use with `StandardMaterial`
96///
97/// To render correctly with `StandardMaterial`, a mesh needs to have properly defined:
98/// - [`UVs`](Mesh::ATTRIBUTE_UV_0): Bevy needs to know how to map a texture onto the mesh
99///     (also true for `ColorMaterial`).
100/// - [`Normals`](Mesh::ATTRIBUTE_NORMAL): Bevy needs to know how light interacts with your mesh.
101///     [0.0, 0.0, 1.0] is very common for simple flat meshes on the XY plane,
102///     because simple meshes are smooth and they don't require complex light calculations.
103/// - Vertex winding order: by default, `StandardMaterial.cull_mode` is `Some(Face::Back)`,
104///     which means that Bevy would *only* render the "front" of each triangle, which
105///     is the side of the triangle from where the vertices appear in a *counter-clockwise* order.
106#[derive(Asset, Debug, Clone, Reflect)]
107pub struct Mesh {
108    #[reflect(ignore)]
109    primitive_topology: PrimitiveTopology,
110    /// `std::collections::BTreeMap` with all defined vertex attributes (Positions, Normals, ...)
111    /// for this mesh. Attribute ids to attribute values.
112    /// Uses a [`BTreeMap`] because, unlike `HashMap`, it has a defined iteration order,
113    /// which allows easy stable `VertexBuffers` (i.e. same buffer order)
114    #[reflect(ignore)]
115    attributes: BTreeMap<MeshVertexAttributeId, MeshAttributeData>,
116    indices: Option<Indices>,
117    morph_targets: Option<Handle<Image>>,
118    morph_target_names: Option<Vec<String>>,
119    pub asset_usage: RenderAssetUsages,
120}
121
122impl Mesh {
123    /// Where the vertex is located in space. Use in conjunction with [`Mesh::insert_attribute`]
124    /// or [`Mesh::with_inserted_attribute`].
125    ///
126    /// The format of this attribute is [`VertexFormat::Float32x3`].
127    pub const ATTRIBUTE_POSITION: MeshVertexAttribute =
128        MeshVertexAttribute::new("Vertex_Position", 0, VertexFormat::Float32x3);
129
130    /// The direction the vertex normal is facing in.
131    /// Use in conjunction with [`Mesh::insert_attribute`] or [`Mesh::with_inserted_attribute`].
132    ///
133    /// The format of this attribute is [`VertexFormat::Float32x3`].
134    pub const ATTRIBUTE_NORMAL: MeshVertexAttribute =
135        MeshVertexAttribute::new("Vertex_Normal", 1, VertexFormat::Float32x3);
136
137    /// Texture coordinates for the vertex. Use in conjunction with [`Mesh::insert_attribute`]
138    /// or [`Mesh::with_inserted_attribute`].
139    ///
140    /// Generally `[0.,0.]` is mapped to the top left of the texture, and `[1.,1.]` to the bottom-right.
141    ///
142    /// By default values outside will be clamped per pixel not for the vertex,
143    /// "stretching" the borders of the texture.
144    /// This behavior can be useful in some cases, usually when the borders have only
145    /// one color, for example a logo, and you want to "extend" those borders.
146    ///
147    /// For different mapping outside of `0..=1` range,
148    /// see [`ImageAddressMode`](bevy_image::ImageAddressMode).
149    ///
150    /// The format of this attribute is [`VertexFormat::Float32x2`].
151    pub const ATTRIBUTE_UV_0: MeshVertexAttribute =
152        MeshVertexAttribute::new("Vertex_Uv", 2, VertexFormat::Float32x2);
153
154    /// Alternate texture coordinates for the vertex. Use in conjunction with
155    /// [`Mesh::insert_attribute`] or [`Mesh::with_inserted_attribute`].
156    ///
157    /// Typically, these are used for lightmaps, textures that provide
158    /// precomputed illumination.
159    ///
160    /// The format of this attribute is [`VertexFormat::Float32x2`].
161    pub const ATTRIBUTE_UV_1: MeshVertexAttribute =
162        MeshVertexAttribute::new("Vertex_Uv_1", 3, VertexFormat::Float32x2);
163
164    /// The direction of the vertex tangent. Used for normal mapping.
165    /// Usually generated with [`generate_tangents`](Mesh::generate_tangents) or
166    /// [`with_generated_tangents`](Mesh::with_generated_tangents).
167    ///
168    /// The format of this attribute is [`VertexFormat::Float32x4`].
169    pub const ATTRIBUTE_TANGENT: MeshVertexAttribute =
170        MeshVertexAttribute::new("Vertex_Tangent", 4, VertexFormat::Float32x4);
171
172    /// Per vertex coloring. Use in conjunction with [`Mesh::insert_attribute`]
173    /// or [`Mesh::with_inserted_attribute`].
174    ///
175    /// The format of this attribute is [`VertexFormat::Float32x4`].
176    pub const ATTRIBUTE_COLOR: MeshVertexAttribute =
177        MeshVertexAttribute::new("Vertex_Color", 5, VertexFormat::Float32x4);
178
179    /// Per vertex joint transform matrix weight. Use in conjunction with [`Mesh::insert_attribute`]
180    /// or [`Mesh::with_inserted_attribute`].
181    ///
182    /// The format of this attribute is [`VertexFormat::Float32x4`].
183    pub const ATTRIBUTE_JOINT_WEIGHT: MeshVertexAttribute =
184        MeshVertexAttribute::new("Vertex_JointWeight", 6, VertexFormat::Float32x4);
185
186    /// Per vertex joint transform matrix index. Use in conjunction with [`Mesh::insert_attribute`]
187    /// or [`Mesh::with_inserted_attribute`].
188    ///
189    /// The format of this attribute is [`VertexFormat::Uint16x4`].
190    pub const ATTRIBUTE_JOINT_INDEX: MeshVertexAttribute =
191        MeshVertexAttribute::new("Vertex_JointIndex", 7, VertexFormat::Uint16x4);
192
193    /// Construct a new mesh. You need to provide a [`PrimitiveTopology`] so that the
194    /// renderer knows how to treat the vertex data. Most of the time this will be
195    /// [`PrimitiveTopology::TriangleList`].
196    pub fn new(primitive_topology: PrimitiveTopology, asset_usage: RenderAssetUsages) -> Self {
197        Mesh {
198            primitive_topology,
199            attributes: Default::default(),
200            indices: None,
201            morph_targets: None,
202            morph_target_names: None,
203            asset_usage,
204        }
205    }
206
207    /// Returns the topology of the mesh.
208    pub fn primitive_topology(&self) -> PrimitiveTopology {
209        self.primitive_topology
210    }
211
212    /// Sets the data for a vertex attribute (position, normal, etc.). The name will
213    /// often be one of the associated constants such as [`Mesh::ATTRIBUTE_POSITION`].
214    ///
215    /// `Aabb` of entities with modified mesh are not updated automatically.
216    ///
217    /// # Panics
218    /// Panics when the format of the values does not match the attribute's format.
219    #[inline]
220    pub fn insert_attribute(
221        &mut self,
222        attribute: MeshVertexAttribute,
223        values: impl Into<VertexAttributeValues>,
224    ) {
225        let values = values.into();
226        let values_format = VertexFormat::from(&values);
227        if values_format != attribute.format {
228            panic!(
229                "Failed to insert attribute. Invalid attribute format for {}. Given format is {values_format:?} but expected {:?}",
230                attribute.name, attribute.format
231            );
232        }
233
234        self.attributes
235            .insert(attribute.id, MeshAttributeData { attribute, values });
236    }
237
238    /// Consumes the mesh and returns a mesh with data set for a vertex attribute (position, normal, etc.).
239    /// The name will often be one of the associated constants such as [`Mesh::ATTRIBUTE_POSITION`].
240    ///
241    /// (Alternatively, you can use [`Mesh::insert_attribute`] to mutate an existing mesh in-place)
242    ///
243    /// `Aabb` of entities with modified mesh are not updated automatically.
244    ///
245    /// # Panics
246    /// Panics when the format of the values does not match the attribute's format.
247    #[must_use]
248    #[inline]
249    pub fn with_inserted_attribute(
250        mut self,
251        attribute: MeshVertexAttribute,
252        values: impl Into<VertexAttributeValues>,
253    ) -> Self {
254        self.insert_attribute(attribute, values);
255        self
256    }
257
258    /// Removes the data for a vertex attribute
259    pub fn remove_attribute(
260        &mut self,
261        attribute: impl Into<MeshVertexAttributeId>,
262    ) -> Option<VertexAttributeValues> {
263        self.attributes
264            .remove(&attribute.into())
265            .map(|data| data.values)
266    }
267
268    /// Consumes the mesh and returns a mesh without the data for a vertex attribute
269    ///
270    /// (Alternatively, you can use [`Mesh::remove_attribute`] to mutate an existing mesh in-place)
271    #[must_use]
272    pub fn with_removed_attribute(mut self, attribute: impl Into<MeshVertexAttributeId>) -> Self {
273        self.remove_attribute(attribute);
274        self
275    }
276
277    #[inline]
278    pub fn contains_attribute(&self, id: impl Into<MeshVertexAttributeId>) -> bool {
279        self.attributes.contains_key(&id.into())
280    }
281
282    /// Retrieves the data currently set to the vertex attribute with the specified `name`.
283    #[inline]
284    pub fn attribute(
285        &self,
286        id: impl Into<MeshVertexAttributeId>,
287    ) -> Option<&VertexAttributeValues> {
288        self.attributes.get(&id.into()).map(|data| &data.values)
289    }
290
291    /// Retrieves the data currently set to the vertex attribute with the specified `name` mutably.
292    #[inline]
293    pub fn attribute_mut(
294        &mut self,
295        id: impl Into<MeshVertexAttributeId>,
296    ) -> Option<&mut VertexAttributeValues> {
297        self.attributes
298            .get_mut(&id.into())
299            .map(|data| &mut data.values)
300    }
301
302    /// Returns an iterator that yields references to the data of each vertex attribute.
303    pub fn attributes(
304        &self,
305    ) -> impl Iterator<Item = (&MeshVertexAttribute, &VertexAttributeValues)> {
306        self.attributes
307            .values()
308            .map(|data| (&data.attribute, &data.values))
309    }
310
311    /// Returns an iterator that yields mutable references to the data of each vertex attribute.
312    pub fn attributes_mut(
313        &mut self,
314    ) -> impl Iterator<Item = (&MeshVertexAttribute, &mut VertexAttributeValues)> {
315        self.attributes
316            .values_mut()
317            .map(|data| (&data.attribute, &mut data.values))
318    }
319
320    /// Sets the vertex indices of the mesh. They describe how triangles are constructed out of the
321    /// vertex attributes and are therefore only useful for the [`PrimitiveTopology`] variants
322    /// that use triangles.
323    #[inline]
324    pub fn insert_indices(&mut self, indices: Indices) {
325        self.indices = Some(indices);
326    }
327
328    /// Consumes the mesh and returns a mesh with the given vertex indices. They describe how triangles
329    /// are constructed out of the vertex attributes and are therefore only useful for the
330    /// [`PrimitiveTopology`] variants that use triangles.
331    ///
332    /// (Alternatively, you can use [`Mesh::insert_indices`] to mutate an existing mesh in-place)
333    #[must_use]
334    #[inline]
335    pub fn with_inserted_indices(mut self, indices: Indices) -> Self {
336        self.insert_indices(indices);
337        self
338    }
339
340    /// Retrieves the vertex `indices` of the mesh.
341    #[inline]
342    pub fn indices(&self) -> Option<&Indices> {
343        self.indices.as_ref()
344    }
345
346    /// Retrieves the vertex `indices` of the mesh mutably.
347    #[inline]
348    pub fn indices_mut(&mut self) -> Option<&mut Indices> {
349        self.indices.as_mut()
350    }
351
352    /// Removes the vertex `indices` from the mesh and returns them.
353    #[inline]
354    pub fn remove_indices(&mut self) -> Option<Indices> {
355        core::mem::take(&mut self.indices)
356    }
357
358    /// Consumes the mesh and returns a mesh without the vertex `indices` of the mesh.
359    ///
360    /// (Alternatively, you can use [`Mesh::remove_indices`] to mutate an existing mesh in-place)
361    #[must_use]
362    pub fn with_removed_indices(mut self) -> Self {
363        self.remove_indices();
364        self
365    }
366
367    /// Returns the size of a vertex in bytes.
368    pub fn get_vertex_size(&self) -> u64 {
369        self.attributes
370            .values()
371            .map(|data| data.attribute.format.get_size())
372            .sum()
373    }
374
375    /// Returns the size required for the vertex buffer in bytes.
376    pub fn get_vertex_buffer_size(&self) -> usize {
377        let vertex_size = self.get_vertex_size() as usize;
378        let vertex_count = self.count_vertices();
379        vertex_count * vertex_size
380    }
381
382    /// Computes and returns the index data of the mesh as bytes.
383    /// This is used to transform the index data into a GPU friendly format.
384    pub fn get_index_buffer_bytes(&self) -> Option<&[u8]> {
385        self.indices.as_ref().map(|indices| match &indices {
386            Indices::U16(indices) => cast_slice(&indices[..]),
387            Indices::U32(indices) => cast_slice(&indices[..]),
388        })
389    }
390
391    /// Get this `Mesh`'s [`MeshVertexBufferLayout`], used in `SpecializedMeshPipeline`.
392    pub fn get_mesh_vertex_buffer_layout(
393        &self,
394        mesh_vertex_buffer_layouts: &mut MeshVertexBufferLayouts,
395    ) -> MeshVertexBufferLayoutRef {
396        let mut attributes = Vec::with_capacity(self.attributes.len());
397        let mut attribute_ids = Vec::with_capacity(self.attributes.len());
398        let mut accumulated_offset = 0;
399        for (index, data) in self.attributes.values().enumerate() {
400            attribute_ids.push(data.attribute.id);
401            attributes.push(VertexAttribute {
402                offset: accumulated_offset,
403                format: data.attribute.format,
404                shader_location: index as u32,
405            });
406            accumulated_offset += data.attribute.format.get_size();
407        }
408
409        let layout = MeshVertexBufferLayout {
410            layout: VertexBufferLayout {
411                array_stride: accumulated_offset,
412                step_mode: VertexStepMode::Vertex,
413                attributes,
414            },
415            attribute_ids,
416        };
417        mesh_vertex_buffer_layouts.insert(layout)
418    }
419
420    /// Counts all vertices of the mesh.
421    ///
422    /// If the attributes have different vertex counts, the smallest is returned.
423    pub fn count_vertices(&self) -> usize {
424        let mut vertex_count: Option<usize> = None;
425        for (attribute_id, attribute_data) in &self.attributes {
426            let attribute_len = attribute_data.values.len();
427            if let Some(previous_vertex_count) = vertex_count {
428                if previous_vertex_count != attribute_len {
429                    let name = self
430                        .attributes
431                        .get(attribute_id)
432                        .map(|data| data.attribute.name.to_string())
433                        .unwrap_or_else(|| format!("{attribute_id:?}"));
434
435                    warn!("{name} has a different vertex count ({attribute_len}) than other attributes ({previous_vertex_count}) in this mesh, \
436                        all attributes will be truncated to match the smallest.");
437                    vertex_count = Some(core::cmp::min(previous_vertex_count, attribute_len));
438                }
439            } else {
440                vertex_count = Some(attribute_len);
441            }
442        }
443
444        vertex_count.unwrap_or(0)
445    }
446
447    /// Computes and returns the vertex data of the mesh as bytes.
448    /// Therefore the attributes are located in the order of their [`MeshVertexAttribute::id`].
449    /// This is used to transform the vertex data into a GPU friendly format.
450    ///
451    /// If the vertex attributes have different lengths, they are all truncated to
452    /// the length of the smallest.
453    ///
454    /// This is a convenience method which allocates a Vec.
455    /// Prefer pre-allocating and using [`Mesh::write_packed_vertex_buffer_data`] when possible.
456    pub fn create_packed_vertex_buffer_data(&self) -> Vec<u8> {
457        let mut attributes_interleaved_buffer = vec![0; self.get_vertex_buffer_size()];
458        self.write_packed_vertex_buffer_data(&mut attributes_interleaved_buffer);
459        attributes_interleaved_buffer
460    }
461
462    /// Computes and write the vertex data of the mesh into a mutable byte slice.
463    /// The attributes are located in the order of their [`MeshVertexAttribute::id`].
464    /// This is used to transform the vertex data into a GPU friendly format.
465    ///
466    /// If the vertex attributes have different lengths, they are all truncated to
467    /// the length of the smallest.
468    pub fn write_packed_vertex_buffer_data(&self, slice: &mut [u8]) {
469        let vertex_size = self.get_vertex_size() as usize;
470        let vertex_count = self.count_vertices();
471        // bundle into interleaved buffers
472        let mut attribute_offset = 0;
473        for attribute_data in self.attributes.values() {
474            let attribute_size = attribute_data.attribute.format.get_size() as usize;
475            let attributes_bytes = attribute_data.values.get_bytes();
476            for (vertex_index, attribute_bytes) in attributes_bytes
477                .chunks_exact(attribute_size)
478                .take(vertex_count)
479                .enumerate()
480            {
481                let offset = vertex_index * vertex_size + attribute_offset;
482                slice[offset..offset + attribute_size].copy_from_slice(attribute_bytes);
483            }
484
485            attribute_offset += attribute_size;
486        }
487    }
488
489    /// Duplicates the vertex attributes so that no vertices are shared.
490    ///
491    /// This can dramatically increase the vertex count, so make sure this is what you want.
492    /// Does nothing if no [Indices] are set.
493    #[allow(clippy::match_same_arms)]
494    pub fn duplicate_vertices(&mut self) {
495        fn duplicate<T: Copy>(values: &[T], indices: impl Iterator<Item = usize>) -> Vec<T> {
496            indices.map(|i| values[i]).collect()
497        }
498
499        let Some(indices) = self.indices.take() else {
500            return;
501        };
502
503        for attributes in self.attributes.values_mut() {
504            let indices = indices.iter();
505            match &mut attributes.values {
506                VertexAttributeValues::Float32(vec) => *vec = duplicate(vec, indices),
507                VertexAttributeValues::Sint32(vec) => *vec = duplicate(vec, indices),
508                VertexAttributeValues::Uint32(vec) => *vec = duplicate(vec, indices),
509                VertexAttributeValues::Float32x2(vec) => *vec = duplicate(vec, indices),
510                VertexAttributeValues::Sint32x2(vec) => *vec = duplicate(vec, indices),
511                VertexAttributeValues::Uint32x2(vec) => *vec = duplicate(vec, indices),
512                VertexAttributeValues::Float32x3(vec) => *vec = duplicate(vec, indices),
513                VertexAttributeValues::Sint32x3(vec) => *vec = duplicate(vec, indices),
514                VertexAttributeValues::Uint32x3(vec) => *vec = duplicate(vec, indices),
515                VertexAttributeValues::Sint32x4(vec) => *vec = duplicate(vec, indices),
516                VertexAttributeValues::Uint32x4(vec) => *vec = duplicate(vec, indices),
517                VertexAttributeValues::Float32x4(vec) => *vec = duplicate(vec, indices),
518                VertexAttributeValues::Sint16x2(vec) => *vec = duplicate(vec, indices),
519                VertexAttributeValues::Snorm16x2(vec) => *vec = duplicate(vec, indices),
520                VertexAttributeValues::Uint16x2(vec) => *vec = duplicate(vec, indices),
521                VertexAttributeValues::Unorm16x2(vec) => *vec = duplicate(vec, indices),
522                VertexAttributeValues::Sint16x4(vec) => *vec = duplicate(vec, indices),
523                VertexAttributeValues::Snorm16x4(vec) => *vec = duplicate(vec, indices),
524                VertexAttributeValues::Uint16x4(vec) => *vec = duplicate(vec, indices),
525                VertexAttributeValues::Unorm16x4(vec) => *vec = duplicate(vec, indices),
526                VertexAttributeValues::Sint8x2(vec) => *vec = duplicate(vec, indices),
527                VertexAttributeValues::Snorm8x2(vec) => *vec = duplicate(vec, indices),
528                VertexAttributeValues::Uint8x2(vec) => *vec = duplicate(vec, indices),
529                VertexAttributeValues::Unorm8x2(vec) => *vec = duplicate(vec, indices),
530                VertexAttributeValues::Sint8x4(vec) => *vec = duplicate(vec, indices),
531                VertexAttributeValues::Snorm8x4(vec) => *vec = duplicate(vec, indices),
532                VertexAttributeValues::Uint8x4(vec) => *vec = duplicate(vec, indices),
533                VertexAttributeValues::Unorm8x4(vec) => *vec = duplicate(vec, indices),
534            }
535        }
536    }
537
538    /// Consumes the mesh and returns a mesh with no shared vertices.
539    ///
540    /// This can dramatically increase the vertex count, so make sure this is what you want.
541    /// Does nothing if no [`Indices`] are set.
542    ///
543    /// (Alternatively, you can use [`Mesh::duplicate_vertices`] to mutate an existing mesh in-place)
544    #[must_use]
545    pub fn with_duplicated_vertices(mut self) -> Self {
546        self.duplicate_vertices();
547        self
548    }
549
550    /// Inverts the winding of the indices such that all counter-clockwise triangles are now
551    /// clockwise and vice versa.
552    /// For lines, their start and end indices are flipped.
553    ///
554    /// Does nothing if no [`Indices`] are set.
555    /// If this operation succeeded, an [`Ok`] result is returned.
556    pub fn invert_winding(&mut self) -> Result<(), MeshWindingInvertError> {
557        fn invert<I>(
558            indices: &mut [I],
559            topology: PrimitiveTopology,
560        ) -> Result<(), MeshWindingInvertError> {
561            match topology {
562                PrimitiveTopology::TriangleList => {
563                    // Early return if the index count doesn't match
564                    if indices.len() % 3 != 0 {
565                        return Err(MeshWindingInvertError::AbruptIndicesEnd);
566                    }
567                    for chunk in indices.chunks_mut(3) {
568                        // This currently can only be optimized away with unsafe, rework this when `feature(slice_as_chunks)` gets stable.
569                        let [_, b, c] = chunk else {
570                            return Err(MeshWindingInvertError::AbruptIndicesEnd);
571                        };
572                        core::mem::swap(b, c);
573                    }
574                    Ok(())
575                }
576                PrimitiveTopology::LineList => {
577                    // Early return if the index count doesn't match
578                    if indices.len() % 2 != 0 {
579                        return Err(MeshWindingInvertError::AbruptIndicesEnd);
580                    }
581                    indices.reverse();
582                    Ok(())
583                }
584                PrimitiveTopology::TriangleStrip | PrimitiveTopology::LineStrip => {
585                    indices.reverse();
586                    Ok(())
587                }
588                _ => Err(MeshWindingInvertError::WrongTopology),
589            }
590        }
591        match &mut self.indices {
592            Some(Indices::U16(vec)) => invert(vec, self.primitive_topology),
593            Some(Indices::U32(vec)) => invert(vec, self.primitive_topology),
594            None => Ok(()),
595        }
596    }
597
598    /// Consumes the mesh and returns a mesh with inverted winding of the indices such
599    /// that all counter-clockwise triangles are now clockwise and vice versa.
600    ///
601    /// Does nothing if no [`Indices`] are set.
602    pub fn with_inverted_winding(mut self) -> Result<Self, MeshWindingInvertError> {
603        self.invert_winding().map(|_| self)
604    }
605
606    /// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of a mesh.
607    /// If the mesh is indexed, this defaults to smooth normals. Otherwise, it defaults to flat
608    /// normals.
609    ///
610    /// # Panics
611    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
612    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
613    ///
614    /// FIXME: This should handle more cases since this is called as a part of gltf
615    /// mesh loading where we can't really blame users for loading meshes that might
616    /// not conform to the limitations here!
617    pub fn compute_normals(&mut self) {
618        assert!(
619            matches!(self.primitive_topology, PrimitiveTopology::TriangleList),
620            "`compute_normals` can only work on `TriangleList`s"
621        );
622        if self.indices().is_none() {
623            self.compute_flat_normals();
624        } else {
625            self.compute_smooth_normals();
626        }
627    }
628
629    /// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of a mesh.
630    ///
631    /// # Panics
632    /// Panics if [`Indices`] are set or [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
633    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
634    /// Consider calling [`Mesh::duplicate_vertices`] or exporting your mesh with normal
635    /// attributes.
636    ///
637    /// FIXME: This should handle more cases since this is called as a part of gltf
638    /// mesh loading where we can't really blame users for loading meshes that might
639    /// not conform to the limitations here!
640    pub fn compute_flat_normals(&mut self) {
641        assert!(
642            self.indices().is_none(),
643            "`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`."
644        );
645        assert!(
646            matches!(self.primitive_topology, PrimitiveTopology::TriangleList),
647            "`compute_flat_normals` can only work on `TriangleList`s"
648        );
649
650        let positions = self
651            .attribute(Mesh::ATTRIBUTE_POSITION)
652            .unwrap()
653            .as_float3()
654            .expect("`Mesh::ATTRIBUTE_POSITION` vertex attributes should be of type `float3`");
655
656        let normals: Vec<_> = positions
657            .chunks_exact(3)
658            .map(|p| face_normal(p[0], p[1], p[2]))
659            .flat_map(|normal| [normal; 3])
660            .collect();
661
662        self.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals);
663    }
664
665    /// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of an indexed mesh, smoothing normals for shared
666    /// vertices.
667    ///
668    /// # Panics
669    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
670    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
671    /// Panics if the mesh does not have indices defined.
672    ///
673    /// FIXME: This should handle more cases since this is called as a part of gltf
674    /// mesh loading where we can't really blame users for loading meshes that might
675    /// not conform to the limitations here!
676    pub fn compute_smooth_normals(&mut self) {
677        assert!(
678            matches!(self.primitive_topology, PrimitiveTopology::TriangleList),
679            "`compute_smooth_normals` can only work on `TriangleList`s"
680        );
681        assert!(
682            self.indices().is_some(),
683            "`compute_smooth_normals` can only work on indexed meshes"
684        );
685
686        let positions = self
687            .attribute(Mesh::ATTRIBUTE_POSITION)
688            .unwrap()
689            .as_float3()
690            .expect("`Mesh::ATTRIBUTE_POSITION` vertex attributes should be of type `float3`");
691
692        let mut normals = vec![Vec3::ZERO; positions.len()];
693
694        self.indices()
695            .unwrap()
696            .iter()
697            .collect::<Vec<usize>>()
698            .chunks_exact(3)
699            .for_each(|face| {
700                let [a, b, c] = [face[0], face[1], face[2]];
701                let normal = Vec3::from(face_normal(positions[a], positions[b], positions[c]));
702                [a, b, c].iter().for_each(|pos| {
703                    normals[*pos] += normal;
704                });
705            });
706
707        // average (smooth) normals for shared vertices...
708        // TODO: support different methods of weighting the average
709        for normal in &mut normals {
710            *normal = normal.try_normalize().unwrap_or(Vec3::ZERO);
711        }
712
713        self.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals);
714    }
715
716    /// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
717    /// If the mesh is indexed, this defaults to smooth normals. Otherwise, it defaults to flat
718    /// normals.
719    ///
720    /// (Alternatively, you can use [`Mesh::compute_normals`] to mutate an existing mesh in-place)
721    ///
722    /// # Panics
723    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
724    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
725    #[must_use]
726    pub fn with_computed_normals(mut self) -> Self {
727        self.compute_normals();
728        self
729    }
730
731    /// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
732    ///
733    /// (Alternatively, you can use [`Mesh::compute_flat_normals`] to mutate an existing mesh in-place)
734    ///
735    /// # Panics
736    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
737    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
738    /// Panics if the mesh has indices defined
739    #[must_use]
740    pub fn with_computed_flat_normals(mut self) -> Self {
741        self.compute_flat_normals();
742        self
743    }
744
745    /// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
746    ///
747    /// (Alternatively, you can use [`Mesh::compute_smooth_normals`] to mutate an existing mesh in-place)
748    ///
749    /// # Panics
750    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
751    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
752    /// Panics if the mesh does not have indices defined.
753    #[must_use]
754    pub fn with_computed_smooth_normals(mut self) -> Self {
755        self.compute_smooth_normals();
756        self
757    }
758
759    /// Generate tangents for the mesh using the `mikktspace` algorithm.
760    ///
761    /// Sets the [`Mesh::ATTRIBUTE_TANGENT`] attribute if successful.
762    /// Requires a [`PrimitiveTopology::TriangleList`] topology and the [`Mesh::ATTRIBUTE_POSITION`], [`Mesh::ATTRIBUTE_NORMAL`] and [`Mesh::ATTRIBUTE_UV_0`] attributes set.
763    pub fn generate_tangents(&mut self) -> Result<(), GenerateTangentsError> {
764        let tangents = generate_tangents_for_mesh(self)?;
765        self.insert_attribute(Mesh::ATTRIBUTE_TANGENT, tangents);
766        Ok(())
767    }
768
769    /// Consumes the mesh and returns a mesh with tangents generated using the `mikktspace` algorithm.
770    ///
771    /// The resulting mesh will have the [`Mesh::ATTRIBUTE_TANGENT`] attribute if successful.
772    ///
773    /// (Alternatively, you can use [`Mesh::generate_tangents`] to mutate an existing mesh in-place)
774    ///
775    /// Requires a [`PrimitiveTopology::TriangleList`] topology and the [`Mesh::ATTRIBUTE_POSITION`], [`Mesh::ATTRIBUTE_NORMAL`] and [`Mesh::ATTRIBUTE_UV_0`] attributes set.
776    pub fn with_generated_tangents(mut self) -> Result<Mesh, GenerateTangentsError> {
777        self.generate_tangents()?;
778        Ok(self)
779    }
780
781    /// Merges the [`Mesh`] data of `other` with `self`. The attributes and indices of `other` will be appended to `self`.
782    ///
783    /// Note that attributes of `other` that don't exist on `self` will be ignored.
784    ///
785    /// `Aabb` of entities with modified mesh are not updated automatically.
786    ///
787    /// # Panics
788    ///
789    /// Panics if the vertex attribute values of `other` are incompatible with `self`.
790    /// For example, [`VertexAttributeValues::Float32`] is incompatible with [`VertexAttributeValues::Float32x3`].
791    #[allow(clippy::match_same_arms)]
792    pub fn merge(&mut self, other: &Mesh) {
793        use VertexAttributeValues::*;
794
795        // The indices of `other` should start after the last vertex of `self`.
796        let index_offset = self
797            .attribute(Mesh::ATTRIBUTE_POSITION)
798            .get_or_insert(&Float32x3(Vec::default()))
799            .len();
800
801        // Extend attributes of `self` with attributes of `other`.
802        for (attribute, values) in self.attributes_mut() {
803            let enum_variant_name = values.enum_variant_name();
804            if let Some(other_values) = other.attribute(attribute.id) {
805                match (values, other_values) {
806                    (Float32(vec1), Float32(vec2)) => vec1.extend(vec2),
807                    (Sint32(vec1), Sint32(vec2)) => vec1.extend(vec2),
808                    (Uint32(vec1), Uint32(vec2)) => vec1.extend(vec2),
809                    (Float32x2(vec1), Float32x2(vec2)) => vec1.extend(vec2),
810                    (Sint32x2(vec1), Sint32x2(vec2)) => vec1.extend(vec2),
811                    (Uint32x2(vec1), Uint32x2(vec2)) => vec1.extend(vec2),
812                    (Float32x3(vec1), Float32x3(vec2)) => vec1.extend(vec2),
813                    (Sint32x3(vec1), Sint32x3(vec2)) => vec1.extend(vec2),
814                    (Uint32x3(vec1), Uint32x3(vec2)) => vec1.extend(vec2),
815                    (Sint32x4(vec1), Sint32x4(vec2)) => vec1.extend(vec2),
816                    (Uint32x4(vec1), Uint32x4(vec2)) => vec1.extend(vec2),
817                    (Float32x4(vec1), Float32x4(vec2)) => vec1.extend(vec2),
818                    (Sint16x2(vec1), Sint16x2(vec2)) => vec1.extend(vec2),
819                    (Snorm16x2(vec1), Snorm16x2(vec2)) => vec1.extend(vec2),
820                    (Uint16x2(vec1), Uint16x2(vec2)) => vec1.extend(vec2),
821                    (Unorm16x2(vec1), Unorm16x2(vec2)) => vec1.extend(vec2),
822                    (Sint16x4(vec1), Sint16x4(vec2)) => vec1.extend(vec2),
823                    (Snorm16x4(vec1), Snorm16x4(vec2)) => vec1.extend(vec2),
824                    (Uint16x4(vec1), Uint16x4(vec2)) => vec1.extend(vec2),
825                    (Unorm16x4(vec1), Unorm16x4(vec2)) => vec1.extend(vec2),
826                    (Sint8x2(vec1), Sint8x2(vec2)) => vec1.extend(vec2),
827                    (Snorm8x2(vec1), Snorm8x2(vec2)) => vec1.extend(vec2),
828                    (Uint8x2(vec1), Uint8x2(vec2)) => vec1.extend(vec2),
829                    (Unorm8x2(vec1), Unorm8x2(vec2)) => vec1.extend(vec2),
830                    (Sint8x4(vec1), Sint8x4(vec2)) => vec1.extend(vec2),
831                    (Snorm8x4(vec1), Snorm8x4(vec2)) => vec1.extend(vec2),
832                    (Uint8x4(vec1), Uint8x4(vec2)) => vec1.extend(vec2),
833                    (Unorm8x4(vec1), Unorm8x4(vec2)) => vec1.extend(vec2),
834                    _ => panic!(
835                        "Incompatible vertex attribute types {} and {}",
836                        enum_variant_name,
837                        other_values.enum_variant_name()
838                    ),
839                }
840            }
841        }
842
843        // Extend indices of `self` with indices of `other`.
844        if let (Some(indices), Some(other_indices)) = (self.indices_mut(), other.indices()) {
845            match (indices, other_indices) {
846                (Indices::U16(i1), Indices::U16(i2)) => {
847                    i1.extend(i2.iter().map(|i| *i + index_offset as u16));
848                }
849                (Indices::U32(i1), Indices::U32(i2)) => {
850                    i1.extend(i2.iter().map(|i| *i + index_offset as u32));
851                }
852                (Indices::U16(i1), Indices::U32(i2)) => {
853                    i1.extend(i2.iter().map(|i| *i as u16 + index_offset as u16));
854                }
855                (Indices::U32(i1), Indices::U16(i2)) => {
856                    i1.extend(i2.iter().map(|i| *i as u32 + index_offset as u32));
857                }
858            }
859        }
860    }
861
862    /// Transforms the vertex positions, normals, and tangents of the mesh by the given [`Transform`].
863    ///
864    /// `Aabb` of entities with modified mesh are not updated automatically.
865    pub fn transformed_by(mut self, transform: Transform) -> Self {
866        self.transform_by(transform);
867        self
868    }
869
870    /// Transforms the vertex positions, normals, and tangents of the mesh in place by the given [`Transform`].
871    ///
872    /// `Aabb` of entities with modified mesh are not updated automatically.
873    pub fn transform_by(&mut self, transform: Transform) {
874        // Needed when transforming normals and tangents
875        let scale_recip = 1. / transform.scale;
876        debug_assert!(
877            transform.scale.yzx() * transform.scale.zxy() != Vec3::ZERO,
878            "mesh transform scale cannot be zero on more than one axis"
879        );
880
881        if let Some(VertexAttributeValues::Float32x3(ref mut positions)) =
882            self.attribute_mut(Mesh::ATTRIBUTE_POSITION)
883        {
884            // Apply scale, rotation, and translation to vertex positions
885            positions
886                .iter_mut()
887                .for_each(|pos| *pos = transform.transform_point(Vec3::from_slice(pos)).to_array());
888        }
889
890        // No need to transform normals or tangents if rotation is near identity and scale is uniform
891        if transform.rotation.is_near_identity()
892            && transform.scale.x == transform.scale.y
893            && transform.scale.y == transform.scale.z
894        {
895            return;
896        }
897
898        if let Some(VertexAttributeValues::Float32x3(ref mut normals)) =
899            self.attribute_mut(Mesh::ATTRIBUTE_NORMAL)
900        {
901            // Transform normals, taking into account non-uniform scaling and rotation
902            normals.iter_mut().for_each(|normal| {
903                *normal = (transform.rotation
904                    * scale_normal(Vec3::from_array(*normal), scale_recip))
905                .to_array();
906            });
907        }
908
909        if let Some(VertexAttributeValues::Float32x3(ref mut tangents)) =
910            self.attribute_mut(Mesh::ATTRIBUTE_TANGENT)
911        {
912            // Transform tangents, taking into account non-uniform scaling and rotation
913            tangents.iter_mut().for_each(|tangent| {
914                let scaled_tangent = Vec3::from_slice(tangent) * transform.scale;
915                *tangent = (transform.rotation * scaled_tangent.normalize_or_zero()).to_array();
916            });
917        }
918    }
919
920    /// Translates the vertex positions of the mesh by the given [`Vec3`].
921    ///
922    /// `Aabb` of entities with modified mesh are not updated automatically.
923    pub fn translated_by(mut self, translation: Vec3) -> Self {
924        self.translate_by(translation);
925        self
926    }
927
928    /// Translates the vertex positions of the mesh in place by the given [`Vec3`].
929    ///
930    /// `Aabb` of entities with modified mesh are not updated automatically.
931    pub fn translate_by(&mut self, translation: Vec3) {
932        if translation == Vec3::ZERO {
933            return;
934        }
935
936        if let Some(VertexAttributeValues::Float32x3(ref mut positions)) =
937            self.attribute_mut(Mesh::ATTRIBUTE_POSITION)
938        {
939            // Apply translation to vertex positions
940            positions
941                .iter_mut()
942                .for_each(|pos| *pos = (Vec3::from_slice(pos) + translation).to_array());
943        }
944    }
945
946    /// Rotates the vertex positions, normals, and tangents of the mesh by the given [`Quat`].
947    ///
948    /// `Aabb` of entities with modified mesh are not updated automatically.
949    pub fn rotated_by(mut self, rotation: Quat) -> Self {
950        self.rotate_by(rotation);
951        self
952    }
953
954    /// Rotates the vertex positions, normals, and tangents of the mesh in place by the given [`Quat`].
955    ///
956    /// `Aabb` of entities with modified mesh are not updated automatically.
957    pub fn rotate_by(&mut self, rotation: Quat) {
958        if let Some(VertexAttributeValues::Float32x3(ref mut positions)) =
959            self.attribute_mut(Mesh::ATTRIBUTE_POSITION)
960        {
961            // Apply rotation to vertex positions
962            positions
963                .iter_mut()
964                .for_each(|pos| *pos = (rotation * Vec3::from_slice(pos)).to_array());
965        }
966
967        // No need to transform normals or tangents if rotation is near identity
968        if rotation.is_near_identity() {
969            return;
970        }
971
972        if let Some(VertexAttributeValues::Float32x3(ref mut normals)) =
973            self.attribute_mut(Mesh::ATTRIBUTE_NORMAL)
974        {
975            // Transform normals
976            normals.iter_mut().for_each(|normal| {
977                *normal = (rotation * Vec3::from_slice(normal).normalize_or_zero()).to_array();
978            });
979        }
980
981        if let Some(VertexAttributeValues::Float32x3(ref mut tangents)) =
982            self.attribute_mut(Mesh::ATTRIBUTE_TANGENT)
983        {
984            // Transform tangents
985            tangents.iter_mut().for_each(|tangent| {
986                *tangent = (rotation * Vec3::from_slice(tangent).normalize_or_zero()).to_array();
987            });
988        }
989    }
990
991    /// Scales the vertex positions, normals, and tangents of the mesh by the given [`Vec3`].
992    ///
993    /// `Aabb` of entities with modified mesh are not updated automatically.
994    pub fn scaled_by(mut self, scale: Vec3) -> Self {
995        self.scale_by(scale);
996        self
997    }
998
999    /// Scales the vertex positions, normals, and tangents of the mesh in place by the given [`Vec3`].
1000    ///
1001    /// `Aabb` of entities with modified mesh are not updated automatically.
1002    pub fn scale_by(&mut self, scale: Vec3) {
1003        // Needed when transforming normals and tangents
1004        let scale_recip = 1. / scale;
1005        debug_assert!(
1006            scale.yzx() * scale.zxy() != Vec3::ZERO,
1007            "mesh transform scale cannot be zero on more than one axis"
1008        );
1009
1010        if let Some(VertexAttributeValues::Float32x3(ref mut positions)) =
1011            self.attribute_mut(Mesh::ATTRIBUTE_POSITION)
1012        {
1013            // Apply scale to vertex positions
1014            positions
1015                .iter_mut()
1016                .for_each(|pos| *pos = (scale * Vec3::from_slice(pos)).to_array());
1017        }
1018
1019        // No need to transform normals or tangents if scale is uniform
1020        if scale.x == scale.y && scale.y == scale.z {
1021            return;
1022        }
1023
1024        if let Some(VertexAttributeValues::Float32x3(ref mut normals)) =
1025            self.attribute_mut(Mesh::ATTRIBUTE_NORMAL)
1026        {
1027            // Transform normals, taking into account non-uniform scaling
1028            normals.iter_mut().for_each(|normal| {
1029                *normal = scale_normal(Vec3::from_array(*normal), scale_recip).to_array();
1030            });
1031        }
1032
1033        if let Some(VertexAttributeValues::Float32x3(ref mut tangents)) =
1034            self.attribute_mut(Mesh::ATTRIBUTE_TANGENT)
1035        {
1036            // Transform tangents, taking into account non-uniform scaling
1037            tangents.iter_mut().for_each(|tangent| {
1038                let scaled_tangent = Vec3::from_slice(tangent) * scale;
1039                *tangent = scaled_tangent.normalize_or_zero().to_array();
1040            });
1041        }
1042    }
1043
1044    /// Whether this mesh has morph targets.
1045    pub fn has_morph_targets(&self) -> bool {
1046        self.morph_targets.is_some()
1047    }
1048
1049    /// Set [morph targets] image for this mesh. This requires a "morph target image". See [`MorphTargetImage`](crate::morph::MorphTargetImage) for info.
1050    ///
1051    /// [morph targets]: https://en.wikipedia.org/wiki/Morph_target_animation
1052    pub fn set_morph_targets(&mut self, morph_targets: Handle<Image>) {
1053        self.morph_targets = Some(morph_targets);
1054    }
1055
1056    pub fn morph_targets(&self) -> Option<&Handle<Image>> {
1057        self.morph_targets.as_ref()
1058    }
1059
1060    /// Consumes the mesh and returns a mesh with the given [morph targets].
1061    ///
1062    /// This requires a "morph target image". See [`MorphTargetImage`](crate::morph::MorphTargetImage) for info.
1063    ///
1064    /// (Alternatively, you can use [`Mesh::set_morph_targets`] to mutate an existing mesh in-place)
1065    ///
1066    /// [morph targets]: https://en.wikipedia.org/wiki/Morph_target_animation
1067    #[must_use]
1068    pub fn with_morph_targets(mut self, morph_targets: Handle<Image>) -> Self {
1069        self.set_morph_targets(morph_targets);
1070        self
1071    }
1072
1073    /// Sets the names of each morph target. This should correspond to the order of the morph targets in `set_morph_targets`.
1074    pub fn set_morph_target_names(&mut self, names: Vec<String>) {
1075        self.morph_target_names = Some(names);
1076    }
1077
1078    /// Consumes the mesh and returns a mesh with morph target names.
1079    /// Names should correspond to the order of the morph targets in `set_morph_targets`.
1080    ///
1081    /// (Alternatively, you can use [`Mesh::set_morph_target_names`] to mutate an existing mesh in-place)
1082    #[must_use]
1083    pub fn with_morph_target_names(mut self, names: Vec<String>) -> Self {
1084        self.set_morph_target_names(names);
1085        self
1086    }
1087
1088    /// Gets a list of all morph target names, if they exist.
1089    pub fn morph_target_names(&self) -> Option<&[String]> {
1090        self.morph_target_names.as_deref()
1091    }
1092
1093    /// Normalize joint weights so they sum to 1.
1094    pub fn normalize_joint_weights(&mut self) {
1095        if let Some(joints) = self.attribute_mut(Self::ATTRIBUTE_JOINT_WEIGHT) {
1096            let VertexAttributeValues::Float32x4(ref mut joints) = joints else {
1097                panic!("unexpected joint weight format");
1098            };
1099
1100            for weights in joints.iter_mut() {
1101                // force negative weights to zero
1102                weights.iter_mut().for_each(|w| *w = w.max(0.0));
1103
1104                let sum: f32 = weights.iter().sum();
1105                if sum == 0.0 {
1106                    // all-zero weights are invalid
1107                    weights[0] = 1.0;
1108                } else {
1109                    let recip = sum.recip();
1110                    for weight in weights.iter_mut() {
1111                        *weight *= recip;
1112                    }
1113                }
1114            }
1115        }
1116    }
1117
1118    /// Get a list of this Mesh's [triangles] as an iterator if possible.
1119    ///
1120    /// Returns an error if any of the following conditions are met (see [`MeshTrianglesError`]):
1121    /// * The Mesh's [primitive topology] is not `TriangleList` or `TriangleStrip`.
1122    /// * The Mesh is missing position or index data.
1123    /// * The Mesh's position data has the wrong format (not `Float32x3`).
1124    ///
1125    /// [primitive topology]: PrimitiveTopology
1126    /// [triangles]: Triangle3d
1127    pub fn triangles(&self) -> Result<impl Iterator<Item = Triangle3d> + '_, MeshTrianglesError> {
1128        let Some(position_data) = self.attribute(Mesh::ATTRIBUTE_POSITION) else {
1129            return Err(MeshTrianglesError::MissingPositions);
1130        };
1131
1132        let Some(vertices) = position_data.as_float3() else {
1133            return Err(MeshTrianglesError::PositionsFormat);
1134        };
1135
1136        let Some(indices) = self.indices() else {
1137            return Err(MeshTrianglesError::MissingIndices);
1138        };
1139
1140        match self.primitive_topology {
1141            PrimitiveTopology::TriangleList => {
1142                // When indices reference out-of-bounds vertex data, the triangle is omitted.
1143                // This implicitly truncates the indices to a multiple of 3.
1144                let iterator = match indices {
1145                    Indices::U16(vec) => FourIterators::First(
1146                        vec.as_slice()
1147                            .chunks_exact(3)
1148                            .flat_map(move |indices| indices_to_triangle(vertices, indices)),
1149                    ),
1150                    Indices::U32(vec) => FourIterators::Second(
1151                        vec.as_slice()
1152                            .chunks_exact(3)
1153                            .flat_map(move |indices| indices_to_triangle(vertices, indices)),
1154                    ),
1155                };
1156
1157                return Ok(iterator);
1158            }
1159
1160            PrimitiveTopology::TriangleStrip => {
1161                // When indices reference out-of-bounds vertex data, the triangle is omitted.
1162                // If there aren't enough indices to make a triangle, then an empty vector will be
1163                // returned.
1164                let iterator = match indices {
1165                    Indices::U16(vec) => {
1166                        FourIterators::Third(vec.as_slice().windows(3).enumerate().flat_map(
1167                            move |(i, indices)| {
1168                                if i % 2 == 0 {
1169                                    indices_to_triangle(vertices, indices)
1170                                } else {
1171                                    indices_to_triangle(
1172                                        vertices,
1173                                        &[indices[1], indices[0], indices[2]],
1174                                    )
1175                                }
1176                            },
1177                        ))
1178                    }
1179                    Indices::U32(vec) => {
1180                        FourIterators::Fourth(vec.as_slice().windows(3).enumerate().flat_map(
1181                            move |(i, indices)| {
1182                                if i % 2 == 0 {
1183                                    indices_to_triangle(vertices, indices)
1184                                } else {
1185                                    indices_to_triangle(
1186                                        vertices,
1187                                        &[indices[1], indices[0], indices[2]],
1188                                    )
1189                                }
1190                            },
1191                        ))
1192                    }
1193                };
1194
1195                return Ok(iterator);
1196            }
1197
1198            _ => {
1199                return Err(MeshTrianglesError::WrongTopology);
1200            }
1201        };
1202
1203        fn indices_to_triangle<T: TryInto<usize> + Copy>(
1204            vertices: &[[f32; 3]],
1205            indices: &[T],
1206        ) -> Option<Triangle3d> {
1207            let vert0: Vec3 = Vec3::from(*vertices.get(indices[0].try_into().ok()?)?);
1208            let vert1: Vec3 = Vec3::from(*vertices.get(indices[1].try_into().ok()?)?);
1209            let vert2: Vec3 = Vec3::from(*vertices.get(indices[2].try_into().ok()?)?);
1210            Some(Triangle3d {
1211                vertices: [vert0, vert1, vert2],
1212            })
1213        }
1214    }
1215}
1216
1217impl core::ops::Mul<Mesh> for Transform {
1218    type Output = Mesh;
1219
1220    fn mul(self, rhs: Mesh) -> Self::Output {
1221        rhs.transformed_by(self)
1222    }
1223}
1224
1225#[cfg(test)]
1226mod tests {
1227    use super::Mesh;
1228    use crate::mesh::{Indices, MeshWindingInvertError, VertexAttributeValues};
1229    use bevy_asset::RenderAssetUsages;
1230    use bevy_math::primitives::Triangle3d;
1231    use bevy_math::Vec3;
1232    use bevy_transform::components::Transform;
1233    use wgpu::PrimitiveTopology;
1234
1235    #[test]
1236    #[should_panic]
1237    fn panic_invalid_format() {
1238        let _mesh = Mesh::new(
1239            PrimitiveTopology::TriangleList,
1240            RenderAssetUsages::default(),
1241        )
1242        .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, vec![[0.0, 0.0, 0.0]]);
1243    }
1244
1245    #[test]
1246    fn transform_mesh() {
1247        let mesh = Mesh::new(
1248            PrimitiveTopology::TriangleList,
1249            RenderAssetUsages::default(),
1250        )
1251        .with_inserted_attribute(
1252            Mesh::ATTRIBUTE_POSITION,
1253            vec![[-1., -1., 2.], [1., -1., 2.], [0., 1., 2.]],
1254        )
1255        .with_inserted_attribute(
1256            Mesh::ATTRIBUTE_NORMAL,
1257            vec![
1258                Vec3::new(-1., -1., 1.).normalize().to_array(),
1259                Vec3::new(1., -1., 1.).normalize().to_array(),
1260                [0., 0., 1.],
1261            ],
1262        )
1263        .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, vec![[0., 0.], [1., 0.], [0.5, 1.]]);
1264
1265        let mesh = mesh.transformed_by(
1266            Transform::from_translation(Vec3::splat(-2.)).with_scale(Vec3::new(2., 0., -1.)),
1267        );
1268
1269        if let Some(VertexAttributeValues::Float32x3(positions)) =
1270            mesh.attribute(Mesh::ATTRIBUTE_POSITION)
1271        {
1272            // All positions are first scaled resulting in `vec![[-2, 0., -2.], [2., 0., -2.], [0., 0., -2.]]`
1273            // and then shifted by `-2.` along each axis
1274            assert_eq!(
1275                positions,
1276                &vec![[-4.0, -2.0, -4.0], [0.0, -2.0, -4.0], [-2.0, -2.0, -4.0]]
1277            );
1278        } else {
1279            panic!("Mesh does not have a position attribute");
1280        }
1281
1282        if let Some(VertexAttributeValues::Float32x3(normals)) =
1283            mesh.attribute(Mesh::ATTRIBUTE_NORMAL)
1284        {
1285            assert_eq!(normals, &vec![[0., -1., 0.], [0., -1., 0.], [0., 0., -1.]]);
1286        } else {
1287            panic!("Mesh does not have a normal attribute");
1288        }
1289
1290        if let Some(VertexAttributeValues::Float32x2(uvs)) = mesh.attribute(Mesh::ATTRIBUTE_UV_0) {
1291            assert_eq!(uvs, &vec![[0., 0.], [1., 0.], [0.5, 1.]]);
1292        } else {
1293            panic!("Mesh does not have a uv attribute");
1294        }
1295    }
1296
1297    #[test]
1298    fn point_list_mesh_invert_winding() {
1299        let mesh = Mesh::new(PrimitiveTopology::PointList, RenderAssetUsages::default())
1300            .with_inserted_indices(Indices::U32(vec![]));
1301        assert!(matches!(
1302            mesh.with_inverted_winding(),
1303            Err(MeshWindingInvertError::WrongTopology)
1304        ));
1305    }
1306
1307    #[test]
1308    fn line_list_mesh_invert_winding() {
1309        let mesh = Mesh::new(PrimitiveTopology::LineList, RenderAssetUsages::default())
1310            .with_inserted_indices(Indices::U32(vec![0, 1, 1, 2, 2, 3]));
1311        let mesh = mesh.with_inverted_winding().unwrap();
1312        assert_eq!(
1313            mesh.indices().unwrap().iter().collect::<Vec<usize>>(),
1314            vec![3, 2, 2, 1, 1, 0]
1315        );
1316    }
1317
1318    #[test]
1319    fn line_list_mesh_invert_winding_fail() {
1320        let mesh = Mesh::new(PrimitiveTopology::LineList, RenderAssetUsages::default())
1321            .with_inserted_indices(Indices::U32(vec![0, 1, 1]));
1322        assert!(matches!(
1323            mesh.with_inverted_winding(),
1324            Err(MeshWindingInvertError::AbruptIndicesEnd)
1325        ));
1326    }
1327
1328    #[test]
1329    fn line_strip_mesh_invert_winding() {
1330        let mesh = Mesh::new(PrimitiveTopology::LineStrip, RenderAssetUsages::default())
1331            .with_inserted_indices(Indices::U32(vec![0, 1, 2, 3]));
1332        let mesh = mesh.with_inverted_winding().unwrap();
1333        assert_eq!(
1334            mesh.indices().unwrap().iter().collect::<Vec<usize>>(),
1335            vec![3, 2, 1, 0]
1336        );
1337    }
1338
1339    #[test]
1340    fn triangle_list_mesh_invert_winding() {
1341        let mesh = Mesh::new(
1342            PrimitiveTopology::TriangleList,
1343            RenderAssetUsages::default(),
1344        )
1345        .with_inserted_indices(Indices::U32(vec![
1346            0, 3, 1, // First triangle
1347            1, 3, 2, // Second triangle
1348        ]));
1349        let mesh = mesh.with_inverted_winding().unwrap();
1350        assert_eq!(
1351            mesh.indices().unwrap().iter().collect::<Vec<usize>>(),
1352            vec![
1353                0, 1, 3, // First triangle
1354                1, 2, 3, // Second triangle
1355            ]
1356        );
1357    }
1358
1359    #[test]
1360    fn triangle_list_mesh_invert_winding_fail() {
1361        let mesh = Mesh::new(
1362            PrimitiveTopology::TriangleList,
1363            RenderAssetUsages::default(),
1364        )
1365        .with_inserted_indices(Indices::U32(vec![0, 3, 1, 2]));
1366        assert!(matches!(
1367            mesh.with_inverted_winding(),
1368            Err(MeshWindingInvertError::AbruptIndicesEnd)
1369        ));
1370    }
1371
1372    #[test]
1373    fn triangle_strip_mesh_invert_winding() {
1374        let mesh = Mesh::new(
1375            PrimitiveTopology::TriangleStrip,
1376            RenderAssetUsages::default(),
1377        )
1378        .with_inserted_indices(Indices::U32(vec![0, 1, 2, 3]));
1379        let mesh = mesh.with_inverted_winding().unwrap();
1380        assert_eq!(
1381            mesh.indices().unwrap().iter().collect::<Vec<usize>>(),
1382            vec![3, 2, 1, 0]
1383        );
1384    }
1385
1386    #[test]
1387    fn compute_smooth_normals() {
1388        let mut mesh = Mesh::new(
1389            PrimitiveTopology::TriangleList,
1390            RenderAssetUsages::default(),
1391        );
1392
1393        //  z      y
1394        //  |    /
1395        //  3---2
1396        //  | /  \
1397        //  0-----1--x
1398
1399        mesh.insert_attribute(
1400            Mesh::ATTRIBUTE_POSITION,
1401            vec![[0., 0., 0.], [1., 0., 0.], [0., 1., 0.], [0., 0., 1.]],
1402        );
1403        mesh.insert_indices(Indices::U16(vec![0, 1, 2, 0, 2, 3]));
1404        mesh.compute_smooth_normals();
1405        let normals = mesh
1406            .attribute(Mesh::ATTRIBUTE_NORMAL)
1407            .unwrap()
1408            .as_float3()
1409            .unwrap();
1410        assert_eq!(4, normals.len());
1411        // 0
1412        assert_eq!(Vec3::new(1., 0., 1.).normalize().to_array(), normals[0]);
1413        // 1
1414        assert_eq!([0., 0., 1.], normals[1]);
1415        // 2
1416        assert_eq!(Vec3::new(1., 0., 1.).normalize().to_array(), normals[2]);
1417        // 3
1418        assert_eq!([1., 0., 0.], normals[3]);
1419    }
1420
1421    #[test]
1422    fn triangles_from_triangle_list() {
1423        let mut mesh = Mesh::new(
1424            PrimitiveTopology::TriangleList,
1425            RenderAssetUsages::default(),
1426        );
1427        mesh.insert_attribute(
1428            Mesh::ATTRIBUTE_POSITION,
1429            vec![[0., 0., 0.], [1., 0., 0.], [1., 1., 0.], [0., 1., 0.]],
1430        );
1431        mesh.insert_indices(Indices::U32(vec![0, 1, 2, 2, 3, 0]));
1432        assert_eq!(
1433            vec![
1434                Triangle3d {
1435                    vertices: [
1436                        Vec3::new(0., 0., 0.),
1437                        Vec3::new(1., 0., 0.),
1438                        Vec3::new(1., 1., 0.),
1439                    ]
1440                },
1441                Triangle3d {
1442                    vertices: [
1443                        Vec3::new(1., 1., 0.),
1444                        Vec3::new(0., 1., 0.),
1445                        Vec3::new(0., 0., 0.),
1446                    ]
1447                }
1448            ],
1449            mesh.triangles().unwrap().collect::<Vec<Triangle3d>>()
1450        );
1451    }
1452
1453    #[test]
1454    fn triangles_from_triangle_strip() {
1455        let mut mesh = Mesh::new(
1456            PrimitiveTopology::TriangleStrip,
1457            RenderAssetUsages::default(),
1458        );
1459        // Triangles: (0, 1, 2), (2, 1, 3), (2, 3, 4), (4, 3, 5)
1460        //
1461        // 4 - 5
1462        // | \ |
1463        // 2 - 3
1464        // | \ |
1465        // 0 - 1
1466        let positions: Vec<Vec3> = [
1467            [0., 0., 0.],
1468            [1., 0., 0.],
1469            [0., 1., 0.],
1470            [1., 1., 0.],
1471            [0., 2., 0.],
1472            [1., 2., 0.],
1473        ]
1474        .into_iter()
1475        .map(Vec3::from_array)
1476        .collect();
1477        mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions.clone());
1478        mesh.insert_indices(Indices::U32(vec![0, 1, 2, 3, 4, 5]));
1479        assert_eq!(
1480            vec![
1481                Triangle3d {
1482                    vertices: [positions[0], positions[1], positions[2]]
1483                },
1484                Triangle3d {
1485                    vertices: [positions[2], positions[1], positions[3]]
1486                },
1487                Triangle3d {
1488                    vertices: [positions[2], positions[3], positions[4]]
1489                },
1490                Triangle3d {
1491                    vertices: [positions[4], positions[3], positions[5]]
1492                },
1493            ],
1494            mesh.triangles().unwrap().collect::<Vec<Triangle3d>>()
1495        );
1496    }
1497}