bevy_mesh/
mesh.rs

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