bevy_mesh/
mesh.rs

1use bevy_transform::components::Transform;
2pub use wgpu_types::PrimitiveTopology;
3
4use super::{
5    generate_tangents_for_mesh, scale_normal, triangle_area_normal, triangle_normal, FourIterators,
6    GenerateTangentsError, Indices, MeshAttributeData, MeshTrianglesError, MeshVertexAttribute,
7    MeshVertexAttributeId, MeshVertexBufferLayout, MeshVertexBufferLayoutRef,
8    MeshVertexBufferLayouts, MeshWindingInvertError, VertexAttributeValues, VertexBufferLayout,
9};
10#[cfg(feature = "serialize")]
11use crate::SerializedMeshAttributeData;
12use alloc::collections::BTreeMap;
13use bevy_asset::{Asset, Handle, RenderAssetUsages};
14use bevy_image::Image;
15use bevy_math::{primitives::Triangle3d, *};
16#[cfg(feature = "serialize")]
17use bevy_platform::collections::HashMap;
18use bevy_reflect::Reflect;
19use bytemuck::cast_slice;
20#[cfg(feature = "serialize")]
21use serde::{Deserialize, Serialize};
22use thiserror::Error;
23use tracing::warn;
24use wgpu_types::{VertexAttribute, VertexFormat, VertexStepMode};
25
26pub const INDEX_BUFFER_ASSET_INDEX: u64 = 0;
27pub const VERTEX_ATTRIBUTE_BUFFER_ID: u64 = 10;
28
29/// A 3D object made out of vertices representing triangles, lines, or points,
30/// with "attribute" values for each vertex.
31///
32/// Meshes can be automatically generated by a bevy `AssetLoader` (generally by loading a `Gltf` file),
33/// or by converting a [primitive](bevy_math::primitives) using [`into`](Into).
34/// It is also possible to create one manually. They can be edited after creation.
35///
36/// Meshes can be rendered with a [`Mesh2d`](crate::Mesh2d) and `MeshMaterial2d`
37/// or [`Mesh3d`](crate::Mesh3d) and `MeshMaterial3d` for 2D and 3D respectively.
38///
39/// A [`Mesh`] in Bevy is equivalent to a "primitive" in the glTF format, for a
40/// glTF Mesh representation, see `GltfMesh`.
41///
42/// ## Manual creation
43///
44/// The following function will construct a flat mesh, to be rendered with a
45/// `StandardMaterial` or `ColorMaterial`:
46///
47/// ```
48/// # use bevy_mesh::{Mesh, Indices, PrimitiveTopology};
49/// # use bevy_asset::RenderAssetUsages;
50/// fn create_simple_parallelogram() -> Mesh {
51///     // Create a new mesh using a triangle list topology, where each set of 3 vertices composes a triangle.
52///     Mesh::new(PrimitiveTopology::TriangleList, RenderAssetUsages::default())
53///         // Add 4 vertices, each with its own position attribute (coordinate in
54///         // 3D space), for each of the corners of the parallelogram.
55///         .with_inserted_attribute(
56///             Mesh::ATTRIBUTE_POSITION,
57///             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]]
58///         )
59///         // Assign a UV coordinate to each vertex.
60///         .with_inserted_attribute(
61///             Mesh::ATTRIBUTE_UV_0,
62///             vec![[0.0, 1.0], [0.5, 0.0], [1.0, 0.0], [0.5, 1.0]]
63///         )
64///         // Assign normals (everything points outwards)
65///         .with_inserted_attribute(
66///             Mesh::ATTRIBUTE_NORMAL,
67///             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]]
68///         )
69///         // After defining all the vertices and their attributes, build each triangle using the
70///         // indices of the vertices that make it up in a counter-clockwise order.
71///         .with_inserted_indices(Indices::U32(vec![
72///             // First triangle
73///             0, 3, 1,
74///             // Second triangle
75///             1, 3, 2
76///         ]))
77/// }
78/// ```
79///
80/// You can see how it looks like [here](https://github.com/bevyengine/bevy/blob/main/assets/docs/Mesh.png),
81/// used in a [`Mesh3d`](crate::Mesh3d) with a square bevy logo texture, with added axis, points,
82/// lines and text for clarity.
83///
84/// ## Other examples
85///
86/// For further visualization, explanation, and examples, see the built-in Bevy examples,
87/// and the [implementation of the built-in shapes](https://github.com/bevyengine/bevy/tree/main/crates/bevy_mesh/src/primitives).
88/// In particular, [generate_custom_mesh](https://github.com/bevyengine/bevy/blob/main/examples/3d/generate_custom_mesh.rs)
89/// teaches you to access and modify the attributes of a [`Mesh`] after creating it.
90///
91/// ## Common points of confusion
92///
93/// - UV maps in Bevy start at the top-left, see [`ATTRIBUTE_UV_0`](Mesh::ATTRIBUTE_UV_0),
94///   other APIs can have other conventions, `OpenGL` starts at bottom-left.
95/// - It is possible and sometimes useful for multiple vertices to have the same
96///   [position attribute](Mesh::ATTRIBUTE_POSITION) value,
97///   it's a common technique in 3D modeling for complex UV mapping or other calculations.
98/// - Bevy performs frustum culling based on the `Aabb` of meshes, which is calculated
99///   and added automatically for new meshes only. If a mesh is modified, the entity's `Aabb`
100///   needs to be updated manually or deleted so that it is re-calculated.
101///
102/// ## Use with `StandardMaterial`
103///
104/// To render correctly with `StandardMaterial`, a mesh needs to have properly defined:
105/// - [`UVs`](Mesh::ATTRIBUTE_UV_0): Bevy needs to know how to map a texture onto the mesh
106///   (also true for `ColorMaterial`).
107/// - [`Normals`](Mesh::ATTRIBUTE_NORMAL): Bevy needs to know how light interacts with your mesh.
108///   [0.0, 0.0, 1.0] is very common for simple flat meshes on the XY plane,
109///   because simple meshes are smooth and they don't require complex light calculations.
110/// - Vertex winding order: by default, `StandardMaterial.cull_mode` is `Some(Face::Back)`,
111///   which means that Bevy would *only* render the "front" of each triangle, which
112///   is the side of the triangle from where the vertices appear in a *counter-clockwise* order.
113///
114/// ## Remote Inspection
115///
116/// To transmit a [`Mesh`] between two running Bevy apps, e.g. through BRP, use [`SerializedMesh`].
117/// This type is only meant for short-term transmission between same versions and should not be stored anywhere.
118#[derive(Asset, Debug, Clone, Reflect, PartialEq)]
119#[reflect(Clone)]
120pub struct Mesh {
121    #[reflect(ignore, clone)]
122    primitive_topology: PrimitiveTopology,
123    /// `std::collections::BTreeMap` with all defined vertex attributes (Positions, Normals, ...)
124    /// for this mesh. Attribute ids to attribute values.
125    /// Uses a [`BTreeMap`] because, unlike `HashMap`, it has a defined iteration order,
126    /// which allows easy stable `VertexBuffers` (i.e. same buffer order)
127    #[reflect(ignore, clone)]
128    attributes: BTreeMap<MeshVertexAttributeId, MeshAttributeData>,
129    indices: Option<Indices>,
130    morph_targets: Option<Handle<Image>>,
131    morph_target_names: Option<Vec<String>>,
132    pub asset_usage: RenderAssetUsages,
133    /// Whether or not to build a BLAS for use with `bevy_solari` raytracing.
134    ///
135    /// Note that this is _not_ whether the mesh is _compatible_ with `bevy_solari` raytracing.
136    /// This field just controls whether or not a BLAS gets built for this mesh, assuming that
137    /// the mesh is compatible.
138    ///
139    /// The use case for this field is using lower-resolution proxy meshes for raytracing (to save on BLAS memory usage),
140    /// while using higher-resolution meshes for raster. You can set this field to true for the lower-resolution proxy mesh,
141    /// and to false for the high-resolution raster mesh.
142    ///
143    /// Alternatively, you can use the same mesh for both raster and raytracing, with this field set to true.
144    ///
145    /// Does nothing if not used with `bevy_solari`, or if the mesh is not compatible
146    /// with `bevy_solari` (see `bevy_solari`'s docs).
147    pub enable_raytracing: bool,
148}
149
150impl Mesh {
151    /// Where the vertex is located in space. Use in conjunction with [`Mesh::insert_attribute`]
152    /// or [`Mesh::with_inserted_attribute`].
153    ///
154    /// The format of this attribute is [`VertexFormat::Float32x3`].
155    pub const ATTRIBUTE_POSITION: MeshVertexAttribute =
156        MeshVertexAttribute::new("Vertex_Position", 0, VertexFormat::Float32x3);
157
158    /// The direction the vertex normal is facing in.
159    /// Use in conjunction with [`Mesh::insert_attribute`] or [`Mesh::with_inserted_attribute`].
160    ///
161    /// The format of this attribute is [`VertexFormat::Float32x3`].
162    pub const ATTRIBUTE_NORMAL: MeshVertexAttribute =
163        MeshVertexAttribute::new("Vertex_Normal", 1, VertexFormat::Float32x3);
164
165    /// Texture coordinates for the vertex. Use in conjunction with [`Mesh::insert_attribute`]
166    /// or [`Mesh::with_inserted_attribute`].
167    ///
168    /// Generally `[0.,0.]` is mapped to the top left of the texture, and `[1.,1.]` to the bottom-right.
169    ///
170    /// By default values outside will be clamped per pixel not for the vertex,
171    /// "stretching" the borders of the texture.
172    /// This behavior can be useful in some cases, usually when the borders have only
173    /// one color, for example a logo, and you want to "extend" those borders.
174    ///
175    /// For different mapping outside of `0..=1` range,
176    /// see [`ImageAddressMode`](bevy_image::ImageAddressMode).
177    ///
178    /// The format of this attribute is [`VertexFormat::Float32x2`].
179    pub const ATTRIBUTE_UV_0: MeshVertexAttribute =
180        MeshVertexAttribute::new("Vertex_Uv", 2, VertexFormat::Float32x2);
181
182    /// Alternate texture coordinates for the vertex. Use in conjunction with
183    /// [`Mesh::insert_attribute`] or [`Mesh::with_inserted_attribute`].
184    ///
185    /// Typically, these are used for lightmaps, textures that provide
186    /// precomputed illumination.
187    ///
188    /// The format of this attribute is [`VertexFormat::Float32x2`].
189    pub const ATTRIBUTE_UV_1: MeshVertexAttribute =
190        MeshVertexAttribute::new("Vertex_Uv_1", 3, VertexFormat::Float32x2);
191
192    /// The direction of the vertex tangent. Used for normal mapping.
193    /// Usually generated with [`generate_tangents`](Mesh::generate_tangents) or
194    /// [`with_generated_tangents`](Mesh::with_generated_tangents).
195    ///
196    /// The format of this attribute is [`VertexFormat::Float32x4`].
197    pub const ATTRIBUTE_TANGENT: MeshVertexAttribute =
198        MeshVertexAttribute::new("Vertex_Tangent", 4, VertexFormat::Float32x4);
199
200    /// Per vertex coloring. Use in conjunction with [`Mesh::insert_attribute`]
201    /// or [`Mesh::with_inserted_attribute`].
202    ///
203    /// The format of this attribute is [`VertexFormat::Float32x4`].
204    pub const ATTRIBUTE_COLOR: MeshVertexAttribute =
205        MeshVertexAttribute::new("Vertex_Color", 5, VertexFormat::Float32x4);
206
207    /// Per vertex joint transform matrix weight. Use in conjunction with [`Mesh::insert_attribute`]
208    /// or [`Mesh::with_inserted_attribute`].
209    ///
210    /// The format of this attribute is [`VertexFormat::Float32x4`].
211    pub const ATTRIBUTE_JOINT_WEIGHT: MeshVertexAttribute =
212        MeshVertexAttribute::new("Vertex_JointWeight", 6, VertexFormat::Float32x4);
213
214    /// Per vertex joint transform matrix index. Use in conjunction with [`Mesh::insert_attribute`]
215    /// or [`Mesh::with_inserted_attribute`].
216    ///
217    /// The format of this attribute is [`VertexFormat::Uint16x4`].
218    pub const ATTRIBUTE_JOINT_INDEX: MeshVertexAttribute =
219        MeshVertexAttribute::new("Vertex_JointIndex", 7, VertexFormat::Uint16x4);
220
221    /// The first index that can be used for custom vertex attributes.
222    /// Only the attributes with an index below this are used by Bevy.
223    pub const FIRST_AVAILABLE_CUSTOM_ATTRIBUTE: u64 = 8;
224
225    /// Construct a new mesh. You need to provide a [`PrimitiveTopology`] so that the
226    /// renderer knows how to treat the vertex data. Most of the time this will be
227    /// [`PrimitiveTopology::TriangleList`].
228    pub fn new(primitive_topology: PrimitiveTopology, asset_usage: RenderAssetUsages) -> Self {
229        Mesh {
230            primitive_topology,
231            attributes: Default::default(),
232            indices: None,
233            morph_targets: None,
234            morph_target_names: None,
235            asset_usage,
236            enable_raytracing: true,
237        }
238    }
239
240    /// Returns the topology of the mesh.
241    pub fn primitive_topology(&self) -> PrimitiveTopology {
242        self.primitive_topology
243    }
244
245    /// Sets the data for a vertex attribute (position, normal, etc.). The name will
246    /// often be one of the associated constants such as [`Mesh::ATTRIBUTE_POSITION`].
247    ///
248    /// `Aabb` of entities with modified mesh are not updated automatically.
249    ///
250    /// # Panics
251    /// Panics when the format of the values does not match the attribute's format.
252    #[inline]
253    pub fn insert_attribute(
254        &mut self,
255        attribute: MeshVertexAttribute,
256        values: impl Into<VertexAttributeValues>,
257    ) {
258        let values = values.into();
259        let values_format = VertexFormat::from(&values);
260        if values_format != attribute.format {
261            panic!(
262                "Failed to insert attribute. Invalid attribute format for {}. Given format is {values_format:?} but expected {:?}",
263                attribute.name, attribute.format
264            );
265        }
266
267        self.attributes
268            .insert(attribute.id, MeshAttributeData { attribute, values });
269    }
270
271    /// Consumes the mesh and returns a mesh with data set for a vertex attribute (position, normal, etc.).
272    /// The name will often be one of the associated constants such as [`Mesh::ATTRIBUTE_POSITION`].
273    ///
274    /// (Alternatively, you can use [`Mesh::insert_attribute`] to mutate an existing mesh in-place)
275    ///
276    /// `Aabb` of entities with modified mesh are not updated automatically.
277    ///
278    /// # Panics
279    /// Panics when the format of the values does not match the attribute's format.
280    #[must_use]
281    #[inline]
282    pub fn with_inserted_attribute(
283        mut self,
284        attribute: MeshVertexAttribute,
285        values: impl Into<VertexAttributeValues>,
286    ) -> Self {
287        self.insert_attribute(attribute, values);
288        self
289    }
290
291    /// Removes the data for a vertex attribute
292    pub fn remove_attribute(
293        &mut self,
294        attribute: impl Into<MeshVertexAttributeId>,
295    ) -> Option<VertexAttributeValues> {
296        self.attributes
297            .remove(&attribute.into())
298            .map(|data| data.values)
299    }
300
301    /// Consumes the mesh and returns a mesh without the data for a vertex attribute
302    ///
303    /// (Alternatively, you can use [`Mesh::remove_attribute`] to mutate an existing mesh in-place)
304    #[must_use]
305    pub fn with_removed_attribute(mut self, attribute: impl Into<MeshVertexAttributeId>) -> Self {
306        self.remove_attribute(attribute);
307        self
308    }
309
310    #[inline]
311    pub fn contains_attribute(&self, id: impl Into<MeshVertexAttributeId>) -> bool {
312        self.attributes.contains_key(&id.into())
313    }
314
315    /// Retrieves the data currently set to the vertex attribute with the specified [`MeshVertexAttributeId`].
316    #[inline]
317    pub fn attribute(
318        &self,
319        id: impl Into<MeshVertexAttributeId>,
320    ) -> Option<&VertexAttributeValues> {
321        self.attributes.get(&id.into()).map(|data| &data.values)
322    }
323
324    /// Retrieves the full data currently set to the vertex attribute with the specified [`MeshVertexAttributeId`].
325    #[inline]
326    pub(crate) fn attribute_data(
327        &self,
328        id: impl Into<MeshVertexAttributeId>,
329    ) -> Option<&MeshAttributeData> {
330        self.attributes.get(&id.into())
331    }
332
333    /// Retrieves the data currently set to the vertex attribute with the specified `name` mutably.
334    #[inline]
335    pub fn attribute_mut(
336        &mut self,
337        id: impl Into<MeshVertexAttributeId>,
338    ) -> Option<&mut VertexAttributeValues> {
339        self.attributes
340            .get_mut(&id.into())
341            .map(|data| &mut data.values)
342    }
343
344    /// Returns an iterator that yields references to the data of each vertex attribute.
345    pub fn attributes(
346        &self,
347    ) -> impl Iterator<Item = (&MeshVertexAttribute, &VertexAttributeValues)> {
348        self.attributes
349            .values()
350            .map(|data| (&data.attribute, &data.values))
351    }
352
353    /// Returns an iterator that yields mutable references to the data of each vertex attribute.
354    pub fn attributes_mut(
355        &mut self,
356    ) -> impl Iterator<Item = (&MeshVertexAttribute, &mut VertexAttributeValues)> {
357        self.attributes
358            .values_mut()
359            .map(|data| (&data.attribute, &mut data.values))
360    }
361
362    /// Sets the vertex indices of the mesh. They describe how triangles are constructed out of the
363    /// vertex attributes and are therefore only useful for the [`PrimitiveTopology`] variants
364    /// that use triangles.
365    #[inline]
366    pub fn insert_indices(&mut self, indices: Indices) {
367        self.indices = Some(indices);
368    }
369
370    /// Consumes the mesh and returns a mesh with the given vertex indices. They describe how triangles
371    /// are constructed out of the vertex attributes and are therefore only useful for the
372    /// [`PrimitiveTopology`] variants that use triangles.
373    ///
374    /// (Alternatively, you can use [`Mesh::insert_indices`] to mutate an existing mesh in-place)
375    #[must_use]
376    #[inline]
377    pub fn with_inserted_indices(mut self, indices: Indices) -> Self {
378        self.insert_indices(indices);
379        self
380    }
381
382    /// Retrieves the vertex `indices` of the mesh.
383    #[inline]
384    pub fn indices(&self) -> Option<&Indices> {
385        self.indices.as_ref()
386    }
387
388    /// Retrieves the vertex `indices` of the mesh mutably.
389    #[inline]
390    pub fn indices_mut(&mut self) -> Option<&mut Indices> {
391        self.indices.as_mut()
392    }
393
394    /// Removes the vertex `indices` from the mesh and returns them.
395    #[inline]
396    pub fn remove_indices(&mut self) -> Option<Indices> {
397        core::mem::take(&mut self.indices)
398    }
399
400    /// Consumes the mesh and returns a mesh without the vertex `indices` of the mesh.
401    ///
402    /// (Alternatively, you can use [`Mesh::remove_indices`] to mutate an existing mesh in-place)
403    #[must_use]
404    pub fn with_removed_indices(mut self) -> Self {
405        self.remove_indices();
406        self
407    }
408
409    /// Returns the size of a vertex in bytes.
410    pub fn get_vertex_size(&self) -> u64 {
411        self.attributes
412            .values()
413            .map(|data| data.attribute.format.size())
414            .sum()
415    }
416
417    /// Returns the size required for the vertex buffer in bytes.
418    pub fn get_vertex_buffer_size(&self) -> usize {
419        let vertex_size = self.get_vertex_size() as usize;
420        let vertex_count = self.count_vertices();
421        vertex_count * vertex_size
422    }
423
424    /// Computes and returns the index data of the mesh as bytes.
425    /// This is used to transform the index data into a GPU friendly format.
426    pub fn get_index_buffer_bytes(&self) -> Option<&[u8]> {
427        self.indices.as_ref().map(|indices| match &indices {
428            Indices::U16(indices) => cast_slice(&indices[..]),
429            Indices::U32(indices) => cast_slice(&indices[..]),
430        })
431    }
432
433    /// Get this `Mesh`'s [`MeshVertexBufferLayout`], used in `SpecializedMeshPipeline`.
434    pub fn get_mesh_vertex_buffer_layout(
435        &self,
436        mesh_vertex_buffer_layouts: &mut MeshVertexBufferLayouts,
437    ) -> MeshVertexBufferLayoutRef {
438        let mut attributes = Vec::with_capacity(self.attributes.len());
439        let mut attribute_ids = Vec::with_capacity(self.attributes.len());
440        let mut accumulated_offset = 0;
441        for (index, data) in self.attributes.values().enumerate() {
442            attribute_ids.push(data.attribute.id);
443            attributes.push(VertexAttribute {
444                offset: accumulated_offset,
445                format: data.attribute.format,
446                shader_location: index as u32,
447            });
448            accumulated_offset += data.attribute.format.size();
449        }
450
451        let layout = MeshVertexBufferLayout {
452            layout: VertexBufferLayout {
453                array_stride: accumulated_offset,
454                step_mode: VertexStepMode::Vertex,
455                attributes,
456            },
457            attribute_ids,
458        };
459        mesh_vertex_buffer_layouts.insert(layout)
460    }
461
462    /// Counts all vertices of the mesh.
463    ///
464    /// If the attributes have different vertex counts, the smallest is returned.
465    pub fn count_vertices(&self) -> usize {
466        let mut vertex_count: Option<usize> = None;
467        for (attribute_id, attribute_data) in &self.attributes {
468            let attribute_len = attribute_data.values.len();
469            if let Some(previous_vertex_count) = vertex_count {
470                if previous_vertex_count != attribute_len {
471                    let name = self
472                        .attributes
473                        .get(attribute_id)
474                        .map(|data| data.attribute.name.to_string())
475                        .unwrap_or_else(|| format!("{attribute_id:?}"));
476
477                    warn!("{name} has a different vertex count ({attribute_len}) than other attributes ({previous_vertex_count}) in this mesh, \
478                        all attributes will be truncated to match the smallest.");
479                    vertex_count = Some(core::cmp::min(previous_vertex_count, attribute_len));
480                }
481            } else {
482                vertex_count = Some(attribute_len);
483            }
484        }
485
486        vertex_count.unwrap_or(0)
487    }
488
489    /// Computes and returns the vertex data of the mesh as bytes.
490    /// Therefore the attributes are located in the order of their [`MeshVertexAttribute::id`].
491    /// This is used to transform the vertex data into a GPU friendly format.
492    ///
493    /// If the vertex attributes have different lengths, they are all truncated to
494    /// the length of the smallest.
495    ///
496    /// This is a convenience method which allocates a Vec.
497    /// Prefer pre-allocating and using [`Mesh::write_packed_vertex_buffer_data`] when possible.
498    pub fn create_packed_vertex_buffer_data(&self) -> Vec<u8> {
499        let mut attributes_interleaved_buffer = vec![0; self.get_vertex_buffer_size()];
500        self.write_packed_vertex_buffer_data(&mut attributes_interleaved_buffer);
501        attributes_interleaved_buffer
502    }
503
504    /// Computes and write the vertex data of the mesh into a mutable byte slice.
505    /// The attributes are located in the order of their [`MeshVertexAttribute::id`].
506    /// This is used to transform the vertex data into a GPU friendly format.
507    ///
508    /// If the vertex attributes have different lengths, they are all truncated to
509    /// the length of the smallest.
510    pub fn write_packed_vertex_buffer_data(&self, slice: &mut [u8]) {
511        let vertex_size = self.get_vertex_size() as usize;
512        let vertex_count = self.count_vertices();
513        // bundle into interleaved buffers
514        let mut attribute_offset = 0;
515        for attribute_data in self.attributes.values() {
516            let attribute_size = attribute_data.attribute.format.size() as usize;
517            let attributes_bytes = attribute_data.values.get_bytes();
518            for (vertex_index, attribute_bytes) in attributes_bytes
519                .chunks_exact(attribute_size)
520                .take(vertex_count)
521                .enumerate()
522            {
523                let offset = vertex_index * vertex_size + attribute_offset;
524                slice[offset..offset + attribute_size].copy_from_slice(attribute_bytes);
525            }
526
527            attribute_offset += attribute_size;
528        }
529    }
530
531    /// Duplicates the vertex attributes so that no vertices are shared.
532    ///
533    /// This can dramatically increase the vertex count, so make sure this is what you want.
534    /// Does nothing if no [Indices] are set.
535    pub fn duplicate_vertices(&mut self) {
536        fn duplicate<T: Copy>(values: &[T], indices: impl Iterator<Item = usize>) -> Vec<T> {
537            indices.map(|i| values[i]).collect()
538        }
539
540        let Some(indices) = self.indices.take() else {
541            return;
542        };
543
544        for attributes in self.attributes.values_mut() {
545            let indices = indices.iter();
546            #[expect(
547                clippy::match_same_arms,
548                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."
549            )]
550            match &mut attributes.values {
551                VertexAttributeValues::Float32(vec) => *vec = duplicate(vec, indices),
552                VertexAttributeValues::Sint32(vec) => *vec = duplicate(vec, indices),
553                VertexAttributeValues::Uint32(vec) => *vec = duplicate(vec, indices),
554                VertexAttributeValues::Float32x2(vec) => *vec = duplicate(vec, indices),
555                VertexAttributeValues::Sint32x2(vec) => *vec = duplicate(vec, indices),
556                VertexAttributeValues::Uint32x2(vec) => *vec = duplicate(vec, indices),
557                VertexAttributeValues::Float32x3(vec) => *vec = duplicate(vec, indices),
558                VertexAttributeValues::Sint32x3(vec) => *vec = duplicate(vec, indices),
559                VertexAttributeValues::Uint32x3(vec) => *vec = duplicate(vec, indices),
560                VertexAttributeValues::Sint32x4(vec) => *vec = duplicate(vec, indices),
561                VertexAttributeValues::Uint32x4(vec) => *vec = duplicate(vec, indices),
562                VertexAttributeValues::Float32x4(vec) => *vec = duplicate(vec, indices),
563                VertexAttributeValues::Sint16x2(vec) => *vec = duplicate(vec, indices),
564                VertexAttributeValues::Snorm16x2(vec) => *vec = duplicate(vec, indices),
565                VertexAttributeValues::Uint16x2(vec) => *vec = duplicate(vec, indices),
566                VertexAttributeValues::Unorm16x2(vec) => *vec = duplicate(vec, indices),
567                VertexAttributeValues::Sint16x4(vec) => *vec = duplicate(vec, indices),
568                VertexAttributeValues::Snorm16x4(vec) => *vec = duplicate(vec, indices),
569                VertexAttributeValues::Uint16x4(vec) => *vec = duplicate(vec, indices),
570                VertexAttributeValues::Unorm16x4(vec) => *vec = duplicate(vec, indices),
571                VertexAttributeValues::Sint8x2(vec) => *vec = duplicate(vec, indices),
572                VertexAttributeValues::Snorm8x2(vec) => *vec = duplicate(vec, indices),
573                VertexAttributeValues::Uint8x2(vec) => *vec = duplicate(vec, indices),
574                VertexAttributeValues::Unorm8x2(vec) => *vec = duplicate(vec, indices),
575                VertexAttributeValues::Sint8x4(vec) => *vec = duplicate(vec, indices),
576                VertexAttributeValues::Snorm8x4(vec) => *vec = duplicate(vec, indices),
577                VertexAttributeValues::Uint8x4(vec) => *vec = duplicate(vec, indices),
578                VertexAttributeValues::Unorm8x4(vec) => *vec = duplicate(vec, indices),
579            }
580        }
581    }
582
583    /// Consumes the mesh and returns a mesh with no shared vertices.
584    ///
585    /// This can dramatically increase the vertex count, so make sure this is what you want.
586    /// Does nothing if no [`Indices`] are set.
587    ///
588    /// (Alternatively, you can use [`Mesh::duplicate_vertices`] to mutate an existing mesh in-place)
589    #[must_use]
590    pub fn with_duplicated_vertices(mut self) -> Self {
591        self.duplicate_vertices();
592        self
593    }
594
595    /// Inverts the winding of the indices such that all counter-clockwise triangles are now
596    /// clockwise and vice versa.
597    /// For lines, their start and end indices are flipped.
598    ///
599    /// Does nothing if no [`Indices`] are set.
600    /// If this operation succeeded, an [`Ok`] result is returned.
601    pub fn invert_winding(&mut self) -> Result<(), MeshWindingInvertError> {
602        fn invert<I>(
603            indices: &mut [I],
604            topology: PrimitiveTopology,
605        ) -> Result<(), MeshWindingInvertError> {
606            match topology {
607                PrimitiveTopology::TriangleList => {
608                    // Early return if the index count doesn't match
609                    if !indices.len().is_multiple_of(3) {
610                        return Err(MeshWindingInvertError::AbruptIndicesEnd);
611                    }
612                    for chunk in indices.chunks_mut(3) {
613                        // This currently can only be optimized away with unsafe, rework this when `feature(slice_as_chunks)` gets stable.
614                        let [_, b, c] = chunk else {
615                            return Err(MeshWindingInvertError::AbruptIndicesEnd);
616                        };
617                        core::mem::swap(b, c);
618                    }
619                    Ok(())
620                }
621                PrimitiveTopology::LineList => {
622                    // Early return if the index count doesn't match
623                    if !indices.len().is_multiple_of(2) {
624                        return Err(MeshWindingInvertError::AbruptIndicesEnd);
625                    }
626                    indices.reverse();
627                    Ok(())
628                }
629                PrimitiveTopology::TriangleStrip | PrimitiveTopology::LineStrip => {
630                    indices.reverse();
631                    Ok(())
632                }
633                _ => Err(MeshWindingInvertError::WrongTopology),
634            }
635        }
636        match &mut self.indices {
637            Some(Indices::U16(vec)) => invert(vec, self.primitive_topology),
638            Some(Indices::U32(vec)) => invert(vec, self.primitive_topology),
639            None => Ok(()),
640        }
641    }
642
643    /// Consumes the mesh and returns a mesh with inverted winding of the indices such
644    /// that all counter-clockwise triangles are now clockwise and vice versa.
645    ///
646    /// Does nothing if no [`Indices`] are set.
647    pub fn with_inverted_winding(mut self) -> Result<Self, MeshWindingInvertError> {
648        self.invert_winding().map(|_| self)
649    }
650
651    /// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of a mesh.
652    /// If the mesh is indexed, this defaults to smooth normals. Otherwise, it defaults to flat
653    /// normals.
654    ///
655    /// # Panics
656    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
657    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].=
658    pub fn compute_normals(&mut self) {
659        assert!(
660            matches!(self.primitive_topology, PrimitiveTopology::TriangleList),
661            "`compute_normals` can only work on `TriangleList`s"
662        );
663        if self.indices().is_none() {
664            self.compute_flat_normals();
665        } else {
666            self.compute_smooth_normals();
667        }
668    }
669
670    /// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of a mesh.
671    ///
672    /// # Panics
673    /// Panics if [`Indices`] are set or [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
674    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
675    /// Consider calling [`Mesh::duplicate_vertices`] or exporting your mesh with normal
676    /// attributes.
677    ///
678    /// FIXME: This should handle more cases since this is called as a part of gltf
679    /// mesh loading where we can't really blame users for loading meshes that might
680    /// not conform to the limitations here!
681    pub fn compute_flat_normals(&mut self) {
682        assert!(
683            self.indices().is_none(),
684            "`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`."
685        );
686        assert!(
687            matches!(self.primitive_topology, PrimitiveTopology::TriangleList),
688            "`compute_flat_normals` can only work on `TriangleList`s"
689        );
690
691        let positions = self
692            .attribute(Mesh::ATTRIBUTE_POSITION)
693            .unwrap()
694            .as_float3()
695            .expect("`Mesh::ATTRIBUTE_POSITION` vertex attributes should be of type `float3`");
696
697        let normals: Vec<_> = positions
698            .chunks_exact(3)
699            .map(|p| triangle_normal(p[0], p[1], p[2]))
700            .flat_map(|normal| [normal; 3])
701            .collect();
702
703        self.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals);
704    }
705
706    /// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of an indexed mesh, smoothing normals for shared
707    /// vertices.
708    ///
709    /// This method weights normals by the angles of the corners of connected triangles, thus
710    /// eliminating triangle area and count as factors in the final normal. This does make it
711    /// somewhat slower than [`Mesh::compute_area_weighted_normals`] which does not need to
712    /// greedily normalize each triangle's normal or calculate corner angles.
713    ///
714    /// If you would rather have the computed normals be weighted by triangle area, see
715    /// [`Mesh::compute_area_weighted_normals`] instead. If you need to weight them in some other
716    /// way, see [`Mesh::compute_custom_smooth_normals`].
717    ///
718    /// # Panics
719    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
720    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
721    /// Panics if the mesh does not have indices defined.
722    pub fn compute_smooth_normals(&mut self) {
723        self.compute_custom_smooth_normals(|[a, b, c], positions, normals| {
724            let pa = Vec3::from(positions[a]);
725            let pb = Vec3::from(positions[b]);
726            let pc = Vec3::from(positions[c]);
727
728            let ab = pb - pa;
729            let ba = pa - pb;
730            let bc = pc - pb;
731            let cb = pb - pc;
732            let ca = pa - pc;
733            let ac = pc - pa;
734
735            const EPS: f32 = f32::EPSILON;
736            let weight_a = if ab.length_squared() * ac.length_squared() > EPS {
737                ab.angle_between(ac)
738            } else {
739                0.0
740            };
741            let weight_b = if ba.length_squared() * bc.length_squared() > EPS {
742                ba.angle_between(bc)
743            } else {
744                0.0
745            };
746            let weight_c = if ca.length_squared() * cb.length_squared() > EPS {
747                ca.angle_between(cb)
748            } else {
749                0.0
750            };
751
752            let normal = Vec3::from(triangle_normal(positions[a], positions[b], positions[c]));
753
754            normals[a] += normal * weight_a;
755            normals[b] += normal * weight_b;
756            normals[c] += normal * weight_c;
757        });
758    }
759
760    /// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of an indexed mesh, smoothing normals for shared
761    /// vertices.
762    ///
763    /// This method weights normals by the area of each triangle containing the vertex. Thus,
764    /// larger triangles will skew the normals of their vertices towards their own normal more
765    /// than smaller triangles will.
766    ///
767    /// This method is actually somewhat faster than [`Mesh::compute_smooth_normals`] because an
768    /// intermediate result of triangle normal calculation is already scaled by the triangle's area.
769    ///
770    /// If you would rather have the computed normals be influenced only by the angles of connected
771    /// edges, see [`Mesh::compute_smooth_normals`] instead. If you need to weight them in some
772    /// other way, see [`Mesh::compute_custom_smooth_normals`].
773    ///
774    /// # Panics
775    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
776    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
777    /// Panics if the mesh does not have indices defined.
778    pub fn compute_area_weighted_normals(&mut self) {
779        self.compute_custom_smooth_normals(|[a, b, c], positions, normals| {
780            let normal = Vec3::from(triangle_area_normal(
781                positions[a],
782                positions[b],
783                positions[c],
784            ));
785            [a, b, c].into_iter().for_each(|pos| {
786                normals[pos] += normal;
787            });
788        });
789    }
790
791    /// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of an indexed mesh, smoothing normals for shared
792    /// vertices.
793    ///
794    /// This method allows you to customize how normals are weighted via the `per_triangle` parameter,
795    /// which must be a function or closure that accepts 3 parameters:
796    /// - The indices of the three vertices of the triangle as a `[usize; 3]`.
797    /// - A reference to the values of the [`Mesh::ATTRIBUTE_POSITION`] of the mesh (`&[[f32; 3]]`).
798    /// - A mutable reference to the sums of all normals so far.
799    ///
800    /// See also the standard methods included in Bevy for calculating smooth normals:
801    /// - [`Mesh::compute_smooth_normals`]
802    /// - [`Mesh::compute_area_weighted_normals`]
803    ///
804    /// An example that would weight each connected triangle's normal equally, thus skewing normals
805    /// towards the planes divided into the most triangles:
806    /// ```
807    /// # use bevy_asset::RenderAssetUsages;
808    /// # use bevy_mesh::{Mesh, PrimitiveTopology, Meshable, MeshBuilder};
809    /// # use bevy_math::{Vec3, primitives::Cuboid};
810    /// # let mut mesh = Cuboid::default().mesh().build();
811    /// mesh.compute_custom_smooth_normals(|[a, b, c], positions, normals| {
812    ///     let normal = Vec3::from(bevy_mesh::triangle_normal(positions[a], positions[b], positions[c]));
813    ///     for idx in [a, b, c] {
814    ///         normals[idx] += normal;
815    ///     }
816    /// });
817    /// ```
818    ///
819    /// # Panics
820    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
821    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
822    /// Panics if the mesh does not have indices defined.
823    //
824    // FIXME: This should handle more cases since this is called as a part of gltf
825    // mesh loading where we can't really blame users for loading meshes that might
826    // not conform to the limitations here!
827    //
828    // When fixed, also update "Panics" sections of
829    // - [Mesh::compute_smooth_normals]
830    // - [Mesh::with_computed_smooth_normals]
831    // - [Mesh::compute_area_weighted_normals]
832    // - [Mesh::with_computed_area_weighted_normals]
833    pub fn compute_custom_smooth_normals(
834        &mut self,
835        mut per_triangle: impl FnMut([usize; 3], &[[f32; 3]], &mut [Vec3]),
836    ) {
837        assert!(
838            matches!(self.primitive_topology, PrimitiveTopology::TriangleList),
839            "smooth normals can only be computed on `TriangleList`s"
840        );
841        assert!(
842            self.indices().is_some(),
843            "smooth normals can only be computed on indexed meshes"
844        );
845
846        let positions = self
847            .attribute(Mesh::ATTRIBUTE_POSITION)
848            .unwrap()
849            .as_float3()
850            .expect("`Mesh::ATTRIBUTE_POSITION` vertex attributes should be of type `float3`");
851
852        let mut normals = vec![Vec3::ZERO; positions.len()];
853
854        self.indices()
855            .unwrap()
856            .iter()
857            .collect::<Vec<usize>>()
858            .chunks_exact(3)
859            .for_each(|face| per_triangle([face[0], face[1], face[2]], positions, &mut normals));
860
861        for normal in &mut normals {
862            *normal = normal.try_normalize().unwrap_or(Vec3::ZERO);
863        }
864
865        self.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals);
866    }
867
868    /// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
869    /// If the mesh is indexed, this defaults to smooth normals. Otherwise, it defaults to flat
870    /// normals.
871    ///
872    /// (Alternatively, you can use [`Mesh::compute_normals`] to mutate an existing mesh in-place)
873    ///
874    /// # Panics
875    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
876    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
877    #[must_use]
878    pub fn with_computed_normals(mut self) -> Self {
879        self.compute_normals();
880        self
881    }
882
883    /// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
884    ///
885    /// (Alternatively, you can use [`Mesh::compute_flat_normals`] to mutate an existing mesh in-place)
886    ///
887    /// # Panics
888    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
889    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
890    /// Panics if the mesh has indices defined
891    #[must_use]
892    pub fn with_computed_flat_normals(mut self) -> Self {
893        self.compute_flat_normals();
894        self
895    }
896
897    /// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
898    ///
899    /// (Alternatively, you can use [`Mesh::compute_smooth_normals`] to mutate an existing mesh in-place)
900    ///
901    /// This method weights normals by the angles of triangle corners connected to each vertex. If
902    /// you would rather have the computed normals be weighted by triangle area, see
903    /// [`Mesh::with_computed_area_weighted_normals`] instead.
904    ///
905    /// # Panics
906    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
907    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
908    /// Panics if the mesh does not have indices defined.
909    #[must_use]
910    pub fn with_computed_smooth_normals(mut self) -> Self {
911        self.compute_smooth_normals();
912        self
913    }
914
915    /// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
916    ///
917    /// (Alternatively, you can use [`Mesh::compute_area_weighted_normals`] to mutate an existing mesh in-place)
918    ///
919    /// This method weights normals by the area of each triangle containing the vertex. Thus,
920    /// larger triangles will skew the normals of their vertices towards their own normal more
921    /// than smaller triangles will. If you would rather have the computed normals be influenced
922    /// only by the angles of connected edges, see [`Mesh::with_computed_smooth_normals`] instead.
923    ///
924    /// # Panics
925    /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
926    /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
927    /// Panics if the mesh does not have indices defined.
928    #[must_use]
929    pub fn with_computed_area_weighted_normals(mut self) -> Self {
930        self.compute_area_weighted_normals();
931        self
932    }
933
934    /// Generate tangents for the mesh using the `mikktspace` algorithm.
935    ///
936    /// Sets the [`Mesh::ATTRIBUTE_TANGENT`] attribute if successful.
937    /// Requires a [`PrimitiveTopology::TriangleList`] topology and the [`Mesh::ATTRIBUTE_POSITION`], [`Mesh::ATTRIBUTE_NORMAL`] and [`Mesh::ATTRIBUTE_UV_0`] attributes set.
938    pub fn generate_tangents(&mut self) -> Result<(), GenerateTangentsError> {
939        let tangents = generate_tangents_for_mesh(self)?;
940        self.insert_attribute(Mesh::ATTRIBUTE_TANGENT, tangents);
941        Ok(())
942    }
943
944    /// Consumes the mesh and returns a mesh with tangents generated using the `mikktspace` algorithm.
945    ///
946    /// The resulting mesh will have the [`Mesh::ATTRIBUTE_TANGENT`] attribute if successful.
947    ///
948    /// (Alternatively, you can use [`Mesh::generate_tangents`] to mutate an existing mesh in-place)
949    ///
950    /// Requires a [`PrimitiveTopology::TriangleList`] topology and the [`Mesh::ATTRIBUTE_POSITION`], [`Mesh::ATTRIBUTE_NORMAL`] and [`Mesh::ATTRIBUTE_UV_0`] attributes set.
951    pub fn with_generated_tangents(mut self) -> Result<Mesh, GenerateTangentsError> {
952        self.generate_tangents()?;
953        Ok(self)
954    }
955
956    /// Merges the [`Mesh`] data of `other` with `self`. The attributes and indices of `other` will be appended to `self`.
957    ///
958    /// Note that attributes of `other` that don't exist on `self` will be ignored.
959    ///
960    /// `Aabb` of entities with modified mesh are not updated automatically.
961    ///
962    /// # Errors
963    ///
964    /// If any of the following conditions are not met, this function errors:
965    /// * All of the vertex attributes that have the same attribute id, must also
966    ///   have the same attribute type.
967    ///   For example two attributes with the same id, but where one is a
968    ///   [`VertexAttributeValues::Float32`] and the other is a
969    ///   [`VertexAttributeValues::Float32x3`], would be invalid.
970    /// * Both meshes must have the same primitive topology.
971    pub fn merge(&mut self, other: &Mesh) -> Result<(), MeshMergeError> {
972        use VertexAttributeValues::*;
973
974        // Check if the meshes `primitive_topology` field is the same,
975        // as if that is not the case, the resulting mesh could (and most likely would)
976        // be invalid.
977        if self.primitive_topology != other.primitive_topology {
978            return Err(MeshMergeError::IncompatiblePrimitiveTopology {
979                self_primitive_topology: self.primitive_topology,
980                other_primitive_topology: other.primitive_topology,
981            });
982        }
983
984        // The indices of `other` should start after the last vertex of `self`.
985        let index_offset = self.count_vertices();
986
987        // Extend attributes of `self` with attributes of `other`.
988        for (attribute, values) in self.attributes_mut() {
989            if let Some(other_values) = other.attribute(attribute.id) {
990                #[expect(
991                    clippy::match_same_arms,
992                    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."
993                )]
994                match (values, other_values) {
995                    (Float32(vec1), Float32(vec2)) => vec1.extend(vec2),
996                    (Sint32(vec1), Sint32(vec2)) => vec1.extend(vec2),
997                    (Uint32(vec1), Uint32(vec2)) => vec1.extend(vec2),
998                    (Float32x2(vec1), Float32x2(vec2)) => vec1.extend(vec2),
999                    (Sint32x2(vec1), Sint32x2(vec2)) => vec1.extend(vec2),
1000                    (Uint32x2(vec1), Uint32x2(vec2)) => vec1.extend(vec2),
1001                    (Float32x3(vec1), Float32x3(vec2)) => vec1.extend(vec2),
1002                    (Sint32x3(vec1), Sint32x3(vec2)) => vec1.extend(vec2),
1003                    (Uint32x3(vec1), Uint32x3(vec2)) => vec1.extend(vec2),
1004                    (Sint32x4(vec1), Sint32x4(vec2)) => vec1.extend(vec2),
1005                    (Uint32x4(vec1), Uint32x4(vec2)) => vec1.extend(vec2),
1006                    (Float32x4(vec1), Float32x4(vec2)) => vec1.extend(vec2),
1007                    (Sint16x2(vec1), Sint16x2(vec2)) => vec1.extend(vec2),
1008                    (Snorm16x2(vec1), Snorm16x2(vec2)) => vec1.extend(vec2),
1009                    (Uint16x2(vec1), Uint16x2(vec2)) => vec1.extend(vec2),
1010                    (Unorm16x2(vec1), Unorm16x2(vec2)) => vec1.extend(vec2),
1011                    (Sint16x4(vec1), Sint16x4(vec2)) => vec1.extend(vec2),
1012                    (Snorm16x4(vec1), Snorm16x4(vec2)) => vec1.extend(vec2),
1013                    (Uint16x4(vec1), Uint16x4(vec2)) => vec1.extend(vec2),
1014                    (Unorm16x4(vec1), Unorm16x4(vec2)) => vec1.extend(vec2),
1015                    (Sint8x2(vec1), Sint8x2(vec2)) => vec1.extend(vec2),
1016                    (Snorm8x2(vec1), Snorm8x2(vec2)) => vec1.extend(vec2),
1017                    (Uint8x2(vec1), Uint8x2(vec2)) => vec1.extend(vec2),
1018                    (Unorm8x2(vec1), Unorm8x2(vec2)) => vec1.extend(vec2),
1019                    (Sint8x4(vec1), Sint8x4(vec2)) => vec1.extend(vec2),
1020                    (Snorm8x4(vec1), Snorm8x4(vec2)) => vec1.extend(vec2),
1021                    (Uint8x4(vec1), Uint8x4(vec2)) => vec1.extend(vec2),
1022                    (Unorm8x4(vec1), Unorm8x4(vec2)) => vec1.extend(vec2),
1023                    _ => {
1024                        return Err(MeshMergeError::IncompatibleVertexAttributes {
1025                            self_attribute: *attribute,
1026                            other_attribute: other
1027                                .attribute_data(attribute.id)
1028                                .map(|data| data.attribute),
1029                        })
1030                    }
1031                }
1032            }
1033        }
1034
1035        // Extend indices of `self` with indices of `other`.
1036        if let (Some(indices), Some(other_indices)) = (self.indices_mut(), other.indices()) {
1037            indices.extend(other_indices.iter().map(|i| (i + index_offset) as u32));
1038        }
1039        Ok(())
1040    }
1041
1042    /// Transforms the vertex positions, normals, and tangents of the mesh by the given [`Transform`].
1043    ///
1044    /// `Aabb` of entities with modified mesh are not updated automatically.
1045    pub fn transformed_by(mut self, transform: Transform) -> Self {
1046        self.transform_by(transform);
1047        self
1048    }
1049
1050    /// Transforms the vertex positions, normals, and tangents of the mesh in place by the given [`Transform`].
1051    ///
1052    /// `Aabb` of entities with modified mesh are not updated automatically.
1053    pub fn transform_by(&mut self, transform: Transform) {
1054        // Needed when transforming normals and tangents
1055        let scale_recip = 1. / transform.scale;
1056        debug_assert!(
1057            transform.scale.yzx() * transform.scale.zxy() != Vec3::ZERO,
1058            "mesh transform scale cannot be zero on more than one axis"
1059        );
1060
1061        if let Some(VertexAttributeValues::Float32x3(positions)) =
1062            self.attribute_mut(Mesh::ATTRIBUTE_POSITION)
1063        {
1064            // Apply scale, rotation, and translation to vertex positions
1065            positions
1066                .iter_mut()
1067                .for_each(|pos| *pos = transform.transform_point(Vec3::from_slice(pos)).to_array());
1068        }
1069
1070        // No need to transform normals or tangents if rotation is near identity and scale is uniform
1071        if transform.rotation.is_near_identity()
1072            && transform.scale.x == transform.scale.y
1073            && transform.scale.y == transform.scale.z
1074        {
1075            return;
1076        }
1077
1078        if let Some(VertexAttributeValues::Float32x3(normals)) =
1079            self.attribute_mut(Mesh::ATTRIBUTE_NORMAL)
1080        {
1081            // Transform normals, taking into account non-uniform scaling and rotation
1082            normals.iter_mut().for_each(|normal| {
1083                *normal = (transform.rotation
1084                    * scale_normal(Vec3::from_array(*normal), scale_recip))
1085                .to_array();
1086            });
1087        }
1088
1089        if let Some(VertexAttributeValues::Float32x4(tangents)) =
1090            self.attribute_mut(Mesh::ATTRIBUTE_TANGENT)
1091        {
1092            // Transform tangents, taking into account non-uniform scaling and rotation
1093            tangents.iter_mut().for_each(|tangent| {
1094                let handedness = tangent[3];
1095                let scaled_tangent = Vec3::from_slice(tangent) * transform.scale;
1096                *tangent = (transform.rotation * scaled_tangent.normalize_or_zero())
1097                    .extend(handedness)
1098                    .to_array();
1099            });
1100        }
1101    }
1102
1103    /// Translates the vertex positions of the mesh by the given [`Vec3`].
1104    ///
1105    /// `Aabb` of entities with modified mesh are not updated automatically.
1106    pub fn translated_by(mut self, translation: Vec3) -> Self {
1107        self.translate_by(translation);
1108        self
1109    }
1110
1111    /// Translates the vertex positions of the mesh in place by the given [`Vec3`].
1112    ///
1113    /// `Aabb` of entities with modified mesh are not updated automatically.
1114    pub fn translate_by(&mut self, translation: Vec3) {
1115        if translation == Vec3::ZERO {
1116            return;
1117        }
1118
1119        if let Some(VertexAttributeValues::Float32x3(positions)) =
1120            self.attribute_mut(Mesh::ATTRIBUTE_POSITION)
1121        {
1122            // Apply translation to vertex positions
1123            positions
1124                .iter_mut()
1125                .for_each(|pos| *pos = (Vec3::from_slice(pos) + translation).to_array());
1126        }
1127    }
1128
1129    /// Rotates the vertex positions, normals, and tangents of the mesh by the given [`Quat`].
1130    ///
1131    /// `Aabb` of entities with modified mesh are not updated automatically.
1132    pub fn rotated_by(mut self, rotation: Quat) -> Self {
1133        self.rotate_by(rotation);
1134        self
1135    }
1136
1137    /// Rotates the vertex positions, normals, and tangents of the mesh in place by the given [`Quat`].
1138    ///
1139    /// `Aabb` of entities with modified mesh are not updated automatically.
1140    pub fn rotate_by(&mut self, rotation: Quat) {
1141        if let Some(VertexAttributeValues::Float32x3(positions)) =
1142            self.attribute_mut(Mesh::ATTRIBUTE_POSITION)
1143        {
1144            // Apply rotation to vertex positions
1145            positions
1146                .iter_mut()
1147                .for_each(|pos| *pos = (rotation * Vec3::from_slice(pos)).to_array());
1148        }
1149
1150        // No need to transform normals or tangents if rotation is near identity
1151        if rotation.is_near_identity() {
1152            return;
1153        }
1154
1155        if let Some(VertexAttributeValues::Float32x3(normals)) =
1156            self.attribute_mut(Mesh::ATTRIBUTE_NORMAL)
1157        {
1158            // Transform normals
1159            normals.iter_mut().for_each(|normal| {
1160                *normal = (rotation * Vec3::from_slice(normal).normalize_or_zero()).to_array();
1161            });
1162        }
1163
1164        if let Some(VertexAttributeValues::Float32x4(tangents)) =
1165            self.attribute_mut(Mesh::ATTRIBUTE_TANGENT)
1166        {
1167            // Transform tangents
1168            tangents.iter_mut().for_each(|tangent| {
1169                let handedness = tangent[3];
1170                *tangent = (rotation * Vec3::from_slice(tangent).normalize_or_zero())
1171                    .extend(handedness)
1172                    .to_array();
1173            });
1174        }
1175    }
1176
1177    /// Scales the vertex positions, normals, and tangents of the mesh by the given [`Vec3`].
1178    ///
1179    /// `Aabb` of entities with modified mesh are not updated automatically.
1180    pub fn scaled_by(mut self, scale: Vec3) -> Self {
1181        self.scale_by(scale);
1182        self
1183    }
1184
1185    /// Scales the vertex positions, normals, and tangents of the mesh in place by the given [`Vec3`].
1186    ///
1187    /// `Aabb` of entities with modified mesh are not updated automatically.
1188    pub fn scale_by(&mut self, scale: Vec3) {
1189        // Needed when transforming normals and tangents
1190        let scale_recip = 1. / scale;
1191        debug_assert!(
1192            scale.yzx() * scale.zxy() != Vec3::ZERO,
1193            "mesh transform scale cannot be zero on more than one axis"
1194        );
1195
1196        if let Some(VertexAttributeValues::Float32x3(positions)) =
1197            self.attribute_mut(Mesh::ATTRIBUTE_POSITION)
1198        {
1199            // Apply scale to vertex positions
1200            positions
1201                .iter_mut()
1202                .for_each(|pos| *pos = (scale * Vec3::from_slice(pos)).to_array());
1203        }
1204
1205        // No need to transform normals or tangents if scale is uniform
1206        if scale.x == scale.y && scale.y == scale.z {
1207            return;
1208        }
1209
1210        if let Some(VertexAttributeValues::Float32x3(normals)) =
1211            self.attribute_mut(Mesh::ATTRIBUTE_NORMAL)
1212        {
1213            // Transform normals, taking into account non-uniform scaling
1214            normals.iter_mut().for_each(|normal| {
1215                *normal = scale_normal(Vec3::from_array(*normal), scale_recip).to_array();
1216            });
1217        }
1218
1219        if let Some(VertexAttributeValues::Float32x4(tangents)) =
1220            self.attribute_mut(Mesh::ATTRIBUTE_TANGENT)
1221        {
1222            // Transform tangents, taking into account non-uniform scaling
1223            tangents.iter_mut().for_each(|tangent| {
1224                let handedness = tangent[3];
1225                let scaled_tangent = Vec3::from_slice(tangent) * scale;
1226                *tangent = scaled_tangent
1227                    .normalize_or_zero()
1228                    .extend(handedness)
1229                    .to_array();
1230            });
1231        }
1232    }
1233
1234    /// Whether this mesh has morph targets.
1235    pub fn has_morph_targets(&self) -> bool {
1236        self.morph_targets.is_some()
1237    }
1238
1239    /// Set [morph targets] image for this mesh. This requires a "morph target image". See [`MorphTargetImage`](crate::morph::MorphTargetImage) for info.
1240    ///
1241    /// [morph targets]: https://en.wikipedia.org/wiki/Morph_target_animation
1242    pub fn set_morph_targets(&mut self, morph_targets: Handle<Image>) {
1243        self.morph_targets = Some(morph_targets);
1244    }
1245
1246    pub fn morph_targets(&self) -> Option<&Handle<Image>> {
1247        self.morph_targets.as_ref()
1248    }
1249
1250    /// Consumes the mesh and returns a mesh with the given [morph targets].
1251    ///
1252    /// This requires a "morph target image". See [`MorphTargetImage`](crate::morph::MorphTargetImage) for info.
1253    ///
1254    /// (Alternatively, you can use [`Mesh::set_morph_targets`] to mutate an existing mesh in-place)
1255    ///
1256    /// [morph targets]: https://en.wikipedia.org/wiki/Morph_target_animation
1257    #[must_use]
1258    pub fn with_morph_targets(mut self, morph_targets: Handle<Image>) -> Self {
1259        self.set_morph_targets(morph_targets);
1260        self
1261    }
1262
1263    /// Sets the names of each morph target. This should correspond to the order of the morph targets in `set_morph_targets`.
1264    pub fn set_morph_target_names(&mut self, names: Vec<String>) {
1265        self.morph_target_names = Some(names);
1266    }
1267
1268    /// Consumes the mesh and returns a mesh with morph target names.
1269    /// Names should correspond to the order of the morph targets in `set_morph_targets`.
1270    ///
1271    /// (Alternatively, you can use [`Mesh::set_morph_target_names`] to mutate an existing mesh in-place)
1272    #[must_use]
1273    pub fn with_morph_target_names(mut self, names: Vec<String>) -> Self {
1274        self.set_morph_target_names(names);
1275        self
1276    }
1277
1278    /// Gets a list of all morph target names, if they exist.
1279    pub fn morph_target_names(&self) -> Option<&[String]> {
1280        self.morph_target_names.as_deref()
1281    }
1282
1283    /// Normalize joint weights so they sum to 1.
1284    pub fn normalize_joint_weights(&mut self) {
1285        if let Some(joints) = self.attribute_mut(Self::ATTRIBUTE_JOINT_WEIGHT) {
1286            let VertexAttributeValues::Float32x4(joints) = joints else {
1287                panic!("unexpected joint weight format");
1288            };
1289
1290            for weights in joints.iter_mut() {
1291                // force negative weights to zero
1292                weights.iter_mut().for_each(|w| *w = w.max(0.0));
1293
1294                let sum: f32 = weights.iter().sum();
1295                if sum == 0.0 {
1296                    // all-zero weights are invalid
1297                    weights[0] = 1.0;
1298                } else {
1299                    let recip = sum.recip();
1300                    for weight in weights.iter_mut() {
1301                        *weight *= recip;
1302                    }
1303                }
1304            }
1305        }
1306    }
1307
1308    /// Get a list of this Mesh's [triangles] as an iterator if possible.
1309    ///
1310    /// Returns an error if any of the following conditions are met (see [`MeshTrianglesError`]):
1311    /// * The Mesh's [primitive topology] is not `TriangleList` or `TriangleStrip`.
1312    /// * The Mesh is missing position or index data.
1313    /// * The Mesh's position data has the wrong format (not `Float32x3`).
1314    ///
1315    /// [primitive topology]: PrimitiveTopology
1316    /// [triangles]: Triangle3d
1317    pub fn triangles(&self) -> Result<impl Iterator<Item = Triangle3d> + '_, MeshTrianglesError> {
1318        let Some(position_data) = self.attribute(Mesh::ATTRIBUTE_POSITION) else {
1319            return Err(MeshTrianglesError::MissingPositions);
1320        };
1321
1322        let Some(vertices) = position_data.as_float3() else {
1323            return Err(MeshTrianglesError::PositionsFormat);
1324        };
1325
1326        let Some(indices) = self.indices() else {
1327            return Err(MeshTrianglesError::MissingIndices);
1328        };
1329
1330        match self.primitive_topology {
1331            PrimitiveTopology::TriangleList => {
1332                // When indices reference out-of-bounds vertex data, the triangle is omitted.
1333                // This implicitly truncates the indices to a multiple of 3.
1334                let iterator = match indices {
1335                    Indices::U16(vec) => FourIterators::First(
1336                        vec.as_slice()
1337                            .chunks_exact(3)
1338                            .flat_map(move |indices| indices_to_triangle(vertices, indices)),
1339                    ),
1340                    Indices::U32(vec) => FourIterators::Second(
1341                        vec.as_slice()
1342                            .chunks_exact(3)
1343                            .flat_map(move |indices| indices_to_triangle(vertices, indices)),
1344                    ),
1345                };
1346
1347                return Ok(iterator);
1348            }
1349
1350            PrimitiveTopology::TriangleStrip => {
1351                // When indices reference out-of-bounds vertex data, the triangle is omitted.
1352                // If there aren't enough indices to make a triangle, then an empty vector will be
1353                // returned.
1354                let iterator = match indices {
1355                    Indices::U16(vec) => {
1356                        FourIterators::Third(vec.as_slice().windows(3).enumerate().flat_map(
1357                            move |(i, indices)| {
1358                                if i % 2 == 0 {
1359                                    indices_to_triangle(vertices, indices)
1360                                } else {
1361                                    indices_to_triangle(
1362                                        vertices,
1363                                        &[indices[1], indices[0], indices[2]],
1364                                    )
1365                                }
1366                            },
1367                        ))
1368                    }
1369                    Indices::U32(vec) => {
1370                        FourIterators::Fourth(vec.as_slice().windows(3).enumerate().flat_map(
1371                            move |(i, indices)| {
1372                                if i % 2 == 0 {
1373                                    indices_to_triangle(vertices, indices)
1374                                } else {
1375                                    indices_to_triangle(
1376                                        vertices,
1377                                        &[indices[1], indices[0], indices[2]],
1378                                    )
1379                                }
1380                            },
1381                        ))
1382                    }
1383                };
1384
1385                return Ok(iterator);
1386            }
1387
1388            _ => {
1389                return Err(MeshTrianglesError::WrongTopology);
1390            }
1391        };
1392
1393        fn indices_to_triangle<T: TryInto<usize> + Copy>(
1394            vertices: &[[f32; 3]],
1395            indices: &[T],
1396        ) -> Option<Triangle3d> {
1397            let vert0: Vec3 = Vec3::from(*vertices.get(indices[0].try_into().ok()?)?);
1398            let vert1: Vec3 = Vec3::from(*vertices.get(indices[1].try_into().ok()?)?);
1399            let vert2: Vec3 = Vec3::from(*vertices.get(indices[2].try_into().ok()?)?);
1400            Some(Triangle3d {
1401                vertices: [vert0, vert1, vert2],
1402            })
1403        }
1404    }
1405}
1406
1407impl core::ops::Mul<Mesh> for Transform {
1408    type Output = Mesh;
1409
1410    fn mul(self, rhs: Mesh) -> Self::Output {
1411        rhs.transformed_by(self)
1412    }
1413}
1414
1415/// A version of [`Mesh`] suitable for serializing for short-term transfer.
1416///
1417/// [`Mesh`] does not implement [`Serialize`] / [`Deserialize`] because it is made with the renderer in mind.
1418/// It is not a general-purpose mesh implementation, and its internals are subject to frequent change.
1419/// As such, storing a [`Mesh`] on disk is highly discouraged.
1420///
1421/// But there are still some valid use cases for serializing a [`Mesh`], namely transferring meshes between processes.
1422/// To support this, you can create a [`SerializedMesh`] from a [`Mesh`] with [`SerializedMesh::from_mesh`],
1423/// and then deserialize it with [`SerializedMesh::deserialize`]. The caveats are:
1424/// - The mesh representation is not valid across different versions of Bevy.
1425/// - This conversion is lossy. Only the following information is preserved:
1426///   - Primitive topology
1427///   - Vertex attributes
1428///   - Indices
1429/// - Custom attributes that were not specified with [`MeshDeserializer::add_custom_vertex_attribute`] will be ignored while deserializing.
1430#[cfg(feature = "serialize")]
1431#[derive(Debug, Clone, Serialize, Deserialize)]
1432pub struct SerializedMesh {
1433    primitive_topology: PrimitiveTopology,
1434    attributes: Vec<(MeshVertexAttributeId, SerializedMeshAttributeData)>,
1435    indices: Option<Indices>,
1436}
1437
1438#[cfg(feature = "serialize")]
1439impl SerializedMesh {
1440    /// Create a [`SerializedMesh`] from a [`Mesh`]. See the documentation for [`SerializedMesh`] for caveats.
1441    pub fn from_mesh(mesh: Mesh) -> Self {
1442        Self {
1443            primitive_topology: mesh.primitive_topology,
1444            attributes: mesh
1445                .attributes
1446                .into_iter()
1447                .map(|(id, data)| {
1448                    (
1449                        id,
1450                        SerializedMeshAttributeData::from_mesh_attribute_data(data),
1451                    )
1452                })
1453                .collect(),
1454            indices: mesh.indices,
1455        }
1456    }
1457
1458    /// Create a [`Mesh`] from a [`SerializedMesh`]. See the documentation for [`SerializedMesh`] for caveats.
1459    ///
1460    /// Use [`MeshDeserializer`] if you need to pass extra options to the deserialization process, such as specifying custom vertex attributes.
1461    pub fn into_mesh(self) -> Mesh {
1462        MeshDeserializer::default().deserialize(self)
1463    }
1464}
1465
1466/// Use to specify extra options when deserializing a [`SerializedMesh`] into a [`Mesh`].
1467#[cfg(feature = "serialize")]
1468pub struct MeshDeserializer {
1469    custom_vertex_attributes: HashMap<Box<str>, MeshVertexAttribute>,
1470}
1471
1472#[cfg(feature = "serialize")]
1473impl Default for MeshDeserializer {
1474    fn default() -> Self {
1475        // Written like this so that the compiler can validate that we use all the built-in attributes.
1476        // If you just added a new attribute and got a compile error, please add it to this list :)
1477        const BUILTINS: [MeshVertexAttribute; Mesh::FIRST_AVAILABLE_CUSTOM_ATTRIBUTE as usize] = [
1478            Mesh::ATTRIBUTE_POSITION,
1479            Mesh::ATTRIBUTE_NORMAL,
1480            Mesh::ATTRIBUTE_UV_0,
1481            Mesh::ATTRIBUTE_UV_1,
1482            Mesh::ATTRIBUTE_TANGENT,
1483            Mesh::ATTRIBUTE_COLOR,
1484            Mesh::ATTRIBUTE_JOINT_WEIGHT,
1485            Mesh::ATTRIBUTE_JOINT_INDEX,
1486        ];
1487        Self {
1488            custom_vertex_attributes: BUILTINS
1489                .into_iter()
1490                .map(|attribute| (attribute.name.into(), attribute))
1491                .collect(),
1492        }
1493    }
1494}
1495
1496#[cfg(feature = "serialize")]
1497impl MeshDeserializer {
1498    /// Create a new [`MeshDeserializer`].
1499    pub fn new() -> Self {
1500        Self::default()
1501    }
1502
1503    /// Register a custom vertex attribute to the deserializer. Custom vertex attributes that were not added with this method will be ignored while deserializing.
1504    pub fn add_custom_vertex_attribute(
1505        &mut self,
1506        name: &str,
1507        attribute: MeshVertexAttribute,
1508    ) -> &mut Self {
1509        self.custom_vertex_attributes.insert(name.into(), attribute);
1510        self
1511    }
1512
1513    /// Deserialize a [`SerializedMesh`] into a [`Mesh`].
1514    ///
1515    /// See the documentation for [`SerializedMesh`] for caveats.
1516    pub fn deserialize(&self, serialized_mesh: SerializedMesh) -> Mesh {
1517        Mesh {
1518            attributes:
1519                serialized_mesh
1520                .attributes
1521                .into_iter()
1522                .filter_map(|(id, data)| {
1523                    let attribute = data.attribute.clone();
1524                    let Some(data) =
1525                        data.try_into_mesh_attribute_data(&self.custom_vertex_attributes)
1526                    else {
1527                        warn!(
1528                            "Deserialized mesh contains custom vertex attribute {attribute:?} that \
1529                            was not specified with `MeshDeserializer::add_custom_vertex_attribute`. Ignoring."
1530                        );
1531                        return None;
1532                    };
1533                    Some((id, data))
1534                })
1535                .collect(),
1536            indices: serialized_mesh.indices,
1537            ..Mesh::new(serialized_mesh.primitive_topology, RenderAssetUsages::default())
1538        }
1539    }
1540}
1541
1542/// Error that can occur when calling [`Mesh::merge`].
1543#[derive(Error, Debug, Clone)]
1544pub enum MeshMergeError {
1545    #[error("Incompatible vertex attribute types: {} and {}", self_attribute.name, other_attribute.map(|a| a.name).unwrap_or("None"))]
1546    IncompatibleVertexAttributes {
1547        self_attribute: MeshVertexAttribute,
1548        other_attribute: Option<MeshVertexAttribute>,
1549    },
1550    #[error(
1551        "Incompatible primitive topologies: {:?} and {:?}",
1552        self_primitive_topology,
1553        other_primitive_topology
1554    )]
1555    IncompatiblePrimitiveTopology {
1556        self_primitive_topology: PrimitiveTopology,
1557        other_primitive_topology: PrimitiveTopology,
1558    },
1559}
1560
1561#[cfg(test)]
1562mod tests {
1563    use super::Mesh;
1564    #[cfg(feature = "serialize")]
1565    use super::SerializedMesh;
1566    use crate::mesh::{Indices, MeshWindingInvertError, VertexAttributeValues};
1567    use crate::PrimitiveTopology;
1568    use bevy_asset::RenderAssetUsages;
1569    use bevy_math::primitives::Triangle3d;
1570    use bevy_math::Vec3;
1571    use bevy_transform::components::Transform;
1572
1573    #[test]
1574    #[should_panic]
1575    fn panic_invalid_format() {
1576        let _mesh = Mesh::new(
1577            PrimitiveTopology::TriangleList,
1578            RenderAssetUsages::default(),
1579        )
1580        .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, vec![[0.0, 0.0, 0.0]]);
1581    }
1582
1583    #[test]
1584    fn transform_mesh() {
1585        let mesh = Mesh::new(
1586            PrimitiveTopology::TriangleList,
1587            RenderAssetUsages::default(),
1588        )
1589        .with_inserted_attribute(
1590            Mesh::ATTRIBUTE_POSITION,
1591            vec![[-1., -1., 2.], [1., -1., 2.], [0., 1., 2.]],
1592        )
1593        .with_inserted_attribute(
1594            Mesh::ATTRIBUTE_NORMAL,
1595            vec![
1596                Vec3::new(-1., -1., 1.).normalize().to_array(),
1597                Vec3::new(1., -1., 1.).normalize().to_array(),
1598                [0., 0., 1.],
1599            ],
1600        )
1601        .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, vec![[0., 0.], [1., 0.], [0.5, 1.]]);
1602
1603        let mesh = mesh.transformed_by(
1604            Transform::from_translation(Vec3::splat(-2.)).with_scale(Vec3::new(2., 0., -1.)),
1605        );
1606
1607        if let Some(VertexAttributeValues::Float32x3(positions)) =
1608            mesh.attribute(Mesh::ATTRIBUTE_POSITION)
1609        {
1610            // All positions are first scaled resulting in `vec![[-2, 0., -2.], [2., 0., -2.], [0., 0., -2.]]`
1611            // and then shifted by `-2.` along each axis
1612            assert_eq!(
1613                positions,
1614                &vec![[-4.0, -2.0, -4.0], [0.0, -2.0, -4.0], [-2.0, -2.0, -4.0]]
1615            );
1616        } else {
1617            panic!("Mesh does not have a position attribute");
1618        }
1619
1620        if let Some(VertexAttributeValues::Float32x3(normals)) =
1621            mesh.attribute(Mesh::ATTRIBUTE_NORMAL)
1622        {
1623            assert_eq!(normals, &vec![[0., -1., 0.], [0., -1., 0.], [0., 0., -1.]]);
1624        } else {
1625            panic!("Mesh does not have a normal attribute");
1626        }
1627
1628        if let Some(VertexAttributeValues::Float32x2(uvs)) = mesh.attribute(Mesh::ATTRIBUTE_UV_0) {
1629            assert_eq!(uvs, &vec![[0., 0.], [1., 0.], [0.5, 1.]]);
1630        } else {
1631            panic!("Mesh does not have a uv attribute");
1632        }
1633    }
1634
1635    #[test]
1636    fn point_list_mesh_invert_winding() {
1637        let mesh = Mesh::new(PrimitiveTopology::PointList, RenderAssetUsages::default())
1638            .with_inserted_indices(Indices::U32(vec![]));
1639        assert!(matches!(
1640            mesh.with_inverted_winding(),
1641            Err(MeshWindingInvertError::WrongTopology)
1642        ));
1643    }
1644
1645    #[test]
1646    fn line_list_mesh_invert_winding() {
1647        let mesh = Mesh::new(PrimitiveTopology::LineList, RenderAssetUsages::default())
1648            .with_inserted_indices(Indices::U32(vec![0, 1, 1, 2, 2, 3]));
1649        let mesh = mesh.with_inverted_winding().unwrap();
1650        assert_eq!(
1651            mesh.indices().unwrap().iter().collect::<Vec<usize>>(),
1652            vec![3, 2, 2, 1, 1, 0]
1653        );
1654    }
1655
1656    #[test]
1657    fn line_list_mesh_invert_winding_fail() {
1658        let mesh = Mesh::new(PrimitiveTopology::LineList, RenderAssetUsages::default())
1659            .with_inserted_indices(Indices::U32(vec![0, 1, 1]));
1660        assert!(matches!(
1661            mesh.with_inverted_winding(),
1662            Err(MeshWindingInvertError::AbruptIndicesEnd)
1663        ));
1664    }
1665
1666    #[test]
1667    fn line_strip_mesh_invert_winding() {
1668        let mesh = Mesh::new(PrimitiveTopology::LineStrip, RenderAssetUsages::default())
1669            .with_inserted_indices(Indices::U32(vec![0, 1, 2, 3]));
1670        let mesh = mesh.with_inverted_winding().unwrap();
1671        assert_eq!(
1672            mesh.indices().unwrap().iter().collect::<Vec<usize>>(),
1673            vec![3, 2, 1, 0]
1674        );
1675    }
1676
1677    #[test]
1678    fn triangle_list_mesh_invert_winding() {
1679        let mesh = Mesh::new(
1680            PrimitiveTopology::TriangleList,
1681            RenderAssetUsages::default(),
1682        )
1683        .with_inserted_indices(Indices::U32(vec![
1684            0, 3, 1, // First triangle
1685            1, 3, 2, // Second triangle
1686        ]));
1687        let mesh = mesh.with_inverted_winding().unwrap();
1688        assert_eq!(
1689            mesh.indices().unwrap().iter().collect::<Vec<usize>>(),
1690            vec![
1691                0, 1, 3, // First triangle
1692                1, 2, 3, // Second triangle
1693            ]
1694        );
1695    }
1696
1697    #[test]
1698    fn triangle_list_mesh_invert_winding_fail() {
1699        let mesh = Mesh::new(
1700            PrimitiveTopology::TriangleList,
1701            RenderAssetUsages::default(),
1702        )
1703        .with_inserted_indices(Indices::U32(vec![0, 3, 1, 2]));
1704        assert!(matches!(
1705            mesh.with_inverted_winding(),
1706            Err(MeshWindingInvertError::AbruptIndicesEnd)
1707        ));
1708    }
1709
1710    #[test]
1711    fn triangle_strip_mesh_invert_winding() {
1712        let mesh = Mesh::new(
1713            PrimitiveTopology::TriangleStrip,
1714            RenderAssetUsages::default(),
1715        )
1716        .with_inserted_indices(Indices::U32(vec![0, 1, 2, 3]));
1717        let mesh = mesh.with_inverted_winding().unwrap();
1718        assert_eq!(
1719            mesh.indices().unwrap().iter().collect::<Vec<usize>>(),
1720            vec![3, 2, 1, 0]
1721        );
1722    }
1723
1724    #[test]
1725    fn compute_area_weighted_normals() {
1726        let mut mesh = Mesh::new(
1727            PrimitiveTopology::TriangleList,
1728            RenderAssetUsages::default(),
1729        );
1730
1731        //  z      y
1732        //  |    /
1733        //  3---2
1734        //  | /  \
1735        //  0-----1--x
1736
1737        mesh.insert_attribute(
1738            Mesh::ATTRIBUTE_POSITION,
1739            vec![[0., 0., 0.], [1., 0., 0.], [0., 1., 0.], [0., 0., 1.]],
1740        );
1741        mesh.insert_indices(Indices::U16(vec![0, 1, 2, 0, 2, 3]));
1742        mesh.compute_area_weighted_normals();
1743        let normals = mesh
1744            .attribute(Mesh::ATTRIBUTE_NORMAL)
1745            .unwrap()
1746            .as_float3()
1747            .unwrap();
1748        assert_eq!(4, normals.len());
1749        // 0
1750        assert_eq!(Vec3::new(1., 0., 1.).normalize().to_array(), normals[0]);
1751        // 1
1752        assert_eq!([0., 0., 1.], normals[1]);
1753        // 2
1754        assert_eq!(Vec3::new(1., 0., 1.).normalize().to_array(), normals[2]);
1755        // 3
1756        assert_eq!([1., 0., 0.], normals[3]);
1757    }
1758
1759    #[test]
1760    fn compute_area_weighted_normals_proportionate() {
1761        let mut mesh = Mesh::new(
1762            PrimitiveTopology::TriangleList,
1763            RenderAssetUsages::default(),
1764        );
1765
1766        //  z      y
1767        //  |    /
1768        //  3---2..
1769        //  | /    \
1770        //  0-------1---x
1771
1772        mesh.insert_attribute(
1773            Mesh::ATTRIBUTE_POSITION,
1774            vec![[0., 0., 0.], [2., 0., 0.], [0., 1., 0.], [0., 0., 1.]],
1775        );
1776        mesh.insert_indices(Indices::U16(vec![0, 1, 2, 0, 2, 3]));
1777        mesh.compute_area_weighted_normals();
1778        let normals = mesh
1779            .attribute(Mesh::ATTRIBUTE_NORMAL)
1780            .unwrap()
1781            .as_float3()
1782            .unwrap();
1783        assert_eq!(4, normals.len());
1784        // 0
1785        assert_eq!(Vec3::new(1., 0., 2.).normalize().to_array(), normals[0]);
1786        // 1
1787        assert_eq!([0., 0., 1.], normals[1]);
1788        // 2
1789        assert_eq!(Vec3::new(1., 0., 2.).normalize().to_array(), normals[2]);
1790        // 3
1791        assert_eq!([1., 0., 0.], normals[3]);
1792    }
1793
1794    #[test]
1795    fn compute_angle_weighted_normals() {
1796        // CuboidMeshBuilder duplicates vertices (even though it is indexed)
1797
1798        //   5---------4
1799        //  /|        /|
1800        // 1-+-------0 |
1801        // | 6-------|-7
1802        // |/        |/
1803        // 2---------3
1804        let verts = vec![
1805            [1.0, 1.0, 1.0],
1806            [-1.0, 1.0, 1.0],
1807            [-1.0, -1.0, 1.0],
1808            [1.0, -1.0, 1.0],
1809            [1.0, 1.0, -1.0],
1810            [-1.0, 1.0, -1.0],
1811            [-1.0, -1.0, -1.0],
1812            [1.0, -1.0, -1.0],
1813        ];
1814
1815        let indices = Indices::U16(vec![
1816            0, 1, 2, 2, 3, 0, // front
1817            5, 4, 7, 7, 6, 5, // back
1818            1, 5, 6, 6, 2, 1, // left
1819            4, 0, 3, 3, 7, 4, // right
1820            4, 5, 1, 1, 0, 4, // top
1821            3, 2, 6, 6, 7, 3, // bottom
1822        ]);
1823        let mut mesh = Mesh::new(
1824            PrimitiveTopology::TriangleList,
1825            RenderAssetUsages::default(),
1826        );
1827        mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, verts);
1828        mesh.insert_indices(indices);
1829        mesh.compute_smooth_normals();
1830
1831        let normals = mesh
1832            .attribute(Mesh::ATTRIBUTE_NORMAL)
1833            .unwrap()
1834            .as_float3()
1835            .unwrap();
1836
1837        for new in normals.iter().copied().flatten() {
1838            // std impl is unstable
1839            const FRAC_1_SQRT_3: f32 = 0.57735026;
1840            const MIN: f32 = FRAC_1_SQRT_3 - f32::EPSILON;
1841            const MAX: f32 = FRAC_1_SQRT_3 + f32::EPSILON;
1842            assert!(new.abs() >= MIN, "{new} < {MIN}");
1843            assert!(new.abs() <= MAX, "{new} > {MAX}");
1844        }
1845    }
1846
1847    #[test]
1848    fn triangles_from_triangle_list() {
1849        let mut mesh = Mesh::new(
1850            PrimitiveTopology::TriangleList,
1851            RenderAssetUsages::default(),
1852        );
1853        mesh.insert_attribute(
1854            Mesh::ATTRIBUTE_POSITION,
1855            vec![[0., 0., 0.], [1., 0., 0.], [1., 1., 0.], [0., 1., 0.]],
1856        );
1857        mesh.insert_indices(Indices::U32(vec![0, 1, 2, 2, 3, 0]));
1858        assert_eq!(
1859            vec![
1860                Triangle3d {
1861                    vertices: [
1862                        Vec3::new(0., 0., 0.),
1863                        Vec3::new(1., 0., 0.),
1864                        Vec3::new(1., 1., 0.),
1865                    ]
1866                },
1867                Triangle3d {
1868                    vertices: [
1869                        Vec3::new(1., 1., 0.),
1870                        Vec3::new(0., 1., 0.),
1871                        Vec3::new(0., 0., 0.),
1872                    ]
1873                }
1874            ],
1875            mesh.triangles().unwrap().collect::<Vec<Triangle3d>>()
1876        );
1877    }
1878
1879    #[test]
1880    fn triangles_from_triangle_strip() {
1881        let mut mesh = Mesh::new(
1882            PrimitiveTopology::TriangleStrip,
1883            RenderAssetUsages::default(),
1884        );
1885        // Triangles: (0, 1, 2), (2, 1, 3), (2, 3, 4), (4, 3, 5)
1886        //
1887        // 4 - 5
1888        // | \ |
1889        // 2 - 3
1890        // | \ |
1891        // 0 - 1
1892        let positions: Vec<Vec3> = [
1893            [0., 0., 0.],
1894            [1., 0., 0.],
1895            [0., 1., 0.],
1896            [1., 1., 0.],
1897            [0., 2., 0.],
1898            [1., 2., 0.],
1899        ]
1900        .into_iter()
1901        .map(Vec3::from_array)
1902        .collect();
1903        mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions.clone());
1904        mesh.insert_indices(Indices::U32(vec![0, 1, 2, 3, 4, 5]));
1905        assert_eq!(
1906            vec![
1907                Triangle3d {
1908                    vertices: [positions[0], positions[1], positions[2]]
1909                },
1910                Triangle3d {
1911                    vertices: [positions[2], positions[1], positions[3]]
1912                },
1913                Triangle3d {
1914                    vertices: [positions[2], positions[3], positions[4]]
1915                },
1916                Triangle3d {
1917                    vertices: [positions[4], positions[3], positions[5]]
1918                },
1919            ],
1920            mesh.triangles().unwrap().collect::<Vec<Triangle3d>>()
1921        );
1922    }
1923
1924    #[cfg(feature = "serialize")]
1925    #[test]
1926    fn serialize_deserialize_mesh() {
1927        let mut mesh = Mesh::new(
1928            PrimitiveTopology::TriangleList,
1929            RenderAssetUsages::default(),
1930        );
1931
1932        mesh.insert_attribute(
1933            Mesh::ATTRIBUTE_POSITION,
1934            vec![[0., 0., 0.], [2., 0., 0.], [0., 1., 0.], [0., 0., 1.]],
1935        );
1936        mesh.insert_indices(Indices::U16(vec![0, 1, 2, 0, 2, 3]));
1937
1938        let serialized_mesh = SerializedMesh::from_mesh(mesh.clone());
1939        let serialized_string = serde_json::to_string(&serialized_mesh).unwrap();
1940        let serialized_mesh_from_string: SerializedMesh =
1941            serde_json::from_str(&serialized_string).unwrap();
1942        let deserialized_mesh = serialized_mesh_from_string.into_mesh();
1943        assert_eq!(mesh, deserialized_mesh);
1944    }
1945}