1use bevy_transform::components::Transform;
2pub use wgpu::PrimitiveTopology;
3
4use super::{
5 face_normal, generate_tangents_for_mesh, scale_normal, FourIterators, GenerateTangentsError,
6 Indices, MeshAttributeData, MeshTrianglesError, MeshVertexAttribute, MeshVertexAttributeId,
7 MeshVertexBufferLayout, MeshVertexBufferLayoutRef, MeshVertexBufferLayouts,
8 MeshWindingInvertError, VertexAttributeValues, VertexBufferLayout, VertexFormatSize,
9};
10use alloc::collections::BTreeMap;
11use bevy_asset::{Asset, Handle, RenderAssetUsages};
12use bevy_image::Image;
13use bevy_math::{primitives::Triangle3d, *};
14use bevy_reflect::Reflect;
15use bevy_utils::tracing::warn;
16use bytemuck::cast_slice;
17use wgpu::{VertexAttribute, VertexFormat, VertexStepMode};
18
19pub const INDEX_BUFFER_ASSET_INDEX: u64 = 0;
20pub const VERTEX_ATTRIBUTE_BUFFER_ID: u64 = 10;
21
22#[derive(Asset, Debug, Clone, Reflect)]
107pub struct Mesh {
108 #[reflect(ignore)]
109 primitive_topology: PrimitiveTopology,
110 #[reflect(ignore)]
115 attributes: BTreeMap<MeshVertexAttributeId, MeshAttributeData>,
116 indices: Option<Indices>,
117 morph_targets: Option<Handle<Image>>,
118 morph_target_names: Option<Vec<String>>,
119 pub asset_usage: RenderAssetUsages,
120}
121
122impl Mesh {
123 pub const ATTRIBUTE_POSITION: MeshVertexAttribute =
128 MeshVertexAttribute::new("Vertex_Position", 0, VertexFormat::Float32x3);
129
130 pub const ATTRIBUTE_NORMAL: MeshVertexAttribute =
135 MeshVertexAttribute::new("Vertex_Normal", 1, VertexFormat::Float32x3);
136
137 pub const ATTRIBUTE_UV_0: MeshVertexAttribute =
152 MeshVertexAttribute::new("Vertex_Uv", 2, VertexFormat::Float32x2);
153
154 pub const ATTRIBUTE_UV_1: MeshVertexAttribute =
162 MeshVertexAttribute::new("Vertex_Uv_1", 3, VertexFormat::Float32x2);
163
164 pub const ATTRIBUTE_TANGENT: MeshVertexAttribute =
170 MeshVertexAttribute::new("Vertex_Tangent", 4, VertexFormat::Float32x4);
171
172 pub const ATTRIBUTE_COLOR: MeshVertexAttribute =
177 MeshVertexAttribute::new("Vertex_Color", 5, VertexFormat::Float32x4);
178
179 pub const ATTRIBUTE_JOINT_WEIGHT: MeshVertexAttribute =
184 MeshVertexAttribute::new("Vertex_JointWeight", 6, VertexFormat::Float32x4);
185
186 pub const ATTRIBUTE_JOINT_INDEX: MeshVertexAttribute =
191 MeshVertexAttribute::new("Vertex_JointIndex", 7, VertexFormat::Uint16x4);
192
193 pub fn new(primitive_topology: PrimitiveTopology, asset_usage: RenderAssetUsages) -> Self {
197 Mesh {
198 primitive_topology,
199 attributes: Default::default(),
200 indices: None,
201 morph_targets: None,
202 morph_target_names: None,
203 asset_usage,
204 }
205 }
206
207 pub fn primitive_topology(&self) -> PrimitiveTopology {
209 self.primitive_topology
210 }
211
212 #[inline]
220 pub fn insert_attribute(
221 &mut self,
222 attribute: MeshVertexAttribute,
223 values: impl Into<VertexAttributeValues>,
224 ) {
225 let values = values.into();
226 let values_format = VertexFormat::from(&values);
227 if values_format != attribute.format {
228 panic!(
229 "Failed to insert attribute. Invalid attribute format for {}. Given format is {values_format:?} but expected {:?}",
230 attribute.name, attribute.format
231 );
232 }
233
234 self.attributes
235 .insert(attribute.id, MeshAttributeData { attribute, values });
236 }
237
238 #[must_use]
248 #[inline]
249 pub fn with_inserted_attribute(
250 mut self,
251 attribute: MeshVertexAttribute,
252 values: impl Into<VertexAttributeValues>,
253 ) -> Self {
254 self.insert_attribute(attribute, values);
255 self
256 }
257
258 pub fn remove_attribute(
260 &mut self,
261 attribute: impl Into<MeshVertexAttributeId>,
262 ) -> Option<VertexAttributeValues> {
263 self.attributes
264 .remove(&attribute.into())
265 .map(|data| data.values)
266 }
267
268 #[must_use]
272 pub fn with_removed_attribute(mut self, attribute: impl Into<MeshVertexAttributeId>) -> Self {
273 self.remove_attribute(attribute);
274 self
275 }
276
277 #[inline]
278 pub fn contains_attribute(&self, id: impl Into<MeshVertexAttributeId>) -> bool {
279 self.attributes.contains_key(&id.into())
280 }
281
282 #[inline]
284 pub fn attribute(
285 &self,
286 id: impl Into<MeshVertexAttributeId>,
287 ) -> Option<&VertexAttributeValues> {
288 self.attributes.get(&id.into()).map(|data| &data.values)
289 }
290
291 #[inline]
293 pub fn attribute_mut(
294 &mut self,
295 id: impl Into<MeshVertexAttributeId>,
296 ) -> Option<&mut VertexAttributeValues> {
297 self.attributes
298 .get_mut(&id.into())
299 .map(|data| &mut data.values)
300 }
301
302 pub fn attributes(
304 &self,
305 ) -> impl Iterator<Item = (&MeshVertexAttribute, &VertexAttributeValues)> {
306 self.attributes
307 .values()
308 .map(|data| (&data.attribute, &data.values))
309 }
310
311 pub fn attributes_mut(
313 &mut self,
314 ) -> impl Iterator<Item = (&MeshVertexAttribute, &mut VertexAttributeValues)> {
315 self.attributes
316 .values_mut()
317 .map(|data| (&data.attribute, &mut data.values))
318 }
319
320 #[inline]
324 pub fn insert_indices(&mut self, indices: Indices) {
325 self.indices = Some(indices);
326 }
327
328 #[must_use]
334 #[inline]
335 pub fn with_inserted_indices(mut self, indices: Indices) -> Self {
336 self.insert_indices(indices);
337 self
338 }
339
340 #[inline]
342 pub fn indices(&self) -> Option<&Indices> {
343 self.indices.as_ref()
344 }
345
346 #[inline]
348 pub fn indices_mut(&mut self) -> Option<&mut Indices> {
349 self.indices.as_mut()
350 }
351
352 #[inline]
354 pub fn remove_indices(&mut self) -> Option<Indices> {
355 core::mem::take(&mut self.indices)
356 }
357
358 #[must_use]
362 pub fn with_removed_indices(mut self) -> Self {
363 self.remove_indices();
364 self
365 }
366
367 pub fn get_vertex_size(&self) -> u64 {
369 self.attributes
370 .values()
371 .map(|data| data.attribute.format.get_size())
372 .sum()
373 }
374
375 pub fn get_vertex_buffer_size(&self) -> usize {
377 let vertex_size = self.get_vertex_size() as usize;
378 let vertex_count = self.count_vertices();
379 vertex_count * vertex_size
380 }
381
382 pub fn get_index_buffer_bytes(&self) -> Option<&[u8]> {
385 self.indices.as_ref().map(|indices| match &indices {
386 Indices::U16(indices) => cast_slice(&indices[..]),
387 Indices::U32(indices) => cast_slice(&indices[..]),
388 })
389 }
390
391 pub fn get_mesh_vertex_buffer_layout(
393 &self,
394 mesh_vertex_buffer_layouts: &mut MeshVertexBufferLayouts,
395 ) -> MeshVertexBufferLayoutRef {
396 let mut attributes = Vec::with_capacity(self.attributes.len());
397 let mut attribute_ids = Vec::with_capacity(self.attributes.len());
398 let mut accumulated_offset = 0;
399 for (index, data) in self.attributes.values().enumerate() {
400 attribute_ids.push(data.attribute.id);
401 attributes.push(VertexAttribute {
402 offset: accumulated_offset,
403 format: data.attribute.format,
404 shader_location: index as u32,
405 });
406 accumulated_offset += data.attribute.format.get_size();
407 }
408
409 let layout = MeshVertexBufferLayout {
410 layout: VertexBufferLayout {
411 array_stride: accumulated_offset,
412 step_mode: VertexStepMode::Vertex,
413 attributes,
414 },
415 attribute_ids,
416 };
417 mesh_vertex_buffer_layouts.insert(layout)
418 }
419
420 pub fn count_vertices(&self) -> usize {
424 let mut vertex_count: Option<usize> = None;
425 for (attribute_id, attribute_data) in &self.attributes {
426 let attribute_len = attribute_data.values.len();
427 if let Some(previous_vertex_count) = vertex_count {
428 if previous_vertex_count != attribute_len {
429 let name = self
430 .attributes
431 .get(attribute_id)
432 .map(|data| data.attribute.name.to_string())
433 .unwrap_or_else(|| format!("{attribute_id:?}"));
434
435 warn!("{name} has a different vertex count ({attribute_len}) than other attributes ({previous_vertex_count}) in this mesh, \
436 all attributes will be truncated to match the smallest.");
437 vertex_count = Some(core::cmp::min(previous_vertex_count, attribute_len));
438 }
439 } else {
440 vertex_count = Some(attribute_len);
441 }
442 }
443
444 vertex_count.unwrap_or(0)
445 }
446
447 pub fn create_packed_vertex_buffer_data(&self) -> Vec<u8> {
457 let mut attributes_interleaved_buffer = vec![0; self.get_vertex_buffer_size()];
458 self.write_packed_vertex_buffer_data(&mut attributes_interleaved_buffer);
459 attributes_interleaved_buffer
460 }
461
462 pub fn write_packed_vertex_buffer_data(&self, slice: &mut [u8]) {
469 let vertex_size = self.get_vertex_size() as usize;
470 let vertex_count = self.count_vertices();
471 let mut attribute_offset = 0;
473 for attribute_data in self.attributes.values() {
474 let attribute_size = attribute_data.attribute.format.get_size() as usize;
475 let attributes_bytes = attribute_data.values.get_bytes();
476 for (vertex_index, attribute_bytes) in attributes_bytes
477 .chunks_exact(attribute_size)
478 .take(vertex_count)
479 .enumerate()
480 {
481 let offset = vertex_index * vertex_size + attribute_offset;
482 slice[offset..offset + attribute_size].copy_from_slice(attribute_bytes);
483 }
484
485 attribute_offset += attribute_size;
486 }
487 }
488
489 #[allow(clippy::match_same_arms)]
494 pub fn duplicate_vertices(&mut self) {
495 fn duplicate<T: Copy>(values: &[T], indices: impl Iterator<Item = usize>) -> Vec<T> {
496 indices.map(|i| values[i]).collect()
497 }
498
499 let Some(indices) = self.indices.take() else {
500 return;
501 };
502
503 for attributes in self.attributes.values_mut() {
504 let indices = indices.iter();
505 match &mut attributes.values {
506 VertexAttributeValues::Float32(vec) => *vec = duplicate(vec, indices),
507 VertexAttributeValues::Sint32(vec) => *vec = duplicate(vec, indices),
508 VertexAttributeValues::Uint32(vec) => *vec = duplicate(vec, indices),
509 VertexAttributeValues::Float32x2(vec) => *vec = duplicate(vec, indices),
510 VertexAttributeValues::Sint32x2(vec) => *vec = duplicate(vec, indices),
511 VertexAttributeValues::Uint32x2(vec) => *vec = duplicate(vec, indices),
512 VertexAttributeValues::Float32x3(vec) => *vec = duplicate(vec, indices),
513 VertexAttributeValues::Sint32x3(vec) => *vec = duplicate(vec, indices),
514 VertexAttributeValues::Uint32x3(vec) => *vec = duplicate(vec, indices),
515 VertexAttributeValues::Sint32x4(vec) => *vec = duplicate(vec, indices),
516 VertexAttributeValues::Uint32x4(vec) => *vec = duplicate(vec, indices),
517 VertexAttributeValues::Float32x4(vec) => *vec = duplicate(vec, indices),
518 VertexAttributeValues::Sint16x2(vec) => *vec = duplicate(vec, indices),
519 VertexAttributeValues::Snorm16x2(vec) => *vec = duplicate(vec, indices),
520 VertexAttributeValues::Uint16x2(vec) => *vec = duplicate(vec, indices),
521 VertexAttributeValues::Unorm16x2(vec) => *vec = duplicate(vec, indices),
522 VertexAttributeValues::Sint16x4(vec) => *vec = duplicate(vec, indices),
523 VertexAttributeValues::Snorm16x4(vec) => *vec = duplicate(vec, indices),
524 VertexAttributeValues::Uint16x4(vec) => *vec = duplicate(vec, indices),
525 VertexAttributeValues::Unorm16x4(vec) => *vec = duplicate(vec, indices),
526 VertexAttributeValues::Sint8x2(vec) => *vec = duplicate(vec, indices),
527 VertexAttributeValues::Snorm8x2(vec) => *vec = duplicate(vec, indices),
528 VertexAttributeValues::Uint8x2(vec) => *vec = duplicate(vec, indices),
529 VertexAttributeValues::Unorm8x2(vec) => *vec = duplicate(vec, indices),
530 VertexAttributeValues::Sint8x4(vec) => *vec = duplicate(vec, indices),
531 VertexAttributeValues::Snorm8x4(vec) => *vec = duplicate(vec, indices),
532 VertexAttributeValues::Uint8x4(vec) => *vec = duplicate(vec, indices),
533 VertexAttributeValues::Unorm8x4(vec) => *vec = duplicate(vec, indices),
534 }
535 }
536 }
537
538 #[must_use]
545 pub fn with_duplicated_vertices(mut self) -> Self {
546 self.duplicate_vertices();
547 self
548 }
549
550 pub fn invert_winding(&mut self) -> Result<(), MeshWindingInvertError> {
557 fn invert<I>(
558 indices: &mut [I],
559 topology: PrimitiveTopology,
560 ) -> Result<(), MeshWindingInvertError> {
561 match topology {
562 PrimitiveTopology::TriangleList => {
563 if indices.len() % 3 != 0 {
565 return Err(MeshWindingInvertError::AbruptIndicesEnd);
566 }
567 for chunk in indices.chunks_mut(3) {
568 let [_, b, c] = chunk else {
570 return Err(MeshWindingInvertError::AbruptIndicesEnd);
571 };
572 core::mem::swap(b, c);
573 }
574 Ok(())
575 }
576 PrimitiveTopology::LineList => {
577 if indices.len() % 2 != 0 {
579 return Err(MeshWindingInvertError::AbruptIndicesEnd);
580 }
581 indices.reverse();
582 Ok(())
583 }
584 PrimitiveTopology::TriangleStrip | PrimitiveTopology::LineStrip => {
585 indices.reverse();
586 Ok(())
587 }
588 _ => Err(MeshWindingInvertError::WrongTopology),
589 }
590 }
591 match &mut self.indices {
592 Some(Indices::U16(vec)) => invert(vec, self.primitive_topology),
593 Some(Indices::U32(vec)) => invert(vec, self.primitive_topology),
594 None => Ok(()),
595 }
596 }
597
598 pub fn with_inverted_winding(mut self) -> Result<Self, MeshWindingInvertError> {
603 self.invert_winding().map(|_| self)
604 }
605
606 pub fn compute_normals(&mut self) {
618 assert!(
619 matches!(self.primitive_topology, PrimitiveTopology::TriangleList),
620 "`compute_normals` can only work on `TriangleList`s"
621 );
622 if self.indices().is_none() {
623 self.compute_flat_normals();
624 } else {
625 self.compute_smooth_normals();
626 }
627 }
628
629 pub fn compute_flat_normals(&mut self) {
641 assert!(
642 self.indices().is_none(),
643 "`compute_flat_normals` can't work on indexed geometry. Consider calling either `Mesh::compute_smooth_normals` or `Mesh::duplicate_vertices` followed by `Mesh::compute_flat_normals`."
644 );
645 assert!(
646 matches!(self.primitive_topology, PrimitiveTopology::TriangleList),
647 "`compute_flat_normals` can only work on `TriangleList`s"
648 );
649
650 let positions = self
651 .attribute(Mesh::ATTRIBUTE_POSITION)
652 .unwrap()
653 .as_float3()
654 .expect("`Mesh::ATTRIBUTE_POSITION` vertex attributes should be of type `float3`");
655
656 let normals: Vec<_> = positions
657 .chunks_exact(3)
658 .map(|p| face_normal(p[0], p[1], p[2]))
659 .flat_map(|normal| [normal; 3])
660 .collect();
661
662 self.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals);
663 }
664
665 pub fn compute_smooth_normals(&mut self) {
677 assert!(
678 matches!(self.primitive_topology, PrimitiveTopology::TriangleList),
679 "`compute_smooth_normals` can only work on `TriangleList`s"
680 );
681 assert!(
682 self.indices().is_some(),
683 "`compute_smooth_normals` can only work on indexed meshes"
684 );
685
686 let positions = self
687 .attribute(Mesh::ATTRIBUTE_POSITION)
688 .unwrap()
689 .as_float3()
690 .expect("`Mesh::ATTRIBUTE_POSITION` vertex attributes should be of type `float3`");
691
692 let mut normals = vec![Vec3::ZERO; positions.len()];
693
694 self.indices()
695 .unwrap()
696 .iter()
697 .collect::<Vec<usize>>()
698 .chunks_exact(3)
699 .for_each(|face| {
700 let [a, b, c] = [face[0], face[1], face[2]];
701 let normal = Vec3::from(face_normal(positions[a], positions[b], positions[c]));
702 [a, b, c].iter().for_each(|pos| {
703 normals[*pos] += normal;
704 });
705 });
706
707 for normal in &mut normals {
710 *normal = normal.try_normalize().unwrap_or(Vec3::ZERO);
711 }
712
713 self.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals);
714 }
715
716 #[must_use]
726 pub fn with_computed_normals(mut self) -> Self {
727 self.compute_normals();
728 self
729 }
730
731 #[must_use]
740 pub fn with_computed_flat_normals(mut self) -> Self {
741 self.compute_flat_normals();
742 self
743 }
744
745 #[must_use]
754 pub fn with_computed_smooth_normals(mut self) -> Self {
755 self.compute_smooth_normals();
756 self
757 }
758
759 pub fn generate_tangents(&mut self) -> Result<(), GenerateTangentsError> {
764 let tangents = generate_tangents_for_mesh(self)?;
765 self.insert_attribute(Mesh::ATTRIBUTE_TANGENT, tangents);
766 Ok(())
767 }
768
769 pub fn with_generated_tangents(mut self) -> Result<Mesh, GenerateTangentsError> {
777 self.generate_tangents()?;
778 Ok(self)
779 }
780
781 #[allow(clippy::match_same_arms)]
792 pub fn merge(&mut self, other: &Mesh) {
793 use VertexAttributeValues::*;
794
795 let index_offset = self
797 .attribute(Mesh::ATTRIBUTE_POSITION)
798 .get_or_insert(&Float32x3(Vec::default()))
799 .len();
800
801 for (attribute, values) in self.attributes_mut() {
803 let enum_variant_name = values.enum_variant_name();
804 if let Some(other_values) = other.attribute(attribute.id) {
805 match (values, other_values) {
806 (Float32(vec1), Float32(vec2)) => vec1.extend(vec2),
807 (Sint32(vec1), Sint32(vec2)) => vec1.extend(vec2),
808 (Uint32(vec1), Uint32(vec2)) => vec1.extend(vec2),
809 (Float32x2(vec1), Float32x2(vec2)) => vec1.extend(vec2),
810 (Sint32x2(vec1), Sint32x2(vec2)) => vec1.extend(vec2),
811 (Uint32x2(vec1), Uint32x2(vec2)) => vec1.extend(vec2),
812 (Float32x3(vec1), Float32x3(vec2)) => vec1.extend(vec2),
813 (Sint32x3(vec1), Sint32x3(vec2)) => vec1.extend(vec2),
814 (Uint32x3(vec1), Uint32x3(vec2)) => vec1.extend(vec2),
815 (Sint32x4(vec1), Sint32x4(vec2)) => vec1.extend(vec2),
816 (Uint32x4(vec1), Uint32x4(vec2)) => vec1.extend(vec2),
817 (Float32x4(vec1), Float32x4(vec2)) => vec1.extend(vec2),
818 (Sint16x2(vec1), Sint16x2(vec2)) => vec1.extend(vec2),
819 (Snorm16x2(vec1), Snorm16x2(vec2)) => vec1.extend(vec2),
820 (Uint16x2(vec1), Uint16x2(vec2)) => vec1.extend(vec2),
821 (Unorm16x2(vec1), Unorm16x2(vec2)) => vec1.extend(vec2),
822 (Sint16x4(vec1), Sint16x4(vec2)) => vec1.extend(vec2),
823 (Snorm16x4(vec1), Snorm16x4(vec2)) => vec1.extend(vec2),
824 (Uint16x4(vec1), Uint16x4(vec2)) => vec1.extend(vec2),
825 (Unorm16x4(vec1), Unorm16x4(vec2)) => vec1.extend(vec2),
826 (Sint8x2(vec1), Sint8x2(vec2)) => vec1.extend(vec2),
827 (Snorm8x2(vec1), Snorm8x2(vec2)) => vec1.extend(vec2),
828 (Uint8x2(vec1), Uint8x2(vec2)) => vec1.extend(vec2),
829 (Unorm8x2(vec1), Unorm8x2(vec2)) => vec1.extend(vec2),
830 (Sint8x4(vec1), Sint8x4(vec2)) => vec1.extend(vec2),
831 (Snorm8x4(vec1), Snorm8x4(vec2)) => vec1.extend(vec2),
832 (Uint8x4(vec1), Uint8x4(vec2)) => vec1.extend(vec2),
833 (Unorm8x4(vec1), Unorm8x4(vec2)) => vec1.extend(vec2),
834 _ => panic!(
835 "Incompatible vertex attribute types {} and {}",
836 enum_variant_name,
837 other_values.enum_variant_name()
838 ),
839 }
840 }
841 }
842
843 if let (Some(indices), Some(other_indices)) = (self.indices_mut(), other.indices()) {
845 match (indices, other_indices) {
846 (Indices::U16(i1), Indices::U16(i2)) => {
847 i1.extend(i2.iter().map(|i| *i + index_offset as u16));
848 }
849 (Indices::U32(i1), Indices::U32(i2)) => {
850 i1.extend(i2.iter().map(|i| *i + index_offset as u32));
851 }
852 (Indices::U16(i1), Indices::U32(i2)) => {
853 i1.extend(i2.iter().map(|i| *i as u16 + index_offset as u16));
854 }
855 (Indices::U32(i1), Indices::U16(i2)) => {
856 i1.extend(i2.iter().map(|i| *i as u32 + index_offset as u32));
857 }
858 }
859 }
860 }
861
862 pub fn transformed_by(mut self, transform: Transform) -> Self {
866 self.transform_by(transform);
867 self
868 }
869
870 pub fn transform_by(&mut self, transform: Transform) {
874 let scale_recip = 1. / transform.scale;
876 debug_assert!(
877 transform.scale.yzx() * transform.scale.zxy() != Vec3::ZERO,
878 "mesh transform scale cannot be zero on more than one axis"
879 );
880
881 if let Some(VertexAttributeValues::Float32x3(ref mut positions)) =
882 self.attribute_mut(Mesh::ATTRIBUTE_POSITION)
883 {
884 positions
886 .iter_mut()
887 .for_each(|pos| *pos = transform.transform_point(Vec3::from_slice(pos)).to_array());
888 }
889
890 if transform.rotation.is_near_identity()
892 && transform.scale.x == transform.scale.y
893 && transform.scale.y == transform.scale.z
894 {
895 return;
896 }
897
898 if let Some(VertexAttributeValues::Float32x3(ref mut normals)) =
899 self.attribute_mut(Mesh::ATTRIBUTE_NORMAL)
900 {
901 normals.iter_mut().for_each(|normal| {
903 *normal = (transform.rotation
904 * scale_normal(Vec3::from_array(*normal), scale_recip))
905 .to_array();
906 });
907 }
908
909 if let Some(VertexAttributeValues::Float32x3(ref mut tangents)) =
910 self.attribute_mut(Mesh::ATTRIBUTE_TANGENT)
911 {
912 tangents.iter_mut().for_each(|tangent| {
914 let scaled_tangent = Vec3::from_slice(tangent) * transform.scale;
915 *tangent = (transform.rotation * scaled_tangent.normalize_or_zero()).to_array();
916 });
917 }
918 }
919
920 pub fn translated_by(mut self, translation: Vec3) -> Self {
924 self.translate_by(translation);
925 self
926 }
927
928 pub fn translate_by(&mut self, translation: Vec3) {
932 if translation == Vec3::ZERO {
933 return;
934 }
935
936 if let Some(VertexAttributeValues::Float32x3(ref mut positions)) =
937 self.attribute_mut(Mesh::ATTRIBUTE_POSITION)
938 {
939 positions
941 .iter_mut()
942 .for_each(|pos| *pos = (Vec3::from_slice(pos) + translation).to_array());
943 }
944 }
945
946 pub fn rotated_by(mut self, rotation: Quat) -> Self {
950 self.rotate_by(rotation);
951 self
952 }
953
954 pub fn rotate_by(&mut self, rotation: Quat) {
958 if let Some(VertexAttributeValues::Float32x3(ref mut positions)) =
959 self.attribute_mut(Mesh::ATTRIBUTE_POSITION)
960 {
961 positions
963 .iter_mut()
964 .for_each(|pos| *pos = (rotation * Vec3::from_slice(pos)).to_array());
965 }
966
967 if rotation.is_near_identity() {
969 return;
970 }
971
972 if let Some(VertexAttributeValues::Float32x3(ref mut normals)) =
973 self.attribute_mut(Mesh::ATTRIBUTE_NORMAL)
974 {
975 normals.iter_mut().for_each(|normal| {
977 *normal = (rotation * Vec3::from_slice(normal).normalize_or_zero()).to_array();
978 });
979 }
980
981 if let Some(VertexAttributeValues::Float32x3(ref mut tangents)) =
982 self.attribute_mut(Mesh::ATTRIBUTE_TANGENT)
983 {
984 tangents.iter_mut().for_each(|tangent| {
986 *tangent = (rotation * Vec3::from_slice(tangent).normalize_or_zero()).to_array();
987 });
988 }
989 }
990
991 pub fn scaled_by(mut self, scale: Vec3) -> Self {
995 self.scale_by(scale);
996 self
997 }
998
999 pub fn scale_by(&mut self, scale: Vec3) {
1003 let scale_recip = 1. / scale;
1005 debug_assert!(
1006 scale.yzx() * scale.zxy() != Vec3::ZERO,
1007 "mesh transform scale cannot be zero on more than one axis"
1008 );
1009
1010 if let Some(VertexAttributeValues::Float32x3(ref mut positions)) =
1011 self.attribute_mut(Mesh::ATTRIBUTE_POSITION)
1012 {
1013 positions
1015 .iter_mut()
1016 .for_each(|pos| *pos = (scale * Vec3::from_slice(pos)).to_array());
1017 }
1018
1019 if scale.x == scale.y && scale.y == scale.z {
1021 return;
1022 }
1023
1024 if let Some(VertexAttributeValues::Float32x3(ref mut normals)) =
1025 self.attribute_mut(Mesh::ATTRIBUTE_NORMAL)
1026 {
1027 normals.iter_mut().for_each(|normal| {
1029 *normal = scale_normal(Vec3::from_array(*normal), scale_recip).to_array();
1030 });
1031 }
1032
1033 if let Some(VertexAttributeValues::Float32x3(ref mut tangents)) =
1034 self.attribute_mut(Mesh::ATTRIBUTE_TANGENT)
1035 {
1036 tangents.iter_mut().for_each(|tangent| {
1038 let scaled_tangent = Vec3::from_slice(tangent) * scale;
1039 *tangent = scaled_tangent.normalize_or_zero().to_array();
1040 });
1041 }
1042 }
1043
1044 pub fn has_morph_targets(&self) -> bool {
1046 self.morph_targets.is_some()
1047 }
1048
1049 pub fn set_morph_targets(&mut self, morph_targets: Handle<Image>) {
1053 self.morph_targets = Some(morph_targets);
1054 }
1055
1056 pub fn morph_targets(&self) -> Option<&Handle<Image>> {
1057 self.morph_targets.as_ref()
1058 }
1059
1060 #[must_use]
1068 pub fn with_morph_targets(mut self, morph_targets: Handle<Image>) -> Self {
1069 self.set_morph_targets(morph_targets);
1070 self
1071 }
1072
1073 pub fn set_morph_target_names(&mut self, names: Vec<String>) {
1075 self.morph_target_names = Some(names);
1076 }
1077
1078 #[must_use]
1083 pub fn with_morph_target_names(mut self, names: Vec<String>) -> Self {
1084 self.set_morph_target_names(names);
1085 self
1086 }
1087
1088 pub fn morph_target_names(&self) -> Option<&[String]> {
1090 self.morph_target_names.as_deref()
1091 }
1092
1093 pub fn normalize_joint_weights(&mut self) {
1095 if let Some(joints) = self.attribute_mut(Self::ATTRIBUTE_JOINT_WEIGHT) {
1096 let VertexAttributeValues::Float32x4(ref mut joints) = joints else {
1097 panic!("unexpected joint weight format");
1098 };
1099
1100 for weights in joints.iter_mut() {
1101 weights.iter_mut().for_each(|w| *w = w.max(0.0));
1103
1104 let sum: f32 = weights.iter().sum();
1105 if sum == 0.0 {
1106 weights[0] = 1.0;
1108 } else {
1109 let recip = sum.recip();
1110 for weight in weights.iter_mut() {
1111 *weight *= recip;
1112 }
1113 }
1114 }
1115 }
1116 }
1117
1118 pub fn triangles(&self) -> Result<impl Iterator<Item = Triangle3d> + '_, MeshTrianglesError> {
1128 let Some(position_data) = self.attribute(Mesh::ATTRIBUTE_POSITION) else {
1129 return Err(MeshTrianglesError::MissingPositions);
1130 };
1131
1132 let Some(vertices) = position_data.as_float3() else {
1133 return Err(MeshTrianglesError::PositionsFormat);
1134 };
1135
1136 let Some(indices) = self.indices() else {
1137 return Err(MeshTrianglesError::MissingIndices);
1138 };
1139
1140 match self.primitive_topology {
1141 PrimitiveTopology::TriangleList => {
1142 let iterator = match indices {
1145 Indices::U16(vec) => FourIterators::First(
1146 vec.as_slice()
1147 .chunks_exact(3)
1148 .flat_map(move |indices| indices_to_triangle(vertices, indices)),
1149 ),
1150 Indices::U32(vec) => FourIterators::Second(
1151 vec.as_slice()
1152 .chunks_exact(3)
1153 .flat_map(move |indices| indices_to_triangle(vertices, indices)),
1154 ),
1155 };
1156
1157 return Ok(iterator);
1158 }
1159
1160 PrimitiveTopology::TriangleStrip => {
1161 let iterator = match indices {
1165 Indices::U16(vec) => {
1166 FourIterators::Third(vec.as_slice().windows(3).enumerate().flat_map(
1167 move |(i, indices)| {
1168 if i % 2 == 0 {
1169 indices_to_triangle(vertices, indices)
1170 } else {
1171 indices_to_triangle(
1172 vertices,
1173 &[indices[1], indices[0], indices[2]],
1174 )
1175 }
1176 },
1177 ))
1178 }
1179 Indices::U32(vec) => {
1180 FourIterators::Fourth(vec.as_slice().windows(3).enumerate().flat_map(
1181 move |(i, indices)| {
1182 if i % 2 == 0 {
1183 indices_to_triangle(vertices, indices)
1184 } else {
1185 indices_to_triangle(
1186 vertices,
1187 &[indices[1], indices[0], indices[2]],
1188 )
1189 }
1190 },
1191 ))
1192 }
1193 };
1194
1195 return Ok(iterator);
1196 }
1197
1198 _ => {
1199 return Err(MeshTrianglesError::WrongTopology);
1200 }
1201 };
1202
1203 fn indices_to_triangle<T: TryInto<usize> + Copy>(
1204 vertices: &[[f32; 3]],
1205 indices: &[T],
1206 ) -> Option<Triangle3d> {
1207 let vert0: Vec3 = Vec3::from(*vertices.get(indices[0].try_into().ok()?)?);
1208 let vert1: Vec3 = Vec3::from(*vertices.get(indices[1].try_into().ok()?)?);
1209 let vert2: Vec3 = Vec3::from(*vertices.get(indices[2].try_into().ok()?)?);
1210 Some(Triangle3d {
1211 vertices: [vert0, vert1, vert2],
1212 })
1213 }
1214 }
1215}
1216
1217impl core::ops::Mul<Mesh> for Transform {
1218 type Output = Mesh;
1219
1220 fn mul(self, rhs: Mesh) -> Self::Output {
1221 rhs.transformed_by(self)
1222 }
1223}
1224
1225#[cfg(test)]
1226mod tests {
1227 use super::Mesh;
1228 use crate::mesh::{Indices, MeshWindingInvertError, VertexAttributeValues};
1229 use bevy_asset::RenderAssetUsages;
1230 use bevy_math::primitives::Triangle3d;
1231 use bevy_math::Vec3;
1232 use bevy_transform::components::Transform;
1233 use wgpu::PrimitiveTopology;
1234
1235 #[test]
1236 #[should_panic]
1237 fn panic_invalid_format() {
1238 let _mesh = Mesh::new(
1239 PrimitiveTopology::TriangleList,
1240 RenderAssetUsages::default(),
1241 )
1242 .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, vec![[0.0, 0.0, 0.0]]);
1243 }
1244
1245 #[test]
1246 fn transform_mesh() {
1247 let mesh = Mesh::new(
1248 PrimitiveTopology::TriangleList,
1249 RenderAssetUsages::default(),
1250 )
1251 .with_inserted_attribute(
1252 Mesh::ATTRIBUTE_POSITION,
1253 vec![[-1., -1., 2.], [1., -1., 2.], [0., 1., 2.]],
1254 )
1255 .with_inserted_attribute(
1256 Mesh::ATTRIBUTE_NORMAL,
1257 vec![
1258 Vec3::new(-1., -1., 1.).normalize().to_array(),
1259 Vec3::new(1., -1., 1.).normalize().to_array(),
1260 [0., 0., 1.],
1261 ],
1262 )
1263 .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, vec![[0., 0.], [1., 0.], [0.5, 1.]]);
1264
1265 let mesh = mesh.transformed_by(
1266 Transform::from_translation(Vec3::splat(-2.)).with_scale(Vec3::new(2., 0., -1.)),
1267 );
1268
1269 if let Some(VertexAttributeValues::Float32x3(positions)) =
1270 mesh.attribute(Mesh::ATTRIBUTE_POSITION)
1271 {
1272 assert_eq!(
1275 positions,
1276 &vec![[-4.0, -2.0, -4.0], [0.0, -2.0, -4.0], [-2.0, -2.0, -4.0]]
1277 );
1278 } else {
1279 panic!("Mesh does not have a position attribute");
1280 }
1281
1282 if let Some(VertexAttributeValues::Float32x3(normals)) =
1283 mesh.attribute(Mesh::ATTRIBUTE_NORMAL)
1284 {
1285 assert_eq!(normals, &vec![[0., -1., 0.], [0., -1., 0.], [0., 0., -1.]]);
1286 } else {
1287 panic!("Mesh does not have a normal attribute");
1288 }
1289
1290 if let Some(VertexAttributeValues::Float32x2(uvs)) = mesh.attribute(Mesh::ATTRIBUTE_UV_0) {
1291 assert_eq!(uvs, &vec![[0., 0.], [1., 0.], [0.5, 1.]]);
1292 } else {
1293 panic!("Mesh does not have a uv attribute");
1294 }
1295 }
1296
1297 #[test]
1298 fn point_list_mesh_invert_winding() {
1299 let mesh = Mesh::new(PrimitiveTopology::PointList, RenderAssetUsages::default())
1300 .with_inserted_indices(Indices::U32(vec![]));
1301 assert!(matches!(
1302 mesh.with_inverted_winding(),
1303 Err(MeshWindingInvertError::WrongTopology)
1304 ));
1305 }
1306
1307 #[test]
1308 fn line_list_mesh_invert_winding() {
1309 let mesh = Mesh::new(PrimitiveTopology::LineList, RenderAssetUsages::default())
1310 .with_inserted_indices(Indices::U32(vec![0, 1, 1, 2, 2, 3]));
1311 let mesh = mesh.with_inverted_winding().unwrap();
1312 assert_eq!(
1313 mesh.indices().unwrap().iter().collect::<Vec<usize>>(),
1314 vec![3, 2, 2, 1, 1, 0]
1315 );
1316 }
1317
1318 #[test]
1319 fn line_list_mesh_invert_winding_fail() {
1320 let mesh = Mesh::new(PrimitiveTopology::LineList, RenderAssetUsages::default())
1321 .with_inserted_indices(Indices::U32(vec![0, 1, 1]));
1322 assert!(matches!(
1323 mesh.with_inverted_winding(),
1324 Err(MeshWindingInvertError::AbruptIndicesEnd)
1325 ));
1326 }
1327
1328 #[test]
1329 fn line_strip_mesh_invert_winding() {
1330 let mesh = Mesh::new(PrimitiveTopology::LineStrip, RenderAssetUsages::default())
1331 .with_inserted_indices(Indices::U32(vec![0, 1, 2, 3]));
1332 let mesh = mesh.with_inverted_winding().unwrap();
1333 assert_eq!(
1334 mesh.indices().unwrap().iter().collect::<Vec<usize>>(),
1335 vec![3, 2, 1, 0]
1336 );
1337 }
1338
1339 #[test]
1340 fn triangle_list_mesh_invert_winding() {
1341 let mesh = Mesh::new(
1342 PrimitiveTopology::TriangleList,
1343 RenderAssetUsages::default(),
1344 )
1345 .with_inserted_indices(Indices::U32(vec![
1346 0, 3, 1, 1, 3, 2, ]));
1349 let mesh = mesh.with_inverted_winding().unwrap();
1350 assert_eq!(
1351 mesh.indices().unwrap().iter().collect::<Vec<usize>>(),
1352 vec![
1353 0, 1, 3, 1, 2, 3, ]
1356 );
1357 }
1358
1359 #[test]
1360 fn triangle_list_mesh_invert_winding_fail() {
1361 let mesh = Mesh::new(
1362 PrimitiveTopology::TriangleList,
1363 RenderAssetUsages::default(),
1364 )
1365 .with_inserted_indices(Indices::U32(vec![0, 3, 1, 2]));
1366 assert!(matches!(
1367 mesh.with_inverted_winding(),
1368 Err(MeshWindingInvertError::AbruptIndicesEnd)
1369 ));
1370 }
1371
1372 #[test]
1373 fn triangle_strip_mesh_invert_winding() {
1374 let mesh = Mesh::new(
1375 PrimitiveTopology::TriangleStrip,
1376 RenderAssetUsages::default(),
1377 )
1378 .with_inserted_indices(Indices::U32(vec![0, 1, 2, 3]));
1379 let mesh = mesh.with_inverted_winding().unwrap();
1380 assert_eq!(
1381 mesh.indices().unwrap().iter().collect::<Vec<usize>>(),
1382 vec![3, 2, 1, 0]
1383 );
1384 }
1385
1386 #[test]
1387 fn compute_smooth_normals() {
1388 let mut mesh = Mesh::new(
1389 PrimitiveTopology::TriangleList,
1390 RenderAssetUsages::default(),
1391 );
1392
1393 mesh.insert_attribute(
1400 Mesh::ATTRIBUTE_POSITION,
1401 vec![[0., 0., 0.], [1., 0., 0.], [0., 1., 0.], [0., 0., 1.]],
1402 );
1403 mesh.insert_indices(Indices::U16(vec![0, 1, 2, 0, 2, 3]));
1404 mesh.compute_smooth_normals();
1405 let normals = mesh
1406 .attribute(Mesh::ATTRIBUTE_NORMAL)
1407 .unwrap()
1408 .as_float3()
1409 .unwrap();
1410 assert_eq!(4, normals.len());
1411 assert_eq!(Vec3::new(1., 0., 1.).normalize().to_array(), normals[0]);
1413 assert_eq!([0., 0., 1.], normals[1]);
1415 assert_eq!(Vec3::new(1., 0., 1.).normalize().to_array(), normals[2]);
1417 assert_eq!([1., 0., 0.], normals[3]);
1419 }
1420
1421 #[test]
1422 fn triangles_from_triangle_list() {
1423 let mut mesh = Mesh::new(
1424 PrimitiveTopology::TriangleList,
1425 RenderAssetUsages::default(),
1426 );
1427 mesh.insert_attribute(
1428 Mesh::ATTRIBUTE_POSITION,
1429 vec![[0., 0., 0.], [1., 0., 0.], [1., 1., 0.], [0., 1., 0.]],
1430 );
1431 mesh.insert_indices(Indices::U32(vec![0, 1, 2, 2, 3, 0]));
1432 assert_eq!(
1433 vec![
1434 Triangle3d {
1435 vertices: [
1436 Vec3::new(0., 0., 0.),
1437 Vec3::new(1., 0., 0.),
1438 Vec3::new(1., 1., 0.),
1439 ]
1440 },
1441 Triangle3d {
1442 vertices: [
1443 Vec3::new(1., 1., 0.),
1444 Vec3::new(0., 1., 0.),
1445 Vec3::new(0., 0., 0.),
1446 ]
1447 }
1448 ],
1449 mesh.triangles().unwrap().collect::<Vec<Triangle3d>>()
1450 );
1451 }
1452
1453 #[test]
1454 fn triangles_from_triangle_strip() {
1455 let mut mesh = Mesh::new(
1456 PrimitiveTopology::TriangleStrip,
1457 RenderAssetUsages::default(),
1458 );
1459 let positions: Vec<Vec3> = [
1467 [0., 0., 0.],
1468 [1., 0., 0.],
1469 [0., 1., 0.],
1470 [1., 1., 0.],
1471 [0., 2., 0.],
1472 [1., 2., 0.],
1473 ]
1474 .into_iter()
1475 .map(Vec3::from_array)
1476 .collect();
1477 mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions.clone());
1478 mesh.insert_indices(Indices::U32(vec![0, 1, 2, 3, 4, 5]));
1479 assert_eq!(
1480 vec![
1481 Triangle3d {
1482 vertices: [positions[0], positions[1], positions[2]]
1483 },
1484 Triangle3d {
1485 vertices: [positions[2], positions[1], positions[3]]
1486 },
1487 Triangle3d {
1488 vertices: [positions[2], positions[3], positions[4]]
1489 },
1490 Triangle3d {
1491 vertices: [positions[4], positions[3], positions[5]]
1492 },
1493 ],
1494 mesh.triangles().unwrap().collect::<Vec<Triangle3d>>()
1495 );
1496 }
1497}