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#[derive(Asset, Debug, Clone, Reflect)]
108#[reflect(Clone)]
109pub struct Mesh {
110 #[reflect(ignore, clone)]
111 primitive_topology: PrimitiveTopology,
112 #[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 pub const ATTRIBUTE_POSITION: MeshVertexAttribute =
130 MeshVertexAttribute::new("Vertex_Position", 0, VertexFormat::Float32x3);
131
132 pub const ATTRIBUTE_NORMAL: MeshVertexAttribute =
137 MeshVertexAttribute::new("Vertex_Normal", 1, VertexFormat::Float32x3);
138
139 pub const ATTRIBUTE_UV_0: MeshVertexAttribute =
154 MeshVertexAttribute::new("Vertex_Uv", 2, VertexFormat::Float32x2);
155
156 pub const ATTRIBUTE_UV_1: MeshVertexAttribute =
164 MeshVertexAttribute::new("Vertex_Uv_1", 3, VertexFormat::Float32x2);
165
166 pub const ATTRIBUTE_TANGENT: MeshVertexAttribute =
172 MeshVertexAttribute::new("Vertex_Tangent", 4, VertexFormat::Float32x4);
173
174 pub const ATTRIBUTE_COLOR: MeshVertexAttribute =
179 MeshVertexAttribute::new("Vertex_Color", 5, VertexFormat::Float32x4);
180
181 pub const ATTRIBUTE_JOINT_WEIGHT: MeshVertexAttribute =
186 MeshVertexAttribute::new("Vertex_JointWeight", 6, VertexFormat::Float32x4);
187
188 pub const ATTRIBUTE_JOINT_INDEX: MeshVertexAttribute =
193 MeshVertexAttribute::new("Vertex_JointIndex", 7, VertexFormat::Uint16x4);
194
195 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 pub fn primitive_topology(&self) -> PrimitiveTopology {
211 self.primitive_topology
212 }
213
214 #[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 #[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 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 #[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 #[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 #[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 #[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 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 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 #[inline]
335 pub fn insert_indices(&mut self, indices: Indices) {
336 self.indices = Some(indices);
337 }
338
339 #[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 #[inline]
353 pub fn indices(&self) -> Option<&Indices> {
354 self.indices.as_ref()
355 }
356
357 #[inline]
359 pub fn indices_mut(&mut self) -> Option<&mut Indices> {
360 self.indices.as_mut()
361 }
362
363 #[inline]
365 pub fn remove_indices(&mut self) -> Option<Indices> {
366 core::mem::take(&mut self.indices)
367 }
368
369 #[must_use]
373 pub fn with_removed_indices(mut self) -> Self {
374 self.remove_indices();
375 self
376 }
377
378 pub fn get_vertex_size(&self) -> u64 {
380 self.attributes
381 .values()
382 .map(|data| data.attribute.format.size())
383 .sum()
384 }
385
386 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 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 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 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 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 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 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 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 #[must_use]
559 pub fn with_duplicated_vertices(mut self) -> Self {
560 self.duplicate_vertices();
561 self
562 }
563
564 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 if indices.len() % 3 != 0 {
579 return Err(MeshWindingInvertError::AbruptIndicesEnd);
580 }
581 for chunk in indices.chunks_mut(3) {
582 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 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 pub fn with_inverted_winding(mut self) -> Result<Self, MeshWindingInvertError> {
617 self.invert_winding().map(|_| self)
618 }
619
620 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 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 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 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 #[must_use]
740 pub fn with_computed_normals(mut self) -> Self {
741 self.compute_normals();
742 self
743 }
744
745 #[must_use]
754 pub fn with_computed_flat_normals(mut self) -> Self {
755 self.compute_flat_normals();
756 self
757 }
758
759 #[must_use]
768 pub fn with_computed_smooth_normals(mut self) -> Self {
769 self.compute_smooth_normals();
770 self
771 }
772
773 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 pub fn with_generated_tangents(mut self) -> Result<Mesh, GenerateTangentsError> {
791 self.generate_tangents()?;
792 Ok(self)
793 }
794
795 pub fn merge(&mut self, other: &Mesh) -> Result<(), MergeMeshError> {
806 use VertexAttributeValues::*;
807
808 let index_offset = self.count_vertices();
810
811 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 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 pub fn transformed_by(mut self, transform: Transform) -> Self {
870 self.transform_by(transform);
871 self
872 }
873
874 pub fn transform_by(&mut self, transform: Transform) {
878 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 positions
890 .iter_mut()
891 .for_each(|pos| *pos = transform.transform_point(Vec3::from_slice(pos)).to_array());
892 }
893
894 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 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 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 pub fn translated_by(mut self, translation: Vec3) -> Self {
931 self.translate_by(translation);
932 self
933 }
934
935 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 positions
948 .iter_mut()
949 .for_each(|pos| *pos = (Vec3::from_slice(pos) + translation).to_array());
950 }
951 }
952
953 pub fn rotated_by(mut self, rotation: Quat) -> Self {
957 self.rotate_by(rotation);
958 self
959 }
960
961 pub fn rotate_by(&mut self, rotation: Quat) {
965 if let Some(VertexAttributeValues::Float32x3(positions)) =
966 self.attribute_mut(Mesh::ATTRIBUTE_POSITION)
967 {
968 positions
970 .iter_mut()
971 .for_each(|pos| *pos = (rotation * Vec3::from_slice(pos)).to_array());
972 }
973
974 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 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 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 pub fn scaled_by(mut self, scale: Vec3) -> Self {
1005 self.scale_by(scale);
1006 self
1007 }
1008
1009 pub fn scale_by(&mut self, scale: Vec3) {
1013 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 positions
1025 .iter_mut()
1026 .for_each(|pos| *pos = (scale * Vec3::from_slice(pos)).to_array());
1027 }
1028
1029 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 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 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 pub fn has_morph_targets(&self) -> bool {
1060 self.morph_targets.is_some()
1061 }
1062
1063 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 #[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 pub fn set_morph_target_names(&mut self, names: Vec<String>) {
1089 self.morph_target_names = Some(names);
1090 }
1091
1092 #[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 pub fn morph_target_names(&self) -> Option<&[String]> {
1104 self.morph_target_names.as_deref()
1105 }
1106
1107 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 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 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 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 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 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#[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 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, 1, 3, 2, ]));
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, 1, 2, 3, ]
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 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 assert_eq!(Vec3::new(1., 0., 1.).normalize().to_array(), normals[0]);
1435 assert_eq!([0., 0., 1.], normals[1]);
1437 assert_eq!(Vec3::new(1., 0., 1.).normalize().to_array(), normals[2]);
1439 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 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 assert_eq!(Vec3::new(1., 0., 2.).normalize().to_array(), normals[0]);
1470 assert_eq!([0., 0., 1.], normals[1]);
1472 assert_eq!(Vec3::new(1., 0., 2.).normalize().to_array(), normals[2]);
1474 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 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}