1use bevy_transform::components::Transform;
2pub use wgpu_types::PrimitiveTopology;
34use super::{
5 skinning::{SkinnedMeshBounds, SkinnedMeshBoundsError},
6triangle_area_normal, triangle_normal, FourIterators, Indices, MeshAttributeData,
7MeshTrianglesError, MeshVertexAttribute, MeshVertexAttributeId, MeshVertexBufferLayout,
8MeshVertexBufferLayoutRef, MeshVertexBufferLayouts, MeshWindingInvertError,
9VertexAttributeValues, VertexBufferLayout,
10};
11#[cfg(feature = "morph")]
12use crate::morph::MorphAttributes;
13#[cfg(feature = "serialize")]
14use crate::SerializedMeshAttributeData;
15use alloc::collections::BTreeMap;
16use bevy_asset::{Asset, RenderAssetUsages};
17use bevy_math::{bounding::Aabb3d, primitives::Triangle3d, *};
18use bevy_platform::collections::{hash_map, HashMap};
19use bevy_reflect::{std_traits::ReflectDefault, Reflect};
20use bytemuck::cast_slice;
21use core::hash::{Hash, Hasher};
22use core::ptr;
23#[cfg(feature = "serialize")]
24use serde::{Deserialize, Serialize};
25use thiserror::Error;
26use tracing::warn;
27use wgpu_types::{VertexAttribute, VertexFormat, VertexStepMode, WriteOnly};
2829pub const INDEX_BUFFER_ASSET_INDEX: u64 = 0;
30pub const VERTEX_ATTRIBUTE_BUFFER_ID: u64 = 10;
3132/// Error from accessing mesh vertex attributes or indices
33#[derive(#[allow(unused_qualifications)]
#[automatically_derived]
impl ::core::fmt::Display for MeshAccessError {
fn fmt(&self, __formatter: &mut ::core::fmt::Formatter)
-> ::core::fmt::Result {
#[allow(unused_variables, deprecated, clippy ::
used_underscore_binding)]
match self {
MeshAccessError::ExtractedToRenderWorld {} =>
__formatter.write_str("The mesh vertex/index data has been extracted to the RenderWorld (via `Mesh::asset_usage`)"),
MeshAccessError::NotFound {} =>
__formatter.write_str("The requested mesh data wasn't found in this mesh"),
}
}
}Error, #[automatically_derived]
impl ::core::fmt::Debug for MeshAccessError {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
MeshAccessError::ExtractedToRenderWorld =>
"ExtractedToRenderWorld",
MeshAccessError::NotFound => "NotFound",
})
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for MeshAccessError {
#[inline]
fn clone(&self) -> MeshAccessError {
match self {
MeshAccessError::ExtractedToRenderWorld =>
MeshAccessError::ExtractedToRenderWorld,
MeshAccessError::NotFound => MeshAccessError::NotFound,
}
}
}Clone)]
34pub enum MeshAccessError {
35#[error("The mesh vertex/index data has been extracted to the RenderWorld (via `Mesh::asset_usage`)")]
36ExtractedToRenderWorld,
37#[error("The requested mesh data wasn't found in this mesh")]
38NotFound,
39}
4041const MESH_EXTRACTED_ERROR: &str = "Mesh has been extracted to RenderWorld. To access vertex attributes, the mesh `asset_usage` must include `MAIN_WORLD`";
4243// storage for extractable data with access methods which return errors if the
44// contents have already been extracted
45#[derive(#[automatically_derived]
impl<T: ::core::fmt::Debug> ::core::fmt::Debug for MeshExtractableData<T> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
MeshExtractableData::Data(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Data",
&__self_0),
MeshExtractableData::NoData =>
::core::fmt::Formatter::write_str(f, "NoData"),
MeshExtractableData::ExtractedToRenderWorld =>
::core::fmt::Formatter::write_str(f,
"ExtractedToRenderWorld"),
}
}
}Debug, #[automatically_derived]
impl<T: ::core::clone::Clone> ::core::clone::Clone for MeshExtractableData<T>
{
#[inline]
fn clone(&self) -> MeshExtractableData<T> {
match self {
MeshExtractableData::Data(__self_0) =>
MeshExtractableData::Data(::core::clone::Clone::clone(__self_0)),
MeshExtractableData::NoData => MeshExtractableData::NoData,
MeshExtractableData::ExtractedToRenderWorld =>
MeshExtractableData::ExtractedToRenderWorld,
}
}
}Clone, #[automatically_derived]
impl<T: ::core::cmp::PartialEq> ::core::cmp::PartialEq for
MeshExtractableData<T> {
#[inline]
fn eq(&self, other: &MeshExtractableData<T>) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr &&
match (self, other) {
(MeshExtractableData::Data(__self_0),
MeshExtractableData::Data(__arg1_0)) =>
__self_0 == __arg1_0,
_ => true,
}
}
}PartialEq, const _: () =
{
impl<T> bevy_reflect::GetTypeRegistration for MeshExtractableData<T>
where MeshExtractableData<T>: ::core::any::Any +
::core::marker::Send + ::core::marker::Sync,
T: bevy_reflect::TypePath, T: bevy_reflect::FromReflect +
bevy_reflect::TypePath + bevy_reflect::MaybeTyped +
bevy_reflect::__macro_exports::RegisterForReflection {
fn get_type_registration() -> bevy_reflect::TypeRegistration {
let mut registration =
bevy_reflect::TypeRegistration::of::<Self>();
registration.insert::<bevy_reflect::ReflectFromPtr>(bevy_reflect::FromType::<Self>::from_type());
registration.insert::<bevy_reflect::ReflectFromReflect>(bevy_reflect::FromType::<Self>::from_type());
registration
}
#[inline(never)]
fn register_type_dependencies(registry:
&mut bevy_reflect::TypeRegistry) {
<T as
bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
}
}
impl<T> bevy_reflect::Typed for MeshExtractableData<T> where
MeshExtractableData<T>: ::core::any::Any + ::core::marker::Send +
::core::marker::Sync, T: bevy_reflect::TypePath,
T: bevy_reflect::FromReflect + bevy_reflect::TypePath +
bevy_reflect::MaybeTyped +
bevy_reflect::__macro_exports::RegisterForReflection {
#[inline]
fn type_info() -> &'static bevy_reflect::TypeInfo {
static CELL: bevy_reflect::utility::GenericTypeInfoCell =
bevy_reflect::utility::GenericTypeInfoCell::new();
CELL.get_or_insert::<Self,
_>(||
{
bevy_reflect::TypeInfo::Enum(bevy_reflect::enums::EnumInfo::new::<Self>(&[bevy_reflect::enums::VariantInfo::Tuple(bevy_reflect::enums::TupleVariantInfo::new("Data",
&[bevy_reflect::UnnamedField::new::<T>(0usize)])),
bevy_reflect::enums::VariantInfo::Unit(bevy_reflect::enums::UnitVariantInfo::new("NoData")),
bevy_reflect::enums::VariantInfo::Unit(bevy_reflect::enums::UnitVariantInfo::new("ExtractedToRenderWorld"))]).with_generics(bevy_reflect::Generics::from_iter([bevy_reflect::GenericInfo::Type(bevy_reflect::TypeParamInfo::new::<T>(bevy_reflect::__macro_exports::alloc_utils::Cow::Borrowed("T")))])))
})
}
}
#[allow(deprecated, reason =
"derives on a deprecated type shouldn't be considered a usage")]
impl<T> bevy_reflect::TypePath for MeshExtractableData<T> where
MeshExtractableData<T>: ::core::any::Any + ::core::marker::Send +
::core::marker::Sync, T: bevy_reflect::TypePath {
fn type_path() -> &'static str {
static CELL: bevy_reflect::utility::GenericTypePathCell =
bevy_reflect::utility::GenericTypePathCell::new();
CELL.get_or_insert::<Self,
_>(||
{
::core::ops::Add::<&str>::add(::core::ops::Add::<&str>::add(bevy_reflect::__macro_exports::alloc_utils::ToString::to_string("bevy_mesh::mesh::MeshExtractableData<"),
<T as bevy_reflect::TypePath>::type_path()), ">")
})
}
fn short_type_path() -> &'static str {
static CELL: bevy_reflect::utility::GenericTypePathCell =
bevy_reflect::utility::GenericTypePathCell::new();
CELL.get_or_insert::<Self,
_>(||
{
::core::ops::Add::<&str>::add(::core::ops::Add::<&str>::add(bevy_reflect::__macro_exports::alloc_utils::ToString::to_string("MeshExtractableData<"),
<T as bevy_reflect::TypePath>::short_type_path()), ">")
})
}
fn type_ident() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("MeshExtractableData")
}
fn crate_name() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("bevy_mesh::mesh".split(':').next().unwrap())
}
fn module_path() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("bevy_mesh::mesh")
}
}
impl<T> bevy_reflect::Reflect for MeshExtractableData<T> where
MeshExtractableData<T>: ::core::any::Any + ::core::marker::Send +
::core::marker::Sync, T: bevy_reflect::TypePath,
T: bevy_reflect::FromReflect + bevy_reflect::TypePath +
bevy_reflect::MaybeTyped +
bevy_reflect::__macro_exports::RegisterForReflection {
#[inline]
fn into_any(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn ::core::any::Any> {
self
}
#[inline]
fn as_any(&self) -> &dyn ::core::any::Any { self }
#[inline]
fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any { self }
#[inline]
fn into_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect> {
self
}
#[inline]
fn as_reflect(&self) -> &dyn bevy_reflect::Reflect { self }
#[inline]
fn as_reflect_mut(&mut self) -> &mut dyn bevy_reflect::Reflect {
self
}
#[inline]
fn set(&mut self,
value:
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>)
->
::core::result::Result<(),
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>> {
*self = <dyn bevy_reflect::Reflect>::take(value)?;
::core::result::Result::Ok(())
}
}
impl<T> bevy_reflect::enums::Enum for MeshExtractableData<T> where
MeshExtractableData<T>: ::core::any::Any + ::core::marker::Send +
::core::marker::Sync, T: bevy_reflect::TypePath,
T: bevy_reflect::FromReflect + bevy_reflect::TypePath +
bevy_reflect::MaybeTyped +
bevy_reflect::__macro_exports::RegisterForReflection {
fn field(&self, __name_param: &str)
-> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
match self { _ => ::core::option::Option::None, }
}
fn field_at(&self, __index_param: usize)
-> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
match self {
MeshExtractableData::Data { 0: __value, .. } if
__index_param == 0usize =>
::core::option::Option::Some(__value),
_ => ::core::option::Option::None,
}
}
fn field_mut(&mut self, __name_param: &str)
->
::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
match self { _ => ::core::option::Option::None, }
}
fn field_at_mut(&mut self, __index_param: usize)
->
::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
match self {
MeshExtractableData::Data { 0: __value, .. } if
__index_param == 0usize =>
::core::option::Option::Some(__value),
_ => ::core::option::Option::None,
}
}
fn index_of(&self, __name_param: &str)
-> ::core::option::Option<usize> {
match self { _ => ::core::option::Option::None, }
}
fn name_at(&self, __index_param: usize)
-> ::core::option::Option<&str> {
match self { _ => ::core::option::Option::None, }
}
fn iter_fields(&self) -> bevy_reflect::enums::VariantFieldIter {
bevy_reflect::enums::VariantFieldIter::new(self)
}
#[inline]
fn field_len(&self) -> usize {
match self {
MeshExtractableData::Data { .. } => 1usize,
MeshExtractableData::NoData { .. } => 0usize,
MeshExtractableData::ExtractedToRenderWorld { .. } =>
0usize,
_ => 0,
}
}
#[inline]
fn variant_name(&self) -> &str {
match self {
MeshExtractableData::Data { .. } => "Data",
MeshExtractableData::NoData { .. } => "NoData",
MeshExtractableData::ExtractedToRenderWorld { .. } =>
"ExtractedToRenderWorld",
_ =>
::core::panicking::panic("internal error: entered unreachable code"),
}
}
#[inline]
fn variant_index(&self) -> usize {
match self {
MeshExtractableData::Data { .. } => 0usize,
MeshExtractableData::NoData { .. } => 1usize,
MeshExtractableData::ExtractedToRenderWorld { .. } =>
2usize,
_ =>
::core::panicking::panic("internal error: entered unreachable code"),
}
}
#[inline]
fn variant_type(&self) -> bevy_reflect::enums::VariantType {
match self {
MeshExtractableData::Data { .. } =>
bevy_reflect::enums::VariantType::Tuple,
MeshExtractableData::NoData { .. } =>
bevy_reflect::enums::VariantType::Unit,
MeshExtractableData::ExtractedToRenderWorld { .. } =>
bevy_reflect::enums::VariantType::Unit,
_ =>
::core::panicking::panic("internal error: entered unreachable code"),
}
}
fn to_dynamic_enum(&self) -> bevy_reflect::enums::DynamicEnum {
bevy_reflect::enums::DynamicEnum::from_ref::<Self>(self)
}
}
impl<T> bevy_reflect::PartialReflect for MeshExtractableData<T> where
MeshExtractableData<T>: ::core::any::Any + ::core::marker::Send +
::core::marker::Sync, T: bevy_reflect::TypePath,
T: bevy_reflect::FromReflect + bevy_reflect::TypePath +
bevy_reflect::MaybeTyped +
bevy_reflect::__macro_exports::RegisterForReflection {
#[inline]
fn get_represented_type_info(&self)
-> ::core::option::Option<&'static bevy_reflect::TypeInfo> {
::core::option::Option::Some(<Self as
bevy_reflect::Typed>::type_info())
}
#[inline]
fn try_apply(&mut self,
__value_param: &dyn bevy_reflect::PartialReflect)
-> ::core::result::Result<(), bevy_reflect::ApplyError> {
if let bevy_reflect::ReflectRef::Enum(__value_param) =
bevy_reflect::PartialReflect::reflect_ref(__value_param) {
if bevy_reflect::enums::Enum::variant_name(self) ==
bevy_reflect::enums::Enum::variant_name(__value_param) {
match bevy_reflect::enums::Enum::variant_type(__value_param)
{
bevy_reflect::enums::VariantType::Struct => {
for field in
bevy_reflect::enums::Enum::iter_fields(__value_param) {
let name = field.name().unwrap();
if let ::core::option::Option::Some(v) =
bevy_reflect::enums::Enum::field_mut(self, name) {
bevy_reflect::PartialReflect::try_apply(v, field.value())?;
}
}
}
bevy_reflect::enums::VariantType::Tuple => {
for (index, field) in
::core::iter::Iterator::enumerate(bevy_reflect::enums::Enum::iter_fields(__value_param))
{
if let ::core::option::Option::Some(v) =
bevy_reflect::enums::Enum::field_at_mut(self, index) {
bevy_reflect::PartialReflect::try_apply(v, field.value())?;
}
}
}
_ => {}
}
} else {
match bevy_reflect::enums::Enum::variant_name(__value_param)
{
"Data" => {
*self =
MeshExtractableData::Data {
0: {
let __0 = __value_param.field_at(0usize);
let __0 =
__0.ok_or(bevy_reflect::ApplyError::MissingEnumField {
variant_name: ::core::convert::Into::into("Data"),
field_name: ::core::convert::Into::into(".0"),
})?;
<T as
bevy_reflect::FromReflect>::from_reflect(__0).ok_or(bevy_reflect::ApplyError::MismatchedTypes {
from_type: ::core::convert::Into::into(bevy_reflect::DynamicTypePath::reflect_type_path(__0)),
to_type: ::core::convert::Into::into(<T as
bevy_reflect::TypePath>::type_path()),
})?
},
}
}
"NoData" => { *self = MeshExtractableData::NoData {} }
"ExtractedToRenderWorld" => {
*self = MeshExtractableData::ExtractedToRenderWorld {}
}
name => {
return ::core::result::Result::Err(bevy_reflect::ApplyError::UnknownVariant {
enum_name: ::core::convert::Into::into(bevy_reflect::DynamicTypePath::reflect_type_path(self)),
variant_name: ::core::convert::Into::into(name),
});
}
}
}
} else {
return ::core::result::Result::Err(bevy_reflect::ApplyError::MismatchedKinds {
from_kind: bevy_reflect::PartialReflect::reflect_kind(__value_param),
to_kind: bevy_reflect::ReflectKind::Enum,
});
}
::core::result::Result::Ok(())
}
fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
bevy_reflect::ReflectKind::Enum
}
fn reflect_ref(&self) -> bevy_reflect::ReflectRef {
bevy_reflect::ReflectRef::Enum(self)
}
fn reflect_mut(&mut self) -> bevy_reflect::ReflectMut {
bevy_reflect::ReflectMut::Enum(self)
}
fn reflect_owned(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
-> bevy_reflect::ReflectOwned {
bevy_reflect::ReflectOwned::Enum(self)
}
#[inline]
fn try_into_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect>> {
::core::result::Result::Ok(self)
}
#[inline]
fn try_as_reflect(&self)
-> ::core::option::Option<&dyn bevy_reflect::Reflect> {
::core::option::Option::Some(self)
}
#[inline]
fn try_as_reflect_mut(&mut self)
-> ::core::option::Option<&mut dyn bevy_reflect::Reflect> {
::core::option::Option::Some(self)
}
#[inline]
fn into_partial_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect> {
self
}
#[inline]
fn as_partial_reflect(&self)
-> &dyn bevy_reflect::PartialReflect {
self
}
#[inline]
fn as_partial_reflect_mut(&mut self)
-> &mut dyn bevy_reflect::PartialReflect {
self
}
fn reflect_hash(&self) -> ::core::option::Option<u64> {
(bevy_reflect::enums::enum_hash)(self)
}
fn reflect_partial_eq(&self,
value: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<bool> {
(bevy_reflect::enums::enum_partial_eq)(self, value)
}
fn reflect_partial_cmp(&self,
value: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<::core::cmp::Ordering> {
(bevy_reflect::enums::enum_partial_cmp)(self, value)
}
#[inline]
#[allow(unreachable_code, reason =
"Ignored fields without a `clone` attribute will early-return with an error")]
fn reflect_clone(&self)
->
::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
bevy_reflect::ReflectCloneError> {
let this = self;
::core::result::Result::Ok(bevy_reflect::__macro_exports::alloc_utils::Box::new(match this
{
MeshExtractableData::Data { 0: __0 } =>
MeshExtractableData::Data {
0: <T as
bevy_reflect::PartialReflect>::reflect_clone_and_take(__0)?,
},
MeshExtractableData::NoData {} =>
MeshExtractableData::NoData {},
MeshExtractableData::ExtractedToRenderWorld {} =>
MeshExtractableData::ExtractedToRenderWorld {},
}))
}
}
impl<T> bevy_reflect::FromReflect for MeshExtractableData<T> where
MeshExtractableData<T>: ::core::any::Any + ::core::marker::Send +
::core::marker::Sync, T: bevy_reflect::TypePath,
T: bevy_reflect::FromReflect + bevy_reflect::TypePath +
bevy_reflect::MaybeTyped +
bevy_reflect::__macro_exports::RegisterForReflection {
fn from_reflect(__param0: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<Self> {
if let bevy_reflect::ReflectRef::Enum(__param0) =
bevy_reflect::PartialReflect::reflect_ref(__param0) {
match bevy_reflect::enums::Enum::variant_name(__param0) {
"Data" =>
::core::option::Option::Some(MeshExtractableData::Data {
0: {
let __0 = __param0.field_at(0usize);
let __0 = __0?;
<T as bevy_reflect::FromReflect>::from_reflect(__0)?
},
}),
"NoData" =>
::core::option::Option::Some(MeshExtractableData::NoData {}),
"ExtractedToRenderWorld" =>
::core::option::Option::Some(MeshExtractableData::ExtractedToRenderWorld {}),
name => ::core::option::Option::None,
}
} else { ::core::option::Option::None }
}
}
};Reflect, #[automatically_derived]
impl<T> ::core::default::Default for MeshExtractableData<T> {
#[inline]
fn default() -> MeshExtractableData<T> { Self::NoData }
}Default)]
46enum MeshExtractableData<T> {
47 Data(T),
48#[default]
49NoData,
50 ExtractedToRenderWorld,
51}
5253impl<T> MeshExtractableData<T> {
54// get a reference to internal data. returns error if data has been extracted, or if no
55 // data exists
56fn as_ref(&self) -> Result<&T, MeshAccessError> {
57match self {
58 MeshExtractableData::Data(data) => Ok(data),
59 MeshExtractableData::NoData => Err(MeshAccessError::NotFound),
60 MeshExtractableData::ExtractedToRenderWorld => {
61Err(MeshAccessError::ExtractedToRenderWorld)
62 }
63 }
64 }
6566// get an optional reference to internal data. returns error if data has been extracted
67fn as_ref_option(&self) -> Result<Option<&T>, MeshAccessError> {
68match self {
69 MeshExtractableData::Data(data) => Ok(Some(data)),
70 MeshExtractableData::NoData => Ok(None),
71 MeshExtractableData::ExtractedToRenderWorld => {
72Err(MeshAccessError::ExtractedToRenderWorld)
73 }
74 }
75 }
7677// get a mutable reference to internal data. returns error if data has been extracted,
78 // or if no data exists
79fn as_mut(&mut self) -> Result<&mut T, MeshAccessError> {
80match self {
81 MeshExtractableData::Data(data) => Ok(data),
82 MeshExtractableData::NoData => Err(MeshAccessError::NotFound),
83 MeshExtractableData::ExtractedToRenderWorld => {
84Err(MeshAccessError::ExtractedToRenderWorld)
85 }
86 }
87 }
8889// get an optional mutable reference to internal data. returns error if data has been extracted
90fn as_mut_option(&mut self) -> Result<Option<&mut T>, MeshAccessError> {
91match self {
92 MeshExtractableData::Data(data) => Ok(Some(data)),
93 MeshExtractableData::NoData => Ok(None),
94 MeshExtractableData::ExtractedToRenderWorld => {
95Err(MeshAccessError::ExtractedToRenderWorld)
96 }
97 }
98 }
99100// extract data and replace self with `ExtractedToRenderWorld`. returns error if
101 // data has been extracted
102fn extract(&mut self) -> Result<MeshExtractableData<T>, MeshAccessError> {
103match core::mem::replace(self, MeshExtractableData::ExtractedToRenderWorld) {
104 MeshExtractableData::ExtractedToRenderWorld => {
105Err(MeshAccessError::ExtractedToRenderWorld)
106 }
107 not_extracted => Ok(not_extracted),
108 }
109 }
110111// replace internal data. returns the existing data, or an error if data has been extracted
112fn replace(
113&mut self,
114 data: impl Into<MeshExtractableData<T>>,
115 ) -> Result<Option<T>, MeshAccessError> {
116match core::mem::replace(self, data.into()) {
117 MeshExtractableData::ExtractedToRenderWorld => {
118*self = MeshExtractableData::ExtractedToRenderWorld;
119Err(MeshAccessError::ExtractedToRenderWorld)
120 }
121 MeshExtractableData::Data(t) => Ok(Some(t)),
122 MeshExtractableData::NoData => Ok(None),
123 }
124 }
125}
126127impl<T> From<Option<T>> for MeshExtractableData<T> {
128fn from(value: Option<T>) -> Self {
129match value {
130Some(data) => MeshExtractableData::Data(data),
131None => MeshExtractableData::NoData,
132 }
133 }
134}
135136/// A 3D object made out of vertices representing triangles, lines, or points,
137/// with "attribute" values for each vertex.
138///
139/// Meshes can be automatically generated by a bevy `AssetLoader` (generally by loading a `Gltf` file),
140/// or by converting a [primitive](bevy_math::primitives) using [`into`](Into).
141/// It is also possible to create one manually. They can be edited after creation.
142///
143/// Meshes can be rendered with a [`Mesh2d`](crate::Mesh2d) and `MeshMaterial2d`
144/// or [`Mesh3d`](crate::Mesh3d) and `MeshMaterial3d` for 2D and 3D respectively.
145///
146/// A [`Mesh`] in Bevy is equivalent to a "primitive" in the glTF format, for a
147/// glTF Mesh representation, see `GltfMesh`.
148///
149/// ## Manual creation
150///
151/// The following function will construct a flat mesh, to be rendered with a
152/// `StandardMaterial` or `ColorMaterial`:
153///
154/// ```
155/// # use bevy_mesh::{Mesh, Indices, PrimitiveTopology};
156/// # use bevy_asset::RenderAssetUsages;
157/// fn create_simple_parallelogram() -> Mesh {
158/// // Create a new mesh using a triangle list topology, where each set of 3 vertices composes a triangle.
159/// Mesh::new(PrimitiveTopology::TriangleList, RenderAssetUsages::default())
160/// // Add 4 vertices, each with its own position attribute (coordinate in
161/// // 3D space), for each of the corners of the parallelogram.
162/// .with_inserted_attribute(
163/// Mesh::ATTRIBUTE_POSITION,
164/// 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]]
165/// )
166/// // Assign a UV coordinate to each vertex.
167/// .with_inserted_attribute(
168/// Mesh::ATTRIBUTE_UV_0,
169/// vec![[0.0, 1.0], [0.5, 0.0], [1.0, 0.0], [0.5, 1.0]]
170/// )
171/// // Assign normals (everything points outwards)
172/// .with_inserted_attribute(
173/// Mesh::ATTRIBUTE_NORMAL,
174/// 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]]
175/// )
176/// // After defining all the vertices and their attributes, build each triangle using the
177/// // indices of the vertices that make it up in a counter-clockwise order.
178/// .with_inserted_indices(Indices::U32(vec![
179/// // First triangle
180/// 0, 3, 1,
181/// // Second triangle
182/// 1, 3, 2
183/// ]))
184/// }
185/// ```
186///
187/// You can see how it looks like [here](https://github.com/bevyengine/bevy/blob/main/assets/docs/Mesh.png),
188/// used in a [`Mesh3d`](crate::Mesh3d) with a square bevy logo texture, with added axis, points,
189/// lines and text for clarity.
190///
191/// ## Other examples
192///
193/// For further visualization, explanation, and examples, see the built-in Bevy examples,
194/// and the [implementation of the built-in shapes](https://github.com/bevyengine/bevy/tree/main/crates/bevy_mesh/src/primitives).
195/// In particular, [generate_custom_mesh](https://github.com/bevyengine/bevy/blob/main/examples/3d/generate_custom_mesh.rs)
196/// teaches you to access and modify the attributes of a [`Mesh`] after creating it.
197///
198/// ## Common points of confusion
199///
200/// - UV maps in Bevy start at the top-left, see [`ATTRIBUTE_UV_0`](Mesh::ATTRIBUTE_UV_0),
201/// other APIs can have other conventions, `OpenGL` starts at bottom-left.
202/// - It is possible and sometimes useful for multiple vertices to have the same
203/// [position attribute](Mesh::ATTRIBUTE_POSITION) value,
204/// it's a common technique in 3D modeling for complex UV mapping or other calculations.
205/// - Bevy performs frustum culling based on the `Aabb` of meshes, which is calculated
206/// and added automatically for new meshes only. If a mesh is modified, the entity's `Aabb`
207/// needs to be updated manually or deleted so that it is re-calculated.
208///
209/// ## Use with `StandardMaterial`
210///
211/// To render correctly with `StandardMaterial`, a mesh needs to have properly defined:
212/// - [`UVs`](Mesh::ATTRIBUTE_UV_0): Bevy needs to know how to map a texture onto the mesh
213/// (also true for `ColorMaterial`).
214/// - [`Normals`](Mesh::ATTRIBUTE_NORMAL): Bevy needs to know how light interacts with your mesh.
215/// [0.0, 0.0, 1.0] is very common for simple flat meshes on the XY plane,
216/// because simple meshes are smooth and they don't require complex light calculations.
217/// - Vertex winding order: by default, `StandardMaterial.cull_mode` is `Some(Face::Back)`,
218/// which means that Bevy would *only* render the "front" of each triangle, which
219/// is the side of the triangle from where the vertices appear in a *counter-clockwise* order.
220///
221/// ## Remote Inspection
222///
223/// To transmit a [`Mesh`] between two running Bevy apps, e.g. through BRP, use [`SerializedMesh`].
224/// This type is only meant for short-term transmission between same versions and should not be stored anywhere.
225#[derive(impl bevy_asset::VisitAssetDependencies for Mesh {
fn visit_dependencies(&self,
visit: &mut impl ::core::ops::FnMut(bevy_asset::UntypedAssetId)) {}
}Asset, #[automatically_derived]
impl ::core::fmt::Debug for Mesh {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
let names: &'static _ =
&["primitive_topology", "attributes", "indices", "morph_targets",
"morph_target_names", "asset_usage", "enable_raytracing",
"final_aabb", "skinned_mesh_bounds"];
let values: &[&dyn ::core::fmt::Debug] =
&[&self.primitive_topology, &self.attributes, &self.indices,
&self.morph_targets, &self.morph_target_names,
&self.asset_usage, &self.enable_raytracing,
&self.final_aabb, &&self.skinned_mesh_bounds];
::core::fmt::Formatter::debug_struct_fields_finish(f, "Mesh", names,
values)
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for Mesh {
#[inline]
fn clone(&self) -> Mesh {
Mesh {
primitive_topology: ::core::clone::Clone::clone(&self.primitive_topology),
attributes: ::core::clone::Clone::clone(&self.attributes),
indices: ::core::clone::Clone::clone(&self.indices),
morph_targets: ::core::clone::Clone::clone(&self.morph_targets),
morph_target_names: ::core::clone::Clone::clone(&self.morph_target_names),
asset_usage: ::core::clone::Clone::clone(&self.asset_usage),
enable_raytracing: ::core::clone::Clone::clone(&self.enable_raytracing),
final_aabb: ::core::clone::Clone::clone(&self.final_aabb),
skinned_mesh_bounds: ::core::clone::Clone::clone(&self.skinned_mesh_bounds),
}
}
}Clone, const _: () =
{
impl bevy_reflect::GetTypeRegistration for Mesh where {
fn get_type_registration() -> bevy_reflect::TypeRegistration {
let mut registration =
bevy_reflect::TypeRegistration::of::<Self>();
registration.insert::<bevy_reflect::ReflectFromPtr>(bevy_reflect::FromType::<Self>::from_type());
registration.insert::<bevy_reflect::ReflectFromReflect>(bevy_reflect::FromType::<Self>::from_type());
registration
}
#[inline(never)]
fn register_type_dependencies(registry:
&mut bevy_reflect::TypeRegistry) {
<MeshExtractableData<Indices> as
bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
<MeshExtractableData<Vec<MorphAttributes>> as
bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
<MeshExtractableData<Vec<String>> as
bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
<RenderAssetUsages as
bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
<bool as
bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
<Option<Aabb3d> as
bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
<Option<SkinnedMeshBounds> as
bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
}
}
impl bevy_reflect::Typed for Mesh where {
#[inline]
fn type_info() -> &'static bevy_reflect::TypeInfo {
static CELL: bevy_reflect::utility::NonGenericTypeInfoCell =
bevy_reflect::utility::NonGenericTypeInfoCell::new();
CELL.get_or_set(||
{
bevy_reflect::TypeInfo::Struct(bevy_reflect::structs::StructInfo::new::<Self>(&[bevy_reflect::NamedField::new::<MeshExtractableData<Indices>>("indices"),
bevy_reflect::NamedField::new::<MeshExtractableData<Vec<MorphAttributes>>>("morph_targets"),
bevy_reflect::NamedField::new::<MeshExtractableData<Vec<String>>>("morph_target_names"),
bevy_reflect::NamedField::new::<RenderAssetUsages>("asset_usage"),
bevy_reflect::NamedField::new::<bool>("enable_raytracing"),
bevy_reflect::NamedField::new::<Option<Aabb3d>>("final_aabb"),
bevy_reflect::NamedField::new::<Option<SkinnedMeshBounds>>("skinned_mesh_bounds")]))
})
}
}
#[allow(deprecated, reason =
"derives on a deprecated type shouldn't be considered a usage")]
impl bevy_reflect::TypePath for Mesh where {
fn type_path() -> &'static str { "bevy_mesh::mesh::Mesh" }
fn short_type_path() -> &'static str { "Mesh" }
fn type_ident() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("Mesh")
}
fn crate_name() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("bevy_mesh::mesh".split(':').next().unwrap())
}
fn module_path() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("bevy_mesh::mesh")
}
}
impl bevy_reflect::Reflect for Mesh where {
#[inline]
fn into_any(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn ::core::any::Any> {
self
}
#[inline]
fn as_any(&self) -> &dyn ::core::any::Any { self }
#[inline]
fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any { self }
#[inline]
fn into_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect> {
self
}
#[inline]
fn as_reflect(&self) -> &dyn bevy_reflect::Reflect { self }
#[inline]
fn as_reflect_mut(&mut self) -> &mut dyn bevy_reflect::Reflect {
self
}
#[inline]
fn set(&mut self,
value:
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>)
->
::core::result::Result<(),
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>> {
*self = <dyn bevy_reflect::Reflect>::take(value)?;
::core::result::Result::Ok(())
}
}
#[allow(non_upper_case_globals)]
const _: () =
{
static __INVENTORY: ::inventory::Node =
::inventory::Node {
value: &{
bevy_reflect::__macro_exports::auto_register::AutomaticReflectRegistrations(<Mesh
as
bevy_reflect::__macro_exports::auto_register::RegisterForReflection>::__register)
},
next: ::inventory::__private::UnsafeCell::new(::inventory::__private::Option::None),
};
#[link_section = ".text.startup"]
unsafe extern "C" fn __ctor() {
unsafe {
::inventory::ErasedNode::submit(__INVENTORY.value,
&__INVENTORY)
}
}
#[used]
#[link_section = ".init_array"]
static __CTOR: unsafe extern "C" fn() = __ctor;
};
impl bevy_reflect::structs::Struct for Mesh where {
fn field(&self, name: &str)
-> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
match name {
"indices" => ::core::option::Option::Some(&self.indices),
"morph_targets" =>
::core::option::Option::Some(&self.morph_targets),
"morph_target_names" =>
::core::option::Option::Some(&self.morph_target_names),
"asset_usage" =>
::core::option::Option::Some(&self.asset_usage),
"enable_raytracing" =>
::core::option::Option::Some(&self.enable_raytracing),
"final_aabb" =>
::core::option::Option::Some(&self.final_aabb),
"skinned_mesh_bounds" =>
::core::option::Option::Some(&self.skinned_mesh_bounds),
_ => ::core::option::Option::None,
}
}
fn field_mut(&mut self, name: &str)
->
::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
match name {
"indices" =>
::core::option::Option::Some(&mut self.indices),
"morph_targets" =>
::core::option::Option::Some(&mut self.morph_targets),
"morph_target_names" =>
::core::option::Option::Some(&mut self.morph_target_names),
"asset_usage" =>
::core::option::Option::Some(&mut self.asset_usage),
"enable_raytracing" =>
::core::option::Option::Some(&mut self.enable_raytracing),
"final_aabb" =>
::core::option::Option::Some(&mut self.final_aabb),
"skinned_mesh_bounds" =>
::core::option::Option::Some(&mut self.skinned_mesh_bounds),
_ => ::core::option::Option::None,
}
}
fn field_at(&self, index: usize)
-> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
match index {
0usize => ::core::option::Option::Some(&self.indices),
1usize => ::core::option::Option::Some(&self.morph_targets),
2usize =>
::core::option::Option::Some(&self.morph_target_names),
3usize => ::core::option::Option::Some(&self.asset_usage),
4usize =>
::core::option::Option::Some(&self.enable_raytracing),
5usize => ::core::option::Option::Some(&self.final_aabb),
6usize =>
::core::option::Option::Some(&self.skinned_mesh_bounds),
_ => ::core::option::Option::None,
}
}
fn field_at_mut(&mut self, index: usize)
->
::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
match index {
0usize => ::core::option::Option::Some(&mut self.indices),
1usize =>
::core::option::Option::Some(&mut self.morph_targets),
2usize =>
::core::option::Option::Some(&mut self.morph_target_names),
3usize =>
::core::option::Option::Some(&mut self.asset_usage),
4usize =>
::core::option::Option::Some(&mut self.enable_raytracing),
5usize =>
::core::option::Option::Some(&mut self.final_aabb),
6usize =>
::core::option::Option::Some(&mut self.skinned_mesh_bounds),
_ => ::core::option::Option::None,
}
}
fn name_at(&self, index: usize) -> ::core::option::Option<&str> {
match index {
0usize => ::core::option::Option::Some("indices"),
1usize => ::core::option::Option::Some("morph_targets"),
2usize =>
::core::option::Option::Some("morph_target_names"),
3usize => ::core::option::Option::Some("asset_usage"),
4usize => ::core::option::Option::Some("enable_raytracing"),
5usize => ::core::option::Option::Some("final_aabb"),
6usize =>
::core::option::Option::Some("skinned_mesh_bounds"),
_ => ::core::option::Option::None,
}
}
fn index_of_name(&self, name: &str)
-> ::core::option::Option<usize> {
match name {
"indices" => ::core::option::Option::Some(0usize),
"morph_targets" => ::core::option::Option::Some(1usize),
"morph_target_names" =>
::core::option::Option::Some(2usize),
"asset_usage" => ::core::option::Option::Some(3usize),
"enable_raytracing" => ::core::option::Option::Some(4usize),
"final_aabb" => ::core::option::Option::Some(5usize),
"skinned_mesh_bounds" =>
::core::option::Option::Some(6usize),
_ => ::core::option::Option::None,
}
}
fn field_len(&self) -> usize { 7usize }
fn iter_fields(&self) -> bevy_reflect::structs::FieldIter {
bevy_reflect::structs::FieldIter::new(self)
}
fn to_dynamic_struct(&self)
-> bevy_reflect::structs::DynamicStruct {
let mut dynamic: bevy_reflect::structs::DynamicStruct =
::core::default::Default::default();
dynamic.set_represented_type(bevy_reflect::PartialReflect::get_represented_type_info(self));
dynamic.insert_boxed("indices",
bevy_reflect::PartialReflect::to_dynamic(&self.indices));
dynamic.insert_boxed("morph_targets",
bevy_reflect::PartialReflect::to_dynamic(&self.morph_targets));
dynamic.insert_boxed("morph_target_names",
bevy_reflect::PartialReflect::to_dynamic(&self.morph_target_names));
dynamic.insert_boxed("asset_usage",
bevy_reflect::PartialReflect::to_dynamic(&self.asset_usage));
dynamic.insert_boxed("enable_raytracing",
bevy_reflect::PartialReflect::to_dynamic(&self.enable_raytracing));
dynamic.insert_boxed("final_aabb",
bevy_reflect::PartialReflect::to_dynamic(&self.final_aabb));
dynamic.insert_boxed("skinned_mesh_bounds",
bevy_reflect::PartialReflect::to_dynamic(&self.skinned_mesh_bounds));
dynamic
}
}
impl bevy_reflect::PartialReflect for Mesh where {
#[inline]
fn get_represented_type_info(&self)
-> ::core::option::Option<&'static bevy_reflect::TypeInfo> {
::core::option::Option::Some(<Self as
bevy_reflect::Typed>::type_info())
}
#[inline]
fn try_apply(&mut self, value: &dyn bevy_reflect::PartialReflect)
-> ::core::result::Result<(), bevy_reflect::ApplyError> {
if let bevy_reflect::ReflectRef::Struct(struct_value) =
bevy_reflect::PartialReflect::reflect_ref(value) {
for (name, value) in
bevy_reflect::structs::Struct::iter_fields(struct_value) {
if let ::core::option::Option::Some(v) =
bevy_reflect::structs::Struct::field_mut(self, name) {
bevy_reflect::PartialReflect::try_apply(v, value)?;
}
}
} else {
return ::core::result::Result::Err(bevy_reflect::ApplyError::MismatchedKinds {
from_kind: bevy_reflect::PartialReflect::reflect_kind(value),
to_kind: bevy_reflect::ReflectKind::Struct,
});
}
::core::result::Result::Ok(())
}
#[inline]
fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
bevy_reflect::ReflectKind::Struct
}
#[inline]
fn reflect_ref(&self) -> bevy_reflect::ReflectRef {
bevy_reflect::ReflectRef::Struct(self)
}
#[inline]
fn reflect_mut(&mut self) -> bevy_reflect::ReflectMut {
bevy_reflect::ReflectMut::Struct(self)
}
#[inline]
fn reflect_owned(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
-> bevy_reflect::ReflectOwned {
bevy_reflect::ReflectOwned::Struct(self)
}
#[inline]
fn try_into_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect>> {
::core::result::Result::Ok(self)
}
#[inline]
fn try_as_reflect(&self)
-> ::core::option::Option<&dyn bevy_reflect::Reflect> {
::core::option::Option::Some(self)
}
#[inline]
fn try_as_reflect_mut(&mut self)
-> ::core::option::Option<&mut dyn bevy_reflect::Reflect> {
::core::option::Option::Some(self)
}
#[inline]
fn into_partial_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect> {
self
}
#[inline]
fn as_partial_reflect(&self)
-> &dyn bevy_reflect::PartialReflect {
self
}
#[inline]
fn as_partial_reflect_mut(&mut self)
-> &mut dyn bevy_reflect::PartialReflect {
self
}
fn reflect_partial_eq(&self,
value: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<bool> {
(bevy_reflect::structs::struct_partial_eq)(self, value)
}
fn reflect_partial_cmp(&self,
value: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<::core::cmp::Ordering> {
(bevy_reflect::structs::struct_partial_cmp)(self, value)
}
#[inline]
fn reflect_clone(&self)
->
::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
bevy_reflect::ReflectCloneError> {
::core::result::Result::Ok(bevy_reflect::__macro_exports::alloc_utils::Box::new(::core::clone::Clone::clone(self)))
}
}
impl bevy_reflect::FromReflect for Mesh where {
fn from_reflect(reflect: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<Self> {
if let bevy_reflect::ReflectRef::Struct(__ref_struct) =
bevy_reflect::PartialReflect::reflect_ref(reflect) {
let __this =
Self {
indices: <MeshExtractableData<Indices> as
bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
"indices")?)?,
morph_targets: <MeshExtractableData<Vec<MorphAttributes>> as
bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
"morph_targets")?)?,
morph_target_names: <MeshExtractableData<Vec<String>> as
bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
"morph_target_names")?)?,
asset_usage: <RenderAssetUsages as
bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
"asset_usage")?)?,
enable_raytracing: <bool as
bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
"enable_raytracing")?)?,
final_aabb: <Option<Aabb3d> as
bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
"final_aabb")?)?,
skinned_mesh_bounds: <Option<SkinnedMeshBounds> as
bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
"skinned_mesh_bounds")?)?,
primitive_topology: ::core::default::Default::default(),
attributes: ::core::default::Default::default(),
};
::core::option::Option::Some(__this)
} else { ::core::option::Option::None }
}
}
};Reflect, #[automatically_derived]
impl ::core::cmp::PartialEq for Mesh {
#[inline]
fn eq(&self, other: &Mesh) -> bool {
self.enable_raytracing == other.enable_raytracing &&
self.primitive_topology == other.primitive_topology &&
self.attributes == other.attributes &&
self.indices == other.indices &&
self.morph_targets == other.morph_targets &&
self.morph_target_names == other.morph_target_names &&
self.asset_usage == other.asset_usage &&
self.final_aabb == other.final_aabb &&
self.skinned_mesh_bounds == other.skinned_mesh_bounds
}
}PartialEq)]
226#[reflect(Clone)]
227pub struct Mesh {
228#[reflect(ignore, clone)]
229primitive_topology: PrimitiveTopology,
230/// `std::collections::BTreeMap` with all defined vertex attributes (Positions, Normals, ...)
231 /// for this mesh. Attribute ids to attribute values.
232 /// Uses a [`BTreeMap`] because, unlike `HashMap`, it has a defined iteration order,
233 /// which allows easy stable `VertexBuffers` (i.e. same buffer order)
234#[reflect(ignore, clone)]
235attributes: MeshExtractableData<BTreeMap<MeshVertexAttributeId, MeshAttributeData>>,
236 indices: MeshExtractableData<Indices>,
237#[cfg(feature = "morph")]
238morph_targets: MeshExtractableData<Vec<MorphAttributes>>,
239#[cfg(feature = "morph")]
240morph_target_names: MeshExtractableData<Vec<String>>,
241pub asset_usage: RenderAssetUsages,
242/// Whether or not to build a BLAS for use with `bevy_solari` raytracing.
243 ///
244 /// Note that this is _not_ whether the mesh is _compatible_ with `bevy_solari` raytracing.
245 /// This field just controls whether or not a BLAS gets built for this mesh, assuming that
246 /// the mesh is compatible.
247 ///
248 /// The use case for this field is using lower-resolution proxy meshes for raytracing (to save on BLAS memory usage),
249 /// while using higher-resolution meshes for raster. You can set this field to true for the lower-resolution proxy mesh,
250 /// and to false for the high-resolution raster mesh.
251 ///
252 /// Alternatively, you can use the same mesh for both raster and raytracing, with this field set to true.
253 ///
254 /// Does nothing if not used with `bevy_solari`, or if the mesh is not compatible
255 /// with `bevy_solari` (see `bevy_solari`'s docs).
256pub enable_raytracing: bool,
257/// Precomputed min and max extents of the mesh position data. Used mainly for constructing `Aabb`s for frustum culling.
258 /// This data will be set if/when a mesh is extracted to the GPU
259pub final_aabb: Option<Aabb3d>,
260 skinned_mesh_bounds: Option<SkinnedMeshBounds>,
261}
262263impl Mesh {
264/// Where the vertex is located in space. Use in conjunction with [`Mesh::insert_attribute`]
265 /// or [`Mesh::with_inserted_attribute`].
266 ///
267 /// The format of this attribute is [`VertexFormat::Float32x3`].
268pub const ATTRIBUTE_POSITION: MeshVertexAttribute =
269MeshVertexAttribute::new("Vertex_Position", 0, VertexFormat::Float32x3);
270271/// The direction the vertex normal is facing in.
272 /// Use in conjunction with [`Mesh::insert_attribute`] or [`Mesh::with_inserted_attribute`].
273 ///
274 /// The format of this attribute is [`VertexFormat::Float32x3`].
275pub const ATTRIBUTE_NORMAL: MeshVertexAttribute =
276MeshVertexAttribute::new("Vertex_Normal", 1, VertexFormat::Float32x3);
277278/// Texture coordinates for the vertex. Use in conjunction with [`Mesh::insert_attribute`]
279 /// or [`Mesh::with_inserted_attribute`].
280 ///
281 /// Generally `[0.,0.]` is mapped to the top left of the texture, and `[1.,1.]` to the bottom-right.
282 ///
283 /// By default values outside will be clamped per pixel not for the vertex,
284 /// "stretching" the borders of the texture.
285 /// This behavior can be useful in some cases, usually when the borders have only
286 /// one color, for example a logo, and you want to "extend" those borders.
287 ///
288 /// For different mapping outside of `0..=1` range,
289 /// see [`ImageAddressMode`](https://docs.rs/bevy_image/latest/bevy_image/enum.ImageAddressMode.html).
290 ///
291 /// The format of this attribute is [`VertexFormat::Float32x2`].
292pub const ATTRIBUTE_UV_0: MeshVertexAttribute =
293MeshVertexAttribute::new("Vertex_Uv", 2, VertexFormat::Float32x2);
294295/// Alternate texture coordinates for the vertex. Use in conjunction with
296 /// [`Mesh::insert_attribute`] or [`Mesh::with_inserted_attribute`].
297 ///
298 /// Typically, these are used for lightmaps, textures that provide
299 /// precomputed illumination.
300 ///
301 /// The format of this attribute is [`VertexFormat::Float32x2`].
302pub const ATTRIBUTE_UV_1: MeshVertexAttribute =
303MeshVertexAttribute::new("Vertex_Uv_1", 3, VertexFormat::Float32x2);
304305/// The direction of the vertex tangent. Used for normal mapping.
306 /// Usually generated with [`generate_tangents`](Mesh::generate_tangents) or
307 /// [`with_generated_tangents`](Mesh::with_generated_tangents).
308 ///
309 /// The format of this attribute is [`VertexFormat::Float32x4`].
310pub const ATTRIBUTE_TANGENT: MeshVertexAttribute =
311MeshVertexAttribute::new("Vertex_Tangent", 4, VertexFormat::Float32x4);
312313/// Per vertex coloring. Use in conjunction with [`Mesh::insert_attribute`]
314 /// or [`Mesh::with_inserted_attribute`].
315 ///
316 /// The format of this attribute is [`VertexFormat::Float32x4`].
317pub const ATTRIBUTE_COLOR: MeshVertexAttribute =
318MeshVertexAttribute::new("Vertex_Color", 5, VertexFormat::Float32x4);
319320/// Per vertex joint transform matrix weight. Use in conjunction with [`Mesh::insert_attribute`]
321 /// or [`Mesh::with_inserted_attribute`].
322 ///
323 /// The format of this attribute is [`VertexFormat::Float32x4`].
324pub const ATTRIBUTE_JOINT_WEIGHT: MeshVertexAttribute =
325MeshVertexAttribute::new("Vertex_JointWeight", 6, VertexFormat::Float32x4);
326327/// Per vertex joint transform matrix index. Use in conjunction with [`Mesh::insert_attribute`]
328 /// or [`Mesh::with_inserted_attribute`].
329 ///
330 /// The format of this attribute is [`VertexFormat::Uint16x4`].
331pub const ATTRIBUTE_JOINT_INDEX: MeshVertexAttribute =
332MeshVertexAttribute::new("Vertex_JointIndex", 7, VertexFormat::Uint16x4);
333334/// The first index that can be used for custom vertex attributes.
335 /// Only the attributes with an index below this are used by Bevy.
336pub const FIRST_AVAILABLE_CUSTOM_ATTRIBUTE: u64 = 8;
337338/// Construct a new mesh. You need to provide a [`PrimitiveTopology`] so that the
339 /// renderer knows how to treat the vertex data. Most of the time this will be
340 /// [`PrimitiveTopology::TriangleList`].
341pub fn new(primitive_topology: PrimitiveTopology, asset_usage: RenderAssetUsages) -> Self {
342Mesh {
343primitive_topology,
344 attributes: MeshExtractableData::Data(Default::default()),
345 indices: MeshExtractableData::NoData,
346#[cfg(feature = "morph")]
347morph_targets: MeshExtractableData::NoData,
348#[cfg(feature = "morph")]
349morph_target_names: MeshExtractableData::NoData,
350asset_usage,
351 enable_raytracing: true,
352 final_aabb: None,
353 skinned_mesh_bounds: None,
354 }
355 }
356357/// Returns the topology of the mesh.
358pub fn primitive_topology(&self) -> PrimitiveTopology {
359self.primitive_topology
360 }
361362/// Sets the data for a vertex attribute (position, normal, etc.). The name will
363 /// often be one of the associated constants such as [`Mesh::ATTRIBUTE_POSITION`].
364 ///
365 /// `Aabb` of entities with modified mesh are not updated automatically.
366 ///
367 /// # Panics
368 /// Panics when the format of the values does not match the attribute's format.
369 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
370 /// this as an error use [`Mesh::try_insert_attribute`]
371#[inline]
372pub fn insert_attribute(
373&mut self,
374 attribute: MeshVertexAttribute,
375 values: impl Into<VertexAttributeValues>,
376 ) {
377self.try_insert_attribute(attribute, values)
378 .expect(MESH_EXTRACTED_ERROR);
379 }
380381/// Sets the data for a vertex attribute (position, normal, etc.). The name will
382 /// often be one of the associated constants such as [`Mesh::ATTRIBUTE_POSITION`].
383 ///
384 /// `Aabb` of entities with modified mesh are not updated automatically.
385 ///
386 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
387 ///
388 /// # Panics
389 /// Panics when the format of the values does not match the attribute's format.
390#[inline]
391pub fn try_insert_attribute(
392&mut self,
393 attribute: MeshVertexAttribute,
394 values: impl Into<VertexAttributeValues>,
395 ) -> Result<(), MeshAccessError> {
396let values = values.into();
397let values_format = VertexFormat::from(&values);
398if values_format != attribute.format {
399{
::core::panicking::panic_fmt(format_args!("Failed to insert attribute. Invalid attribute format for {0}. Given format is {2:?} but expected {1:?}",
attribute.name, attribute.format, values_format));
};panic!(
400"Failed to insert attribute. Invalid attribute format for {}. Given format is {values_format:?} but expected {:?}",
401 attribute.name, attribute.format
402 );
403 }
404405self.attributes
406 .as_mut()?
407.insert(attribute.id, MeshAttributeData { attribute, values });
408Ok(())
409 }
410411/// Consumes the mesh and returns a mesh with data set for a vertex attribute (position, normal, etc.).
412 /// The name will often be one of the associated constants such as [`Mesh::ATTRIBUTE_POSITION`].
413 ///
414 /// (Alternatively, you can use [`Mesh::insert_attribute`] to mutate an existing mesh in-place)
415 ///
416 /// `Aabb` of entities with modified mesh are not updated automatically.
417 ///
418 /// # Panics
419 /// Panics when the format of the values does not match the attribute's format.
420 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
421 /// this as an error use [`Mesh::try_with_inserted_attribute`]
422#[must_use]
423 #[inline]
424pub fn with_inserted_attribute(
425mut self,
426 attribute: MeshVertexAttribute,
427 values: impl Into<VertexAttributeValues>,
428 ) -> Self {
429self.insert_attribute(attribute, values);
430self431 }
432433/// Consumes the mesh and returns a mesh with data set for a vertex attribute (position, normal, etc.).
434 /// The name will often be one of the associated constants such as [`Mesh::ATTRIBUTE_POSITION`].
435 ///
436 /// (Alternatively, you can use [`Mesh::insert_attribute`] to mutate an existing mesh in-place)
437 ///
438 /// `Aabb` of entities with modified mesh are not updated automatically.
439 ///
440 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
441#[inline]
442pub fn try_with_inserted_attribute(
443mut self,
444 attribute: MeshVertexAttribute,
445 values: impl Into<VertexAttributeValues>,
446 ) -> Result<Self, MeshAccessError> {
447self.try_insert_attribute(attribute, values)?;
448Ok(self)
449 }
450451/// Removes the data for a vertex attribute
452 ///
453 /// # Panics
454 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
455 /// this as an error use [`Mesh::try_remove_attribute`]
456pub fn remove_attribute(
457&mut self,
458 attribute: impl Into<MeshVertexAttributeId>,
459 ) -> Option<VertexAttributeValues> {
460self.attributes
461 .as_mut()
462 .expect(MESH_EXTRACTED_ERROR)
463 .remove(&attribute.into())
464 .map(|data| data.values)
465 }
466467/// Removes the data for a vertex attribute
468 /// Returns an error if the mesh data has been extracted to `RenderWorld`or
469 /// if the attribute does not exist.
470pub fn try_remove_attribute(
471&mut self,
472 attribute: impl Into<MeshVertexAttributeId>,
473 ) -> Result<VertexAttributeValues, MeshAccessError> {
474Ok(self
475.attributes
476 .as_mut()?
477.remove(&attribute.into())
478 .ok_or(MeshAccessError::NotFound)?
479.values)
480 }
481482/// Consumes the mesh and returns a mesh without the data for a vertex attribute
483 ///
484 /// (Alternatively, you can use [`Mesh::remove_attribute`] to mutate an existing mesh in-place)
485 ///
486 /// # Panics
487 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
488 /// this as an error use [`Mesh::try_with_removed_attribute`]
489#[must_use]
490pub fn with_removed_attribute(mut self, attribute: impl Into<MeshVertexAttributeId>) -> Self {
491self.remove_attribute(attribute);
492self493 }
494495/// Consumes the mesh and returns a mesh without the data for a vertex attribute
496 ///
497 /// (Alternatively, you can use [`Mesh::remove_attribute`] to mutate an existing mesh in-place)
498 ///
499 /// Returns an error if the mesh data has been extracted to `RenderWorld`or
500 /// if the attribute does not exist.
501pub fn try_with_removed_attribute(
502mut self,
503 attribute: impl Into<MeshVertexAttributeId>,
504 ) -> Result<Self, MeshAccessError> {
505self.try_remove_attribute(attribute)?;
506Ok(self)
507 }
508509/// Returns a bool indicating if the attribute is present in this mesh's vertex data.
510 ///
511 /// # Panics
512 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
513 /// this as an error use [`Mesh::try_contains_attribute`]
514#[inline]
515pub fn contains_attribute(&self, id: impl Into<MeshVertexAttributeId>) -> bool {
516self.attributes
517 .as_ref()
518 .expect(MESH_EXTRACTED_ERROR)
519 .contains_key(&id.into())
520 }
521522/// Returns a bool indicating if the attribute is present in this mesh's vertex data.
523 ///
524 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
525#[inline]
526pub fn try_contains_attribute(
527&self,
528 id: impl Into<MeshVertexAttributeId>,
529 ) -> Result<bool, MeshAccessError> {
530Ok(self.attributes.as_ref()?.contains_key(&id.into()))
531 }
532533/// Retrieves the data currently set to the vertex attribute with the specified [`MeshVertexAttributeId`].
534 ///
535 /// # Panics
536 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
537 /// this as an error use [`Mesh::try_attribute`] or [`Mesh::try_attribute_option`]
538#[inline]
539pub fn attribute(
540&self,
541 id: impl Into<MeshVertexAttributeId>,
542 ) -> Option<&VertexAttributeValues> {
543self.try_attribute_option(id).expect(MESH_EXTRACTED_ERROR)
544 }
545546/// Retrieves the data currently set to the vertex attribute with the specified [`MeshVertexAttributeId`].
547 ///
548 /// Returns an error if the mesh data has been extracted to `RenderWorld`or
549 /// if the attribute does not exist.
550#[inline]
551pub fn try_attribute(
552&self,
553 id: impl Into<MeshVertexAttributeId>,
554 ) -> Result<&VertexAttributeValues, MeshAccessError> {
555self.try_attribute_option(id)?
556.ok_or(MeshAccessError::NotFound)
557 }
558559/// Retrieves the data currently set to the vertex attribute with the specified [`MeshVertexAttributeId`].
560 ///
561 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
562#[inline]
563pub fn try_attribute_option(
564&self,
565 id: impl Into<MeshVertexAttributeId>,
566 ) -> Result<Option<&VertexAttributeValues>, MeshAccessError> {
567Ok(self
568.attributes
569 .as_ref()?
570.get(&id.into())
571 .map(|data| &data.values))
572 }
573574/// Retrieves the full data currently set to the vertex attribute with the specified [`MeshVertexAttributeId`].
575#[inline]
576pub(crate) fn try_attribute_data(
577&self,
578 id: impl Into<MeshVertexAttributeId>,
579 ) -> Result<Option<&MeshAttributeData>, MeshAccessError> {
580Ok(self.attributes.as_ref()?.get(&id.into()))
581 }
582583/// Retrieves the data currently set to the vertex attribute with the specified `name` mutably.
584 ///
585 /// # Panics
586 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
587 /// this as an error use [`Mesh::try_attribute_mut`]
588#[inline]
589pub fn attribute_mut(
590&mut self,
591 id: impl Into<MeshVertexAttributeId>,
592 ) -> Option<&mut VertexAttributeValues> {
593self.try_attribute_mut_option(id)
594 .expect(MESH_EXTRACTED_ERROR)
595 }
596597/// Retrieves the data currently set to the vertex attribute with the specified `name` mutably.
598 ///
599 /// Returns an error if the mesh data has been extracted to `RenderWorld`or
600 /// if the attribute does not exist.
601#[inline]
602pub fn try_attribute_mut(
603&mut self,
604 id: impl Into<MeshVertexAttributeId>,
605 ) -> Result<&mut VertexAttributeValues, MeshAccessError> {
606self.try_attribute_mut_option(id)?
607.ok_or(MeshAccessError::NotFound)
608 }
609610/// Retrieves the data currently set to the vertex attribute with the specified `name` mutably.
611 ///
612 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
613#[inline]
614pub fn try_attribute_mut_option(
615&mut self,
616 id: impl Into<MeshVertexAttributeId>,
617 ) -> Result<Option<&mut VertexAttributeValues>, MeshAccessError> {
618Ok(self
619.attributes
620 .as_mut()?
621.get_mut(&id.into())
622 .map(|data| &mut data.values))
623 }
624625/// Returns an iterator that yields references to the data of each vertex attribute.
626 ///
627 /// # Panics
628 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
629 /// this as an error use [`Mesh::try_attributes`]
630pub fn attributes(
631&self,
632 ) -> impl Iterator<Item = (&MeshVertexAttribute, &VertexAttributeValues)> {
633self.try_attributes().expect(MESH_EXTRACTED_ERROR)
634 }
635636/// Returns an iterator that yields references to the data of each vertex attribute.
637 /// Returns an error if data has been extracted to `RenderWorld`
638pub fn try_attributes(
639&self,
640 ) -> Result<impl Iterator<Item = (&MeshVertexAttribute, &VertexAttributeValues)>, MeshAccessError>
641 {
642Ok(self
643.attributes
644 .as_ref()?
645.values()
646 .map(|data| (&data.attribute, &data.values)))
647 }
648649/// Returns an iterator that yields mutable references to the data of each vertex attribute.
650 ///
651 /// # Panics
652 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
653 /// this as an error use [`Mesh::try_attributes_mut`]
654pub fn attributes_mut(
655&mut self,
656 ) -> impl Iterator<Item = (&MeshVertexAttribute, &mut VertexAttributeValues)> {
657self.try_attributes_mut().expect(MESH_EXTRACTED_ERROR)
658 }
659660/// Returns an iterator that yields mutable references to the data of each vertex attribute.
661 ///
662 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
663pub fn try_attributes_mut(
664&mut self,
665 ) -> Result<
666impl Iterator<Item = (&MeshVertexAttribute, &mut VertexAttributeValues)>,
667MeshAccessError,
668 > {
669Ok(self
670.attributes
671 .as_mut()?
672.values_mut()
673 .map(|data| (&data.attribute, &mut data.values)))
674 }
675676/// Sets the vertex indices of the mesh. They describe how triangles are constructed out of the
677 /// vertex attributes and are therefore only useful for the [`PrimitiveTopology`] variants
678 /// that use triangles.
679 ///
680 /// # Panics
681 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
682 /// this as an error use [`Mesh::try_insert_indices`]
683#[inline]
684pub fn insert_indices(&mut self, indices: Indices) {
685self.indices
686 .replace(Some(indices))
687 .expect(MESH_EXTRACTED_ERROR);
688 }
689690/// Sets the vertex indices of the mesh. They describe how triangles are constructed out of the
691 /// vertex attributes and are therefore only useful for the [`PrimitiveTopology`] variants
692 /// that use triangles.
693 ///
694 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
695#[inline]
696pub fn try_insert_indices(&mut self, indices: Indices) -> Result<(), MeshAccessError> {
697self.indices.replace(Some(indices))?;
698Ok(())
699 }
700701/// Consumes the mesh and returns a mesh with the given vertex indices. They describe how triangles
702 /// are constructed out of the vertex attributes and are therefore only useful for the
703 /// [`PrimitiveTopology`] variants that use triangles.
704 ///
705 /// (Alternatively, you can use [`Mesh::insert_indices`] to mutate an existing mesh in-place)
706 ///
707 /// # Panics
708 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
709 /// this as an error use [`Mesh::try_with_inserted_indices`]
710#[must_use]
711 #[inline]
712pub fn with_inserted_indices(mut self, indices: Indices) -> Self {
713self.insert_indices(indices);
714self715 }
716717/// Consumes the mesh and returns a mesh with the given vertex indices. They describe how triangles
718 /// are constructed out of the vertex attributes and are therefore only useful for the
719 /// [`PrimitiveTopology`] variants that use triangles.
720 ///
721 /// (Alternatively, you can use [`Mesh::try_insert_indices`] to mutate an existing mesh in-place)
722 ///
723 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
724#[inline]
725pub fn try_with_inserted_indices(mut self, indices: Indices) -> Result<Self, MeshAccessError> {
726self.try_insert_indices(indices)?;
727Ok(self)
728 }
729730/// Retrieves the vertex `indices` of the mesh, returns None if not found.
731 ///
732 /// # Panics
733 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
734 /// this as an error use [`Mesh::try_indices`]
735#[inline]
736pub fn indices(&self) -> Option<&Indices> {
737self.indices.as_ref_option().expect(MESH_EXTRACTED_ERROR)
738 }
739740/// Retrieves the vertex `indices` of the mesh.
741 ///
742 /// Returns an error if the mesh data has been extracted to `RenderWorld`or
743 /// if the attribute does not exist.
744#[inline]
745pub fn try_indices(&self) -> Result<&Indices, MeshAccessError> {
746self.indices.as_ref()
747 }
748749/// Retrieves the vertex `indices` of the mesh, returns None if not found.
750 ///
751 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
752#[inline]
753pub fn try_indices_option(&self) -> Result<Option<&Indices>, MeshAccessError> {
754self.indices.as_ref_option()
755 }
756757/// Retrieves the vertex `indices` of the mesh mutably.
758#[inline]
759pub fn indices_mut(&mut self) -> Option<&mut Indices> {
760self.try_indices_mut_option().expect(MESH_EXTRACTED_ERROR)
761 }
762763/// Retrieves the vertex `indices` of the mesh mutably.
764 ///
765 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
766#[inline]
767pub fn try_indices_mut(&mut self) -> Result<&mut Indices, MeshAccessError> {
768self.indices.as_mut()
769 }
770771/// Retrieves the vertex `indices` of the mesh mutably.
772 ///
773 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
774#[inline]
775pub fn try_indices_mut_option(&mut self) -> Result<Option<&mut Indices>, MeshAccessError> {
776self.indices.as_mut_option()
777 }
778779/// Removes the vertex `indices` from the mesh and returns them.
780 ///
781 /// # Panics
782 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
783 /// this as an error use [`Mesh::try_remove_indices`]
784#[inline]
785pub fn remove_indices(&mut self) -> Option<Indices> {
786self.try_remove_indices().expect(MESH_EXTRACTED_ERROR)
787 }
788789/// Removes the vertex `indices` from the mesh and returns them.
790 ///
791 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
792#[inline]
793pub fn try_remove_indices(&mut self) -> Result<Option<Indices>, MeshAccessError> {
794self.indices.replace(None)
795 }
796797/// Consumes the mesh and returns a mesh without the vertex `indices` of the mesh.
798 ///
799 /// (Alternatively, you can use [`Mesh::remove_indices`] to mutate an existing mesh in-place)
800 ///
801 /// # Panics
802 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
803 /// this as an error use [`Mesh::try_with_removed_indices`]
804#[must_use]
805pub fn with_removed_indices(mut self) -> Self {
806self.remove_indices();
807self808 }
809810/// Consumes the mesh and returns a mesh without the vertex `indices` of the mesh.
811 ///
812 /// (Alternatively, you can use [`Mesh::try_remove_indices`] to mutate an existing mesh in-place)
813 ///
814 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
815pub fn try_with_removed_indices(mut self) -> Result<Self, MeshAccessError> {
816self.try_remove_indices()?;
817Ok(self)
818 }
819820/// Returns the size of a vertex in bytes.
821 ///
822 /// # Panics
823 /// Panics when the mesh data has already been extracted to `RenderWorld`.
824pub fn get_vertex_size(&self) -> u64 {
825self.attributes
826 .as_ref()
827 .expect(MESH_EXTRACTED_ERROR)
828 .values()
829 .map(|data| data.attribute.format.size())
830 .sum()
831 }
832833/// Returns the size required for the vertex buffer in bytes.
834 ///
835 /// # Panics
836 /// Panics when the mesh data has already been extracted to `RenderWorld`.
837pub fn get_vertex_buffer_size(&self) -> usize {
838let vertex_size = self.get_vertex_size() as usize;
839let vertex_count = self.count_vertices();
840vertex_count * vertex_size841 }
842843/// Computes and returns the index data of the mesh as bytes.
844 /// This is used to transform the index data into a GPU friendly format.
845 ///
846 /// # Panics
847 /// Panics when the mesh data has already been extracted to `RenderWorld`.
848pub fn get_index_buffer_bytes(&self) -> Option<&[u8]> {
849let mesh_indices = self.indices.as_ref_option().expect(MESH_EXTRACTED_ERROR);
850851mesh_indices.as_ref().map(|indices| match &indices {
852 Indices::U16(indices) => cast_slice(&indices[..]),
853 Indices::U32(indices) => cast_slice(&indices[..]),
854 })
855 }
856857/// If any morph displacements are present, returns them as a
858 /// [`MorphAttributes`] array.
859 ///
860 /// # Panics
861 /// Panics when the mesh data has already been extracted to the render
862 /// world.
863#[cfg(feature = "morph")]
864pub fn get_morph_targets(&self) -> Option<&[MorphAttributes]> {
865self.morph_targets
866 .as_ref_option()
867 .expect(MESH_EXTRACTED_ERROR)
868 .map(|morph_attributes| &morph_attributes[..])
869 }
870871/// Get this `Mesh`'s [`MeshVertexBufferLayout`], used in `SpecializedMeshPipeline`.
872 ///
873 /// # Panics
874 /// Panics when the mesh data has already been extracted to `RenderWorld`.
875pub fn get_mesh_vertex_buffer_layout(
876&self,
877 mesh_vertex_buffer_layouts: &mut MeshVertexBufferLayouts,
878 ) -> MeshVertexBufferLayoutRef {
879let mesh_attributes = self.attributes.as_ref().expect(MESH_EXTRACTED_ERROR);
880881let mut attributes = Vec::with_capacity(mesh_attributes.len());
882let mut attribute_ids = Vec::with_capacity(mesh_attributes.len());
883let mut accumulated_offset = 0;
884for (index, data) in mesh_attributes.values().enumerate() {
885 attribute_ids.push(data.attribute.id);
886 attributes.push(VertexAttribute {
887 offset: accumulated_offset,
888 format: data.attribute.format,
889 shader_location: index as u32,
890 });
891 accumulated_offset += data.attribute.format.size();
892 }
893894let layout = MeshVertexBufferLayout {
895 layout: VertexBufferLayout {
896 array_stride: accumulated_offset,
897 step_mode: VertexStepMode::Vertex,
898attributes,
899 },
900attribute_ids,
901 };
902mesh_vertex_buffer_layouts.insert(layout)
903 }
904905/// Counts all vertices of the mesh.
906 ///
907 /// If the attributes have different vertex counts, the smallest is returned.
908 ///
909 /// # Panics
910 /// Panics when the mesh data has already been extracted to `RenderWorld`.
911pub fn count_vertices(&self) -> usize {
912let mut vertex_count: Option<usize> = None;
913let mesh_attributes = self.attributes.as_ref().expect(MESH_EXTRACTED_ERROR);
914915for (attribute_id, attribute_data) in mesh_attributes {
916let attribute_len = attribute_data.values.len();
917if let Some(previous_vertex_count) = vertex_count {
918if previous_vertex_count != attribute_len {
919let name = mesh_attributes
920 .get(attribute_id)
921 .map(|data| data.attribute.name.to_string())
922 .unwrap_or_else(|| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?}", attribute_id))
})format!("{attribute_id:?}"));
923924{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event src/mesh.rs:924",
"bevy_mesh::mesh", ::tracing::Level::WARN,
::tracing_core::__macro_support::Option::Some("src/mesh.rs"),
::tracing_core::__macro_support::Option::Some(924u32),
::tracing_core::__macro_support::Option::Some("bevy_mesh::mesh"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::WARN <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::WARN <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("{0} has a different vertex count ({1}) than other attributes ({2}) in this mesh, all attributes will be truncated to match the smallest.",
name, attribute_len, previous_vertex_count) as
&dyn ::tracing::field::Value))])
});
} else { ; }
};warn!("{name} has a different vertex count ({attribute_len}) than other attributes ({previous_vertex_count}) in this mesh, \
925 all attributes will be truncated to match the smallest.");
926 vertex_count = Some(core::cmp::min(previous_vertex_count, attribute_len));
927 }
928 } else {
929 vertex_count = Some(attribute_len);
930 }
931 }
932933vertex_count.unwrap_or(0)
934 }
935936/// Computes and returns the vertex data of the mesh as bytes.
937 /// Therefore the attributes are located in the order of their [`MeshVertexAttribute::id`].
938 /// This is used to transform the vertex data into a GPU friendly format.
939 ///
940 /// If the vertex attributes have different lengths, they are all truncated to
941 /// the length of the smallest.
942 ///
943 /// This is a convenience method which allocates a Vec.
944 /// Prefer pre-allocating and using [`Mesh::write_packed_vertex_buffer_data`] when possible.
945 ///
946 /// # Panics
947 /// Panics when the mesh data has already been extracted to `RenderWorld`.
948pub fn create_packed_vertex_buffer_data(&self) -> Vec<u8> {
949let mut attributes_interleaved_buffer = ::alloc::vec::from_elem(0, self.get_vertex_buffer_size())vec![0; self.get_vertex_buffer_size()];
950self.write_packed_vertex_buffer_data(WriteOnly::from_mut(
951&mut attributes_interleaved_buffer,
952 ));
953attributes_interleaved_buffer954 }
955956/// Computes and write the vertex data of the mesh into a mutable byte slice.
957 /// The attributes are located in the order of their [`MeshVertexAttribute::id`].
958 /// This is used to transform the vertex data into a GPU friendly format.
959 ///
960 /// If the vertex attributes have different lengths, they are all truncated to
961 /// the length of the smallest.
962 ///
963 /// # Panics
964 /// Panics when the mesh data has already been extracted to `RenderWorld`.
965pub fn write_packed_vertex_buffer_data(&self, mut slice: WriteOnly<'_, [u8]>) {
966let mesh_attributes = self.attributes.as_ref().expect(MESH_EXTRACTED_ERROR);
967968let vertex_size = self.get_vertex_size() as usize;
969let vertex_count = self.count_vertices();
970// bundle into interleaved buffers
971let mut attribute_offset = 0;
972for attribute_data in mesh_attributes.values() {
973let attribute_size = attribute_data.attribute.format.size() as usize;
974let attributes_bytes = attribute_data.values.get_bytes();
975for (vertex_index, attribute_bytes) in attributes_bytes
976 .chunks_exact(attribute_size)
977 .take(vertex_count)
978 .enumerate()
979 {
980let offset = vertex_index * vertex_size + attribute_offset;
981 slice
982 .slice(offset..offset + attribute_size)
983 .copy_from_slice(attribute_bytes);
984 }
985986 attribute_offset += attribute_size;
987 }
988 }
989990/// Duplicates the vertex attributes so that no vertices are shared.
991 ///
992 /// This can dramatically increase the vertex count, so make sure this is what you want.
993 /// Does nothing if no [Indices] are set.
994 ///
995 /// # Panics
996 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
997 /// this as an error use [`Mesh::try_duplicate_vertices`]
998pub fn duplicate_vertices(&mut self) {
999self.try_duplicate_vertices().expect(MESH_EXTRACTED_ERROR);
1000 }
10011002/// Duplicates the vertex attributes so that no vertices are shared.
1003 ///
1004 /// This can dramatically increase the vertex count, so make sure this is what you want.
1005 /// Does nothing if no [Indices] are set.
1006 ///
1007 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
1008pub fn try_duplicate_vertices(&mut self) -> Result<(), MeshAccessError> {
1009fn duplicate<T: Copy>(values: &[T], indices: impl Iterator<Item = usize>) -> Vec<T> {
1010indices.map(|i| values[i]).collect()
1011 }
10121013let Some(indices) = self.indices.replace(None)? else {
1014return Ok(());
1015 };
10161017let mesh_attributes = self.attributes.as_mut()?;
10181019for attributes in mesh_attributes.values_mut() {
1020let indices = indices.iter();
1021#[expect(
1022 clippy::match_same_arms,
1023 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."
1024)]
1025match &mut attributes.values {
1026 VertexAttributeValues::Float32(vec) => *vec = duplicate(vec, indices),
1027 VertexAttributeValues::Sint32(vec) => *vec = duplicate(vec, indices),
1028 VertexAttributeValues::Uint32(vec) => *vec = duplicate(vec, indices),
1029 VertexAttributeValues::Float32x2(vec) => *vec = duplicate(vec, indices),
1030 VertexAttributeValues::Sint32x2(vec) => *vec = duplicate(vec, indices),
1031 VertexAttributeValues::Uint32x2(vec) => *vec = duplicate(vec, indices),
1032 VertexAttributeValues::Float32x3(vec) => *vec = duplicate(vec, indices),
1033 VertexAttributeValues::Sint32x3(vec) => *vec = duplicate(vec, indices),
1034 VertexAttributeValues::Uint32x3(vec) => *vec = duplicate(vec, indices),
1035 VertexAttributeValues::Sint32x4(vec) => *vec = duplicate(vec, indices),
1036 VertexAttributeValues::Uint32x4(vec) => *vec = duplicate(vec, indices),
1037 VertexAttributeValues::Float32x4(vec) => *vec = duplicate(vec, indices),
1038 VertexAttributeValues::Sint16x2(vec) => *vec = duplicate(vec, indices),
1039 VertexAttributeValues::Snorm16x2(vec) => *vec = duplicate(vec, indices),
1040 VertexAttributeValues::Uint16x2(vec) => *vec = duplicate(vec, indices),
1041 VertexAttributeValues::Unorm16x2(vec) => *vec = duplicate(vec, indices),
1042 VertexAttributeValues::Sint16x4(vec) => *vec = duplicate(vec, indices),
1043 VertexAttributeValues::Snorm16x4(vec) => *vec = duplicate(vec, indices),
1044 VertexAttributeValues::Uint16x4(vec) => *vec = duplicate(vec, indices),
1045 VertexAttributeValues::Unorm16x4(vec) => *vec = duplicate(vec, indices),
1046 VertexAttributeValues::Sint8x2(vec) => *vec = duplicate(vec, indices),
1047 VertexAttributeValues::Snorm8x2(vec) => *vec = duplicate(vec, indices),
1048 VertexAttributeValues::Uint8x2(vec) => *vec = duplicate(vec, indices),
1049 VertexAttributeValues::Unorm8x2(vec) => *vec = duplicate(vec, indices),
1050 VertexAttributeValues::Sint8x4(vec) => *vec = duplicate(vec, indices),
1051 VertexAttributeValues::Snorm8x4(vec) => *vec = duplicate(vec, indices),
1052 VertexAttributeValues::Uint8x4(vec) => *vec = duplicate(vec, indices),
1053 VertexAttributeValues::Unorm8x4(vec) => *vec = duplicate(vec, indices),
1054 VertexAttributeValues::Uint8(vec) => *vec = duplicate(vec, indices),
1055 VertexAttributeValues::Sint8(vec) => *vec = duplicate(vec, indices),
1056 VertexAttributeValues::Unorm8(vec) => *vec = duplicate(vec, indices),
1057 VertexAttributeValues::Snorm8(vec) => *vec = duplicate(vec, indices),
1058 VertexAttributeValues::Uint16(vec) => *vec = duplicate(vec, indices),
1059 VertexAttributeValues::Sint16(vec) => *vec = duplicate(vec, indices),
1060 VertexAttributeValues::Unorm16(vec) => *vec = duplicate(vec, indices),
1061 VertexAttributeValues::Snorm16(vec) => *vec = duplicate(vec, indices),
1062 VertexAttributeValues::Float16(vec) => *vec = duplicate(vec, indices),
1063 VertexAttributeValues::Float16x2(vec) => *vec = duplicate(vec, indices),
1064 VertexAttributeValues::Float16x4(vec) => *vec = duplicate(vec, indices),
1065 VertexAttributeValues::Float64(vec) => *vec = duplicate(vec, indices),
1066 VertexAttributeValues::Float64x2(vec) => *vec = duplicate(vec, indices),
1067 VertexAttributeValues::Float64x3(vec) => *vec = duplicate(vec, indices),
1068 VertexAttributeValues::Float64x4(vec) => *vec = duplicate(vec, indices),
1069 VertexAttributeValues::Unorm10_10_10_2(vec) => *vec = duplicate(vec, indices),
1070 VertexAttributeValues::Unorm8x4Bgra(vec) => *vec = duplicate(vec, indices),
1071 }
1072 }
10731074Ok(())
1075 }
10761077/// Consumes the mesh and returns a mesh with no shared vertices.
1078 ///
1079 /// This can dramatically increase the vertex count, so make sure this is what you want.
1080 /// Does nothing if no [`Indices`] are set.
1081 ///
1082 /// (Alternatively, you can use [`Mesh::duplicate_vertices`] to mutate an existing mesh in-place)
1083 ///
1084 /// # Panics
1085 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1086 /// this as an error use [`Mesh::try_with_duplicated_vertices`]
1087#[must_use]
1088pub fn with_duplicated_vertices(mut self) -> Self {
1089self.duplicate_vertices();
1090self1091 }
10921093/// Consumes the mesh and returns a mesh with no shared vertices.
1094 ///
1095 /// This can dramatically increase the vertex count, so make sure this is what you want.
1096 /// Does nothing if no [`Indices`] are set.
1097 ///
1098 /// (Alternatively, you can use [`Mesh::try_duplicate_vertices`] to mutate an existing mesh in-place)
1099 ///
1100 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
1101pub fn try_with_duplicated_vertices(mut self) -> Result<Self, MeshAccessError> {
1102self.try_duplicate_vertices()?;
1103Ok(self)
1104 }
11051106/// Remove duplicate vertices and create the index pointing to the unique vertices.
1107 ///
1108 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
1109 /// Returns an error if the mesh already has [`Indices`] set, even if there
1110 /// are duplicate vertices. If deduplication is needed with indices already set,
1111 /// consider calling [`Mesh::duplicate_vertices`] and then this function.
1112pub fn merge_duplicate_vertices(&mut self) -> Result<(), MeshMergeDuplicateVerticesError> {
1113match self.try_indices() {
1114Ok(_) => return Err(MeshMergeDuplicateVerticesError::IndicesAlreadySet),
1115Err(err) => match err {
1116 MeshAccessError::ExtractedToRenderWorld => return Err(err.into()),
1117 MeshAccessError::NotFound => (),
1118 },
1119 }
11201121#[derive(#[automatically_derived]
impl<'a> ::core::marker::Copy for VertexRef<'a> { }Copy, #[automatically_derived]
impl<'a> ::core::clone::Clone for VertexRef<'a> {
#[inline]
fn clone(&self) -> VertexRef<'a> {
let _:
::core::clone::AssertParamIsClone<&'a BTreeMap<MeshVertexAttributeId,
MeshAttributeData>>;
let _: ::core::clone::AssertParamIsClone<usize>;
*self
}
}Clone)]
1122struct VertexRef<'a> {
1123 mesh_attributes: &'a BTreeMap<MeshVertexAttributeId, MeshAttributeData>,
1124 i: usize,
1125 }
1126impl<'a> VertexRef<'a> {
1127fn push_to(&self, target: &mut BTreeMap<MeshVertexAttributeId, MeshAttributeData>) {
1128for (key, this_attribute_data) in self.mesh_attributes.iter() {
1129let target_attribute_data = target.get_mut(key).unwrap(); // ok to unwrap, all keys added to new_attributes below
1130target_attribute_data
1131 .values
1132 .push_from(&this_attribute_data.values, self.i);
1133 }
1134 }
1135 }
1136impl<'a> PartialEqfor VertexRef<'a> {
1137fn eq(&self, other: &Self) -> bool {
1138if !ptr::eq(self.mesh_attributes, other.mesh_attributes) {
::core::panicking::panic("assertion failed: ptr::eq(self.mesh_attributes, other.mesh_attributes)")
};assert!(ptr::eq(self.mesh_attributes, other.mesh_attributes));
1139for values in self.mesh_attributes.values() {
1140if values.values.get_bytes_at(self.i) != values.values.get_bytes_at(other.i) {
1141return false;
1142 }
1143 }
1144true
1145}
1146 }
1147impl<'a> Eqfor VertexRef<'a> {}
1148impl<'a> Hashfor VertexRef<'a> {
1149fn hash<H: Hasher>(&self, state: &mut H) {
1150for values in self.mesh_attributes.values() {
1151 values.values.get_bytes_at(self.i).hash(state);
1152 }
1153 }
1154 }
11551156let old_attributes = self.attributes.as_ref()?;
11571158let mut new_attributes: BTreeMap<MeshVertexAttributeId, MeshAttributeData> = self
1159.attributes
1160 .as_ref()?
1161.iter()
1162 .map(|(k, v)| {
1163 (
1164*k,
1165MeshAttributeData {
1166 attribute: v.attribute,
1167 values: VertexAttributeValues::new(VertexFormat::from(&v.values)),
1168 },
1169 )
1170 })
1171 .collect();
11721173let mut vertex_to_new_index: HashMap<VertexRef, u32> = HashMap::new();
1174let mut indices = Vec::with_capacity(self.count_vertices());
1175for i in 0..self.count_vertices() {
1176let len: u32 = vertex_to_new_index
1177 .len()
1178 .try_into()
1179 .expect("The number of vertices exceeds u32::MAX");
1180let vertex_ref = VertexRef {
1181 mesh_attributes: old_attributes,
1182 i,
1183 };
1184let j = match vertex_to_new_index.entry(vertex_ref) {
1185 hash_map::Entry::Occupied(e) => *e.get(),
1186 hash_map::Entry::Vacant(e) => {
1187 e.insert(len);
1188 vertex_ref.push_to(&mut new_attributes);
1189 len
1190 }
1191 };
1192 indices.push(j);
1193 }
1194drop(vertex_to_new_index);
11951196for v in new_attributes.values_mut() {
1197 v.values.shrink_to_fit();
1198 }
11991200self.attributes = MeshExtractableData::Data(new_attributes);
1201self.indices = MeshExtractableData::Data(Indices::U32(indices));
12021203Ok(())
1204 }
12051206/// Consumes the mesh and returns a mesh with merged vertices.
1207 ///
1208 /// (Alternatively, you can use [`Mesh::merge_duplicate_vertices`] to mutate an existing mesh in-place)
1209 ///
1210 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
1211 /// Returns an error if the mesh already has [`Indices`] set, even if there
1212 /// are duplicate vertices. If deduplication is needed with indices already set,
1213 /// consider calling [`Mesh::duplicate_vertices`] and then this function.
1214pub fn with_merge_duplicate_vertices(
1215mut self,
1216 ) -> Result<Self, MeshMergeDuplicateVerticesError> {
1217self.merge_duplicate_vertices()?;
1218Ok(self)
1219 }
12201221/// Inverts the winding of the indices such that all counter-clockwise triangles are now
1222 /// clockwise and vice versa.
1223 /// For lines, their start and end indices are flipped.
1224 ///
1225 /// Does nothing if no [`Indices`] are set.
1226 /// If this operation succeeded, an [`Ok`] result is returned.
1227pub fn invert_winding(&mut self) -> Result<(), MeshWindingInvertError> {
1228fn invert<I>(
1229 indices: &mut [I],
1230 topology: PrimitiveTopology,
1231 ) -> Result<(), MeshWindingInvertError> {
1232match topology {
1233 PrimitiveTopology::TriangleList => {
1234let (chunks, []) = indices.as_chunks_mut() else {
1235// Early return if the index count doesn't match
1236return Err(MeshWindingInvertError::AbruptIndicesEnd);
1237 };
12381239for [_, b, c] in chunks {
1240 core::mem::swap(b, c);
1241 }
1242Ok(())
1243 }
1244 PrimitiveTopology::LineList => {
1245// Early return if the index count doesn't match
1246if !indices.len().is_multiple_of(2) {
1247return Err(MeshWindingInvertError::AbruptIndicesEnd);
1248 }
1249indices.reverse();
1250Ok(())
1251 }
1252 PrimitiveTopology::TriangleStrip | PrimitiveTopology::LineStrip => {
1253indices.reverse();
1254Ok(())
1255 }
1256_ => Err(MeshWindingInvertError::WrongTopology),
1257 }
1258 }
12591260let mesh_indices = self.indices.as_mut_option()?;
12611262match mesh_indices {
1263Some(Indices::U16(vec)) => invert(vec, self.primitive_topology),
1264Some(Indices::U32(vec)) => invert(vec, self.primitive_topology),
1265None => Ok(()),
1266 }
1267 }
12681269/// Consumes the mesh and returns a mesh with inverted winding of the indices such
1270 /// that all counter-clockwise triangles are now clockwise and vice versa.
1271 ///
1272 /// Does nothing if no [`Indices`] are set.
1273pub fn with_inverted_winding(mut self) -> Result<Self, MeshWindingInvertError> {
1274self.invert_winding().map(|_| self)
1275 }
12761277/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of a mesh.
1278 /// If the mesh is indexed, this defaults to smooth normals. Otherwise, it defaults to flat
1279 /// normals.
1280 ///
1281 /// # Panics
1282 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1283 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].=
1284 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1285 /// this as an error use [`Mesh::try_compute_normals`]
1286pub fn compute_normals(&mut self) {
1287self.try_compute_normals().expect(MESH_EXTRACTED_ERROR);
1288 }
12891290/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of a mesh.
1291 /// If the mesh is indexed, this defaults to smooth normals. Otherwise, it defaults to flat
1292 /// normals.
1293 ///
1294 /// # Panics
1295 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1296 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].=
1297pub fn try_compute_normals(&mut self) -> Result<(), MeshAccessError> {
1298if !#[allow(non_exhaustive_omitted_patterns)] match self.primitive_topology {
PrimitiveTopology::TriangleList => true,
_ => false,
} {
{
::core::panicking::panic_fmt(format_args!("`compute_normals` can only work on `TriangleList`s"));
}
};assert!(
1299matches!(self.primitive_topology, PrimitiveTopology::TriangleList),
1300"`compute_normals` can only work on `TriangleList`s"
1301);
1302if self.try_indices_option()?.is_none() {
1303self.try_compute_flat_normals()
1304 } else {
1305self.try_compute_smooth_normals()
1306 }
1307 }
13081309/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of a mesh.
1310 ///
1311 /// # Panics
1312 /// Panics if [`Indices`] are set or [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1313 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1314 /// Consider calling [`Mesh::duplicate_vertices`] or exporting your mesh with normal
1315 /// attributes.
1316 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1317 /// this as an error use [`Mesh::try_compute_flat_normals`]
1318 ///
1319 /// FIXME: This should handle more cases since this is called as a part of gltf
1320 /// mesh loading where we can't really blame users for loading meshes that might
1321 /// not conform to the limitations here!
1322pub fn compute_flat_normals(&mut self) {
1323self.try_compute_flat_normals().expect(MESH_EXTRACTED_ERROR);
1324 }
13251326/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of a mesh.
1327 ///
1328 /// # Panics
1329 /// Panics if [`Indices`] are set or [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1330 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1331 /// Consider calling [`Mesh::duplicate_vertices`] or exporting your mesh with normal
1332 /// attributes.
1333 ///
1334 /// FIXME: This should handle more cases since this is called as a part of gltf
1335 /// mesh loading where we can't really blame users for loading meshes that might
1336 /// not conform to the limitations here!
1337pub fn try_compute_flat_normals(&mut self) -> Result<(), MeshAccessError> {
1338if !self.try_indices_option()?.is_none() {
{
::core::panicking::panic_fmt(format_args!("`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`."));
}
};assert!(
1339self.try_indices_option()?.is_none(),
1340"`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`."
1341);
1342if !#[allow(non_exhaustive_omitted_patterns)] match self.primitive_topology {
PrimitiveTopology::TriangleList => true,
_ => false,
} {
{
::core::panicking::panic_fmt(format_args!("`compute_flat_normals` can only work on `TriangleList`s"));
}
};assert!(
1343matches!(self.primitive_topology, PrimitiveTopology::TriangleList),
1344"`compute_flat_normals` can only work on `TriangleList`s"
1345);
13461347let positions = self
1348.try_attribute(Mesh::ATTRIBUTE_POSITION)?
1349.as_float3()
1350 .expect("`Mesh::ATTRIBUTE_POSITION` vertex attributes should be of type `float3`");
13511352let normals: Vec<_> = positions1353 .as_chunks()
1354 .0
1355.iter()
1356 .flat_map(|&[a, b, c]| [triangle_normal(a, b, c); 3])
1357 .collect();
13581359self.try_insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals)
1360 }
13611362/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of an indexed mesh, smoothing normals for shared
1363 /// vertices.
1364 ///
1365 /// This method weights normals by the angles of the corners of connected triangles, thus
1366 /// eliminating triangle area and count as factors in the final normal. This does make it
1367 /// somewhat slower than [`Mesh::compute_area_weighted_normals`] which does not need to
1368 /// greedily normalize each triangle's normal or calculate corner angles.
1369 ///
1370 /// If you would rather have the computed normals be weighted by triangle area, see
1371 /// [`Mesh::compute_area_weighted_normals`] instead. If you need to weight them in some other
1372 /// way, see [`Mesh::compute_custom_smooth_normals`].
1373 ///
1374 /// # Panics
1375 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1376 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1377 /// Panics if the mesh does not have indices defined.
1378 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1379 /// this as an error use [`Mesh::try_compute_smooth_normals`]
1380pub fn compute_smooth_normals(&mut self) {
1381self.try_compute_smooth_normals()
1382 .expect(MESH_EXTRACTED_ERROR);
1383 }
13841385/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of an indexed mesh, smoothing normals for shared
1386 /// vertices.
1387 ///
1388 /// This method weights normals by the angles of the corners of connected triangles, thus
1389 /// eliminating triangle area and count as factors in the final normal. This does make it
1390 /// somewhat slower than [`Mesh::compute_area_weighted_normals`] which does not need to
1391 /// greedily normalize each triangle's normal or calculate corner angles.
1392 ///
1393 /// If you would rather have the computed normals be weighted by triangle area, see
1394 /// [`Mesh::compute_area_weighted_normals`] instead. If you need to weight them in some other
1395 /// way, see [`Mesh::compute_custom_smooth_normals`].
1396 ///
1397 /// # Panics
1398 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1399 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1400 /// Panics if the mesh does not have indices defined.
1401pub fn try_compute_smooth_normals(&mut self) -> Result<(), MeshAccessError> {
1402self.try_compute_custom_smooth_normals(|[a, b, c], positions, normals| {
1403let pa = Vec3::from(positions[a]);
1404let pb = Vec3::from(positions[b]);
1405let pc = Vec3::from(positions[c]);
14061407let ab = pb - pa;
1408let ba = pa - pb;
1409let bc = pc - pb;
1410let cb = pb - pc;
1411let ca = pa - pc;
1412let ac = pc - pa;
14131414const EPS: f32 = f32::EPSILON;
1415let weight_a = if ab.length_squared() * ac.length_squared() > EPS {
1416ab.angle_between(ac)
1417 } else {
14180.0
1419};
1420let weight_b = if ba.length_squared() * bc.length_squared() > EPS {
1421ba.angle_between(bc)
1422 } else {
14230.0
1424};
1425let weight_c = if ca.length_squared() * cb.length_squared() > EPS {
1426ca.angle_between(cb)
1427 } else {
14280.0
1429};
14301431let normal = Vec3::from(triangle_normal(positions[a], positions[b], positions[c]));
14321433normals[a] += normal * weight_a;
1434normals[b] += normal * weight_b;
1435normals[c] += normal * weight_c;
1436 })
1437 }
14381439/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of an indexed mesh, smoothing normals for shared
1440 /// vertices.
1441 ///
1442 /// This method weights normals by the area of each triangle containing the vertex. Thus,
1443 /// larger triangles will skew the normals of their vertices towards their own normal more
1444 /// than smaller triangles will.
1445 ///
1446 /// This method is actually somewhat faster than [`Mesh::compute_smooth_normals`] because an
1447 /// intermediate result of triangle normal calculation is already scaled by the triangle's area.
1448 ///
1449 /// If you would rather have the computed normals be influenced only by the angles of connected
1450 /// edges, see [`Mesh::compute_smooth_normals`] instead. If you need to weight them in some
1451 /// other way, see [`Mesh::compute_custom_smooth_normals`].
1452 ///
1453 /// # Panics
1454 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1455 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1456 /// Panics if the mesh does not have indices defined.
1457 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1458 /// this as an error use [`Mesh::try_compute_area_weighted_normals`]
1459pub fn compute_area_weighted_normals(&mut self) {
1460self.try_compute_area_weighted_normals()
1461 .expect(MESH_EXTRACTED_ERROR);
1462 }
14631464/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of an indexed mesh, smoothing normals for shared
1465 /// vertices.
1466 ///
1467 /// This method weights normals by the area of each triangle containing the vertex. Thus,
1468 /// larger triangles will skew the normals of their vertices towards their own normal more
1469 /// than smaller triangles will.
1470 ///
1471 /// This method is actually somewhat faster than [`Mesh::compute_smooth_normals`] because an
1472 /// intermediate result of triangle normal calculation is already scaled by the triangle's area.
1473 ///
1474 /// If you would rather have the computed normals be influenced only by the angles of connected
1475 /// edges, see [`Mesh::compute_smooth_normals`] instead. If you need to weight them in some
1476 /// other way, see [`Mesh::compute_custom_smooth_normals`].
1477 ///
1478 /// # Panics
1479 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1480 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1481 /// Panics if the mesh does not have indices defined.
1482pub fn try_compute_area_weighted_normals(&mut self) -> Result<(), MeshAccessError> {
1483self.try_compute_custom_smooth_normals(|[a, b, c], positions, normals| {
1484let normal = Vec3::from(triangle_area_normal(
1485positions[a],
1486positions[b],
1487positions[c],
1488 ));
1489 [a, b, c].into_iter().for_each(|pos| {
1490normals[pos] += normal;
1491 });
1492 })
1493 }
14941495/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of an indexed mesh, smoothing normals for shared
1496 /// vertices.
1497 ///
1498 /// This method allows you to customize how normals are weighted via the `per_triangle` parameter,
1499 /// which must be a function or closure that accepts 3 parameters:
1500 /// - The indices of the three vertices of the triangle as a `[usize; 3]`.
1501 /// - A reference to the values of the [`Mesh::ATTRIBUTE_POSITION`] of the mesh (`&[[f32; 3]]`).
1502 /// - A mutable reference to the sums of all normals so far.
1503 ///
1504 /// See also the standard methods included in Bevy for calculating smooth normals:
1505 /// - [`Mesh::compute_smooth_normals`]
1506 /// - [`Mesh::compute_area_weighted_normals`]
1507 ///
1508 /// An example that would weight each connected triangle's normal equally, thus skewing normals
1509 /// towards the planes divided into the most triangles:
1510 /// ```
1511 /// # use bevy_asset::RenderAssetUsages;
1512 /// # use bevy_mesh::{Mesh, PrimitiveTopology, Meshable, MeshBuilder};
1513 /// # use bevy_math::{Vec3, primitives::Cuboid};
1514 /// # let mut mesh = Cuboid::default().mesh().build();
1515 /// mesh.compute_custom_smooth_normals(|[a, b, c], positions, normals| {
1516 /// let normal = Vec3::from(bevy_mesh::triangle_normal(positions[a], positions[b], positions[c]));
1517 /// for idx in [a, b, c] {
1518 /// normals[idx] += normal;
1519 /// }
1520 /// });
1521 /// ```
1522 ///
1523 /// # Panics
1524 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1525 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1526 /// Panics if the mesh does not have indices defined.
1527 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1528 /// this as an error use [`Mesh::try_compute_custom_smooth_normals`]
1529//
1530 // FIXME: This should handle more cases since this is called as a part of gltf
1531 // mesh loading where we can't really blame users for loading meshes that might
1532 // not conform to the limitations here!
1533 //
1534 // When fixed, also update "Panics" sections of
1535 // - [Mesh::compute_smooth_normals]
1536 // - [Mesh::with_computed_smooth_normals]
1537 // - [Mesh::compute_area_weighted_normals]
1538 // - [Mesh::with_computed_area_weighted_normals]
1539pub fn compute_custom_smooth_normals(
1540&mut self,
1541 per_triangle: impl FnMut([usize; 3], &[[f32; 3]], &mut [Vec3]),
1542 ) {
1543self.try_compute_custom_smooth_normals(per_triangle)
1544 .expect(MESH_EXTRACTED_ERROR);
1545 }
15461547/// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of an indexed mesh, smoothing normals for shared
1548 /// vertices.
1549 ///
1550 /// This method allows you to customize how normals are weighted via the `per_triangle` parameter,
1551 /// which must be a function or closure that accepts 3 parameters:
1552 /// - The indices of the three vertices of the triangle as a `[usize; 3]`.
1553 /// - A reference to the values of the [`Mesh::ATTRIBUTE_POSITION`] of the mesh (`&[[f32; 3]]`).
1554 /// - A mutable reference to the sums of all normals so far.
1555 ///
1556 /// See also the standard methods included in Bevy for calculating smooth normals:
1557 /// - [`Mesh::compute_smooth_normals`]
1558 /// - [`Mesh::compute_area_weighted_normals`]
1559 ///
1560 /// An example that would weight each connected triangle's normal equally, thus skewing normals
1561 /// towards the planes divided into the most triangles:
1562 /// ```
1563 /// # use bevy_asset::RenderAssetUsages;
1564 /// # use bevy_mesh::{Mesh, PrimitiveTopology, Meshable, MeshBuilder};
1565 /// # use bevy_math::{Vec3, primitives::Cuboid};
1566 /// # let mut mesh = Cuboid::default().mesh().build();
1567 /// mesh.compute_custom_smooth_normals(|[a, b, c], positions, normals| {
1568 /// let normal = Vec3::from(bevy_mesh::triangle_normal(positions[a], positions[b], positions[c]));
1569 /// for idx in [a, b, c] {
1570 /// normals[idx] += normal;
1571 /// }
1572 /// });
1573 /// ```
1574 ///
1575 /// # Panics
1576 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1577 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1578 /// Panics if the mesh does not have indices defined.
1579//
1580 // FIXME: This should handle more cases since this is called as a part of gltf
1581 // mesh loading where we can't really blame users for loading meshes that might
1582 // not conform to the limitations here!
1583 //
1584 // When fixed, also update "Panics" sections of
1585 // - [Mesh::compute_smooth_normals]
1586 // - [Mesh::with_computed_smooth_normals]
1587 // - [Mesh::compute_area_weighted_normals]
1588 // - [Mesh::with_computed_area_weighted_normals]
1589pub fn try_compute_custom_smooth_normals(
1590&mut self,
1591mut per_triangle: impl FnMut([usize; 3], &[[f32; 3]], &mut [Vec3]),
1592 ) -> Result<(), MeshAccessError> {
1593if !#[allow(non_exhaustive_omitted_patterns)] match self.primitive_topology {
PrimitiveTopology::TriangleList => true,
_ => false,
} {
{
::core::panicking::panic_fmt(format_args!("smooth normals can only be computed on `TriangleList`s"));
}
};assert!(
1594matches!(self.primitive_topology, PrimitiveTopology::TriangleList),
1595"smooth normals can only be computed on `TriangleList`s"
1596);
1597if !self.try_indices_option()?.is_some() {
{
::core::panicking::panic_fmt(format_args!("smooth normals can only be computed on indexed meshes"));
}
};assert!(
1598self.try_indices_option()?.is_some(),
1599"smooth normals can only be computed on indexed meshes"
1600);
16011602let positions = self
1603.try_attribute(Mesh::ATTRIBUTE_POSITION)?
1604.as_float3()
1605 .expect("`Mesh::ATTRIBUTE_POSITION` vertex attributes should be of type `float3`");
16061607let mut normals = ::alloc::vec::from_elem(Vec3::ZERO, positions.len())vec![Vec3::ZERO; positions.len()];
16081609match self.try_indices()? {
1610 Indices::U16(vec) => vec.as_chunks().0.iter().for_each(|&chunk| {
1611per_triangle(chunk.map(|i| ias usize), positions, &mut normals);
1612 }),
1613 Indices::U32(vec) => vec.as_chunks().0.iter().for_each(|&chunk| {
1614per_triangle(chunk.map(|i| ias usize), positions, &mut normals);
1615 }),
1616 }
16171618for normal in &mut normals {
1619*normal = normal.try_normalize().unwrap_or(Vec3::ZERO);
1620 }
16211622self.try_insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals)
1623 }
16241625/// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
1626 /// If the mesh is indexed, this defaults to smooth normals. Otherwise, it defaults to flat
1627 /// normals.
1628 ///
1629 /// (Alternatively, you can use [`Mesh::compute_normals`] to mutate an existing mesh in-place)
1630 ///
1631 /// # Panics
1632 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1633 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1634 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1635 /// this as an error use [`Mesh::try_with_computed_normals`]
1636#[must_use]
1637pub fn with_computed_normals(self) -> Self {
1638self.try_with_computed_normals()
1639 .expect(MESH_EXTRACTED_ERROR)
1640 }
16411642/// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
1643 /// If the mesh is indexed, this defaults to smooth normals. Otherwise, it defaults to flat
1644 /// normals.
1645 ///
1646 /// (Alternatively, you can use [`Mesh::compute_normals`] to mutate an existing mesh in-place)
1647 ///
1648 /// # Panics
1649 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1650 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1651pub fn try_with_computed_normals(mut self) -> Result<Self, MeshAccessError> {
1652self.try_compute_normals()?;
1653Ok(self)
1654 }
16551656/// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
1657 ///
1658 /// (Alternatively, you can use [`Mesh::compute_flat_normals`] to mutate an existing mesh in-place)
1659 ///
1660 /// # Panics
1661 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1662 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1663 /// Panics if the mesh has indices defined
1664 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1665 /// this as an error use [`Mesh::try_with_computed_flat_normals`]
1666pub fn with_computed_flat_normals(mut self) -> Self {
1667self.compute_flat_normals();
1668self1669 }
16701671/// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
1672 ///
1673 /// (Alternatively, you can use [`Mesh::compute_flat_normals`] to mutate an existing mesh in-place)
1674 ///
1675 /// # Panics
1676 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1677 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1678 /// Panics if the mesh has indices defined
1679pub fn try_with_computed_flat_normals(mut self) -> Result<Self, MeshAccessError> {
1680self.try_compute_flat_normals()?;
1681Ok(self)
1682 }
16831684/// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
1685 ///
1686 /// (Alternatively, you can use [`Mesh::compute_smooth_normals`] to mutate an existing mesh in-place)
1687 ///
1688 /// This method weights normals by the angles of triangle corners connected to each vertex. If
1689 /// you would rather have the computed normals be weighted by triangle area, see
1690 /// [`Mesh::with_computed_area_weighted_normals`] instead.
1691 ///
1692 /// # Panics
1693 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1694 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1695 /// Panics if the mesh does not have indices defined.
1696 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1697 /// this as an error use [`Mesh::try_with_computed_smooth_normals`]
1698pub fn with_computed_smooth_normals(mut self) -> Self {
1699self.compute_smooth_normals();
1700self1701 }
1702/// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
1703 ///
1704 /// (Alternatively, you can use [`Mesh::compute_smooth_normals`] to mutate an existing mesh in-place)
1705 ///
1706 /// This method weights normals by the angles of triangle corners connected to each vertex. If
1707 /// you would rather have the computed normals be weighted by triangle area, see
1708 /// [`Mesh::with_computed_area_weighted_normals`] instead.
1709 ///
1710 /// # Panics
1711 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1712 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1713 /// Panics if the mesh does not have indices defined.
1714pub fn try_with_computed_smooth_normals(mut self) -> Result<Self, MeshAccessError> {
1715self.try_compute_smooth_normals()?;
1716Ok(self)
1717 }
17181719/// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
1720 ///
1721 /// (Alternatively, you can use [`Mesh::compute_area_weighted_normals`] to mutate an existing mesh in-place)
1722 ///
1723 /// This method weights normals by the area of each triangle containing the vertex. Thus,
1724 /// larger triangles will skew the normals of their vertices towards their own normal more
1725 /// than smaller triangles will. If you would rather have the computed normals be influenced
1726 /// only by the angles of connected edges, see [`Mesh::with_computed_smooth_normals`] instead.
1727 ///
1728 /// # Panics
1729 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1730 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1731 /// Panics if the mesh does not have indices defined.
1732 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1733 /// this as an error use [`Mesh::try_with_computed_area_weighted_normals`]
1734pub fn with_computed_area_weighted_normals(mut self) -> Self {
1735self.compute_area_weighted_normals();
1736self1737 }
17381739/// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`].
1740 ///
1741 /// (Alternatively, you can use [`Mesh::compute_area_weighted_normals`] to mutate an existing mesh in-place)
1742 ///
1743 /// This method weights normals by the area of each triangle containing the vertex. Thus,
1744 /// larger triangles will skew the normals of their vertices towards their own normal more
1745 /// than smaller triangles will. If you would rather have the computed normals be influenced
1746 /// only by the angles of connected edges, see [`Mesh::with_computed_smooth_normals`] instead.
1747 ///
1748 /// # Panics
1749 /// Panics if [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3`.
1750 /// Panics if the mesh has any other topology than [`PrimitiveTopology::TriangleList`].
1751 /// Panics if the mesh does not have indices defined.
1752pub fn try_with_computed_area_weighted_normals(mut self) -> Result<Self, MeshAccessError> {
1753self.try_compute_area_weighted_normals()?;
1754Ok(self)
1755 }
17561757/// Generate tangents for the mesh using the `mikktspace` algorithm.
1758 ///
1759 /// Sets the [`Mesh::ATTRIBUTE_TANGENT`] attribute if successful.
1760 /// Requires a [`PrimitiveTopology::TriangleList`] topology and the [`Mesh::ATTRIBUTE_POSITION`], [`Mesh::ATTRIBUTE_NORMAL`] and [`Mesh::ATTRIBUTE_UV_0`] attributes set.
1761#[cfg(feature = "bevy_mikktspace")]
1762pub fn generate_tangents(&mut self) -> Result<(), super::GenerateTangentsError> {
1763let tangents = super::generate_tangents_for_mesh(self)?;
1764self.try_insert_attribute(Mesh::ATTRIBUTE_TANGENT, tangents)?;
1765Ok(())
1766 }
17671768/// Consumes the mesh and returns a mesh with tangents generated using the `mikktspace` algorithm.
1769 ///
1770 /// The resulting mesh will have the [`Mesh::ATTRIBUTE_TANGENT`] attribute if successful.
1771 ///
1772 /// (Alternatively, you can use [`Mesh::generate_tangents`] to mutate an existing mesh in-place)
1773 ///
1774 /// Requires a [`PrimitiveTopology::TriangleList`] topology and the [`Mesh::ATTRIBUTE_POSITION`], [`Mesh::ATTRIBUTE_NORMAL`] and [`Mesh::ATTRIBUTE_UV_0`] attributes set.
1775#[cfg(feature = "bevy_mikktspace")]
1776pub fn with_generated_tangents(mut self) -> Result<Mesh, super::GenerateTangentsError> {
1777self.generate_tangents()?;
1778Ok(self)
1779 }
17801781/// Merges the [`Mesh`] data of `other` with `self`. The attributes and indices of `other` will be appended to `self`.
1782 ///
1783 /// Note that attributes of `other` that don't exist on `self` will be ignored.
1784 ///
1785 /// `Aabb` of entities with modified mesh are not updated automatically.
1786 ///
1787 /// # Errors
1788 ///
1789 /// If any of the following conditions are not met, this function errors:
1790 /// * All of the vertex attributes that have the same attribute id, must also
1791 /// have the same attribute type.
1792 /// For example two attributes with the same id, but where one is a
1793 /// [`VertexAttributeValues::Float32`] and the other is a
1794 /// [`VertexAttributeValues::Float32x3`], would be invalid.
1795 /// * Both meshes must have the same primitive topology.
1796pub fn merge(&mut self, other: &Mesh) -> Result<(), MeshMergeError> {
1797use VertexAttributeValues::*;
17981799// Check if the meshes `primitive_topology` field is the same,
1800 // as if that is not the case, the resulting mesh could (and most likely would)
1801 // be invalid.
1802if self.primitive_topology != other.primitive_topology {
1803return Err(MeshMergeError::IncompatiblePrimitiveTopology {
1804 self_primitive_topology: self.primitive_topology,
1805 other_primitive_topology: other.primitive_topology,
1806 });
1807 }
18081809// The indices of `other` should start after the last vertex of `self`.
1810let index_offset = self.count_vertices();
18111812// Extend attributes of `self` with attributes of `other`.
1813for (attribute, values) in self.try_attributes_mut()? {
1814if let Some(other_values) = other.try_attribute_option(attribute.id)? {
1815#[expect(
1816 clippy::match_same_arms,
1817 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."
1818)]
1819match (values, other_values) {
1820 (Float32(vec1), Float32(vec2)) => vec1.extend(vec2),
1821 (Sint32(vec1), Sint32(vec2)) => vec1.extend(vec2),
1822 (Uint32(vec1), Uint32(vec2)) => vec1.extend(vec2),
1823 (Float32x2(vec1), Float32x2(vec2)) => vec1.extend(vec2),
1824 (Sint32x2(vec1), Sint32x2(vec2)) => vec1.extend(vec2),
1825 (Uint32x2(vec1), Uint32x2(vec2)) => vec1.extend(vec2),
1826 (Float32x3(vec1), Float32x3(vec2)) => vec1.extend(vec2),
1827 (Sint32x3(vec1), Sint32x3(vec2)) => vec1.extend(vec2),
1828 (Uint32x3(vec1), Uint32x3(vec2)) => vec1.extend(vec2),
1829 (Sint32x4(vec1), Sint32x4(vec2)) => vec1.extend(vec2),
1830 (Uint32x4(vec1), Uint32x4(vec2)) => vec1.extend(vec2),
1831 (Float32x4(vec1), Float32x4(vec2)) => vec1.extend(vec2),
1832 (Sint16x2(vec1), Sint16x2(vec2)) => vec1.extend(vec2),
1833 (Snorm16x2(vec1), Snorm16x2(vec2)) => vec1.extend(vec2),
1834 (Uint16x2(vec1), Uint16x2(vec2)) => vec1.extend(vec2),
1835 (Unorm16x2(vec1), Unorm16x2(vec2)) => vec1.extend(vec2),
1836 (Sint16x4(vec1), Sint16x4(vec2)) => vec1.extend(vec2),
1837 (Snorm16x4(vec1), Snorm16x4(vec2)) => vec1.extend(vec2),
1838 (Uint16x4(vec1), Uint16x4(vec2)) => vec1.extend(vec2),
1839 (Unorm16x4(vec1), Unorm16x4(vec2)) => vec1.extend(vec2),
1840 (Sint8x2(vec1), Sint8x2(vec2)) => vec1.extend(vec2),
1841 (Snorm8x2(vec1), Snorm8x2(vec2)) => vec1.extend(vec2),
1842 (Uint8x2(vec1), Uint8x2(vec2)) => vec1.extend(vec2),
1843 (Unorm8x2(vec1), Unorm8x2(vec2)) => vec1.extend(vec2),
1844 (Sint8x4(vec1), Sint8x4(vec2)) => vec1.extend(vec2),
1845 (Snorm8x4(vec1), Snorm8x4(vec2)) => vec1.extend(vec2),
1846 (Uint8x4(vec1), Uint8x4(vec2)) => vec1.extend(vec2),
1847 (Unorm8x4(vec1), Unorm8x4(vec2)) => vec1.extend(vec2),
1848_ => {
1849return Err(MeshMergeError::IncompatibleVertexAttributes {
1850 self_attribute: *attribute,
1851 other_attribute: other
1852 .try_attribute_data(attribute.id)?
1853.map(|data| data.attribute),
1854 })
1855 }
1856 }
1857 }
1858 }
18591860// Extend indices of `self` with indices of `other`.
1861if let (Some(indices), Some(other_indices)) =
1862 (self.try_indices_mut_option()?, other.try_indices_option()?)
1863 {
1864indices.extend(other_indices.iter().map(|i| (i + index_offset) as u32));
1865 }
1866Ok(())
1867 }
18681869/// Transforms the vertex positions, normals, and tangents of the mesh by the given [`Transform`].
1870 ///
1871 /// `Aabb` of entities with modified mesh are not updated automatically.
1872 ///
1873 /// # Panics
1874 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1875 /// this as an error use [`Mesh::try_transformed_by`]
1876pub fn transformed_by(mut self, transform: Transform) -> Self {
1877self.transform_by(transform);
1878self1879 }
18801881/// Transforms the vertex positions, normals, and tangents of the mesh by the given [`Transform`].
1882 ///
1883 /// `Aabb` of entities with modified mesh are not updated automatically.
1884pub fn try_transformed_by(mut self, transform: Transform) -> Result<Self, MeshAccessError> {
1885self.try_transform_by(transform)?;
1886Ok(self)
1887 }
18881889/// Transforms the vertex positions, normals, and tangents of the mesh in place by the given [`Transform`].
1890 ///
1891 /// `Aabb` of entities with modified mesh are not updated automatically.
1892 ///
1893 /// # Panics
1894 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1895 /// this as an error use [`Mesh::try_transform_by`]
1896pub fn transform_by(&mut self, transform: Transform) {
1897self.try_transform_by(transform)
1898 .expect(MESH_EXTRACTED_ERROR);
1899 }
19001901/// Transforms the vertex positions, normals, and tangents of the mesh in place by the given [`Transform`].
1902 ///
1903 /// `Aabb` of entities with modified mesh are not updated automatically.
1904pub fn try_transform_by(&mut self, transform: Transform) -> Result<(), MeshAccessError> {
1905// Needed when transforming normals and tangents
1906let scale_recip = 1. / transform.scale;
1907if true {
if !(transform.scale.yzx() * transform.scale.zxy() != Vec3::ZERO) {
{
::core::panicking::panic_fmt(format_args!("mesh transform scale cannot be zero on more than one axis"));
}
};
};debug_assert!(
1908 transform.scale.yzx() * transform.scale.zxy() != Vec3::ZERO,
1909"mesh transform scale cannot be zero on more than one axis"
1910);
19111912if let Some(VertexAttributeValues::Float32x3(positions)) =
1913self.try_attribute_mut_option(Mesh::ATTRIBUTE_POSITION)?
1914{
1915// Apply scale, rotation, and translation to vertex positions
1916positions1917 .iter_mut()
1918 .for_each(|pos| *pos = transform.transform_point(Vec3::from_slice(pos)).to_array());
1919 }
19201921// No need to transform normals or tangents if rotation is near identity and scale is uniform
1922if transform.rotation.is_near_identity()
1923 && transform.scale.x == transform.scale.y
1924 && transform.scale.y == transform.scale.z
1925 {
1926return Ok(());
1927 }
19281929if let Some(VertexAttributeValues::Float32x3(normals)) =
1930self.try_attribute_mut_option(Mesh::ATTRIBUTE_NORMAL)?
1931{
1932// Transform normals, taking into account non-uniform scaling and rotation
1933normals.iter_mut().for_each(|normal| {
1934*normal = (transform.rotation
1935 * scale_normal(Vec3::from_array(*normal), scale_recip))
1936 .to_array();
1937 });
1938 }
19391940if let Some(VertexAttributeValues::Float32x4(tangents)) =
1941self.try_attribute_mut_option(Mesh::ATTRIBUTE_TANGENT)?
1942{
1943// Transform tangents, taking into account non-uniform scaling and rotation
1944tangents.iter_mut().for_each(|tangent| {
1945let handedness = tangent[3];
1946let scaled_tangent = Vec3::from_slice(tangent) * transform.scale;
1947*tangent = (transform.rotation * scaled_tangent.normalize_or_zero())
1948 .extend(handedness)
1949 .to_array();
1950 });
1951 }
19521953Ok(())
1954 }
19551956/// Translates the vertex positions of the mesh by the given [`Vec3`].
1957 ///
1958 /// `Aabb` of entities with modified mesh are not updated automatically.
1959 ///
1960 /// # Panics
1961 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1962 /// this as an error use [`Mesh::try_translated_by`]
1963pub fn translated_by(mut self, translation: Vec3) -> Self {
1964self.translate_by(translation);
1965self1966 }
19671968/// Translates the vertex positions of the mesh by the given [`Vec3`].
1969 ///
1970 /// `Aabb` of entities with modified mesh are not updated automatically.
1971pub fn try_translated_by(mut self, translation: Vec3) -> Result<Self, MeshAccessError> {
1972self.try_translate_by(translation)?;
1973Ok(self)
1974 }
19751976/// Translates the vertex positions of the mesh in place by the given [`Vec3`].
1977 ///
1978 /// `Aabb` of entities with modified mesh are not updated automatically.
1979 ///
1980 /// # Panics
1981 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
1982 /// this as an error use [`Mesh::try_translate_by`]
1983pub fn translate_by(&mut self, translation: Vec3) {
1984self.try_translate_by(translation)
1985 .expect(MESH_EXTRACTED_ERROR);
1986 }
19871988/// Translates the vertex positions of the mesh in place by the given [`Vec3`].
1989 ///
1990 /// `Aabb` of entities with modified mesh are not updated automatically.
1991pub fn try_translate_by(&mut self, translation: Vec3) -> Result<(), MeshAccessError> {
1992if translation == Vec3::ZERO {
1993return Ok(());
1994 }
19951996if let Some(VertexAttributeValues::Float32x3(positions)) =
1997self.try_attribute_mut_option(Mesh::ATTRIBUTE_POSITION)?
1998{
1999// Apply translation to vertex positions
2000positions2001 .iter_mut()
2002 .for_each(|pos| *pos = (Vec3::from_slice(pos) + translation).to_array());
2003 }
20042005Ok(())
2006 }
20072008/// Rotates the vertex positions, normals, and tangents of the mesh by the given [`Quat`].
2009 ///
2010 /// `Aabb` of entities with modified mesh are not updated automatically.
2011 ///
2012 /// # Panics
2013 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2014 /// this as an error use [`Mesh::try_rotated_by`]
2015pub fn rotated_by(mut self, rotation: Quat) -> Self {
2016self.try_rotate_by(rotation).expect(MESH_EXTRACTED_ERROR);
2017self2018 }
20192020/// Rotates the vertex positions, normals, and tangents of the mesh by the given [`Quat`].
2021 ///
2022 /// `Aabb` of entities with modified mesh are not updated automatically.
2023pub fn try_rotated_by(mut self, rotation: Quat) -> Result<Self, MeshAccessError> {
2024self.try_rotate_by(rotation)?;
2025Ok(self)
2026 }
20272028/// Rotates the vertex positions, normals, and tangents of the mesh in place by the given [`Quat`].
2029 ///
2030 /// `Aabb` of entities with modified mesh are not updated automatically.
2031 ///
2032 /// # Panics
2033 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2034 /// this as an error use [`Mesh::try_rotate_by`]
2035pub fn rotate_by(&mut self, rotation: Quat) {
2036self.try_rotate_by(rotation).expect(MESH_EXTRACTED_ERROR);
2037 }
20382039/// Rotates the vertex positions, normals, and tangents of the mesh in place by the given [`Quat`].
2040 ///
2041 /// `Aabb` of entities with modified mesh are not updated automatically.
2042pub fn try_rotate_by(&mut self, rotation: Quat) -> Result<(), MeshAccessError> {
2043if let Some(VertexAttributeValues::Float32x3(positions)) =
2044self.try_attribute_mut_option(Mesh::ATTRIBUTE_POSITION)?
2045{
2046// Apply rotation to vertex positions
2047positions2048 .iter_mut()
2049 .for_each(|pos| *pos = (rotation * Vec3::from_slice(pos)).to_array());
2050 }
20512052// No need to transform normals or tangents if rotation is near identity
2053if rotation.is_near_identity() {
2054return Ok(());
2055 }
20562057if let Some(VertexAttributeValues::Float32x3(normals)) =
2058self.try_attribute_mut_option(Mesh::ATTRIBUTE_NORMAL)?
2059{
2060// Transform normals
2061normals.iter_mut().for_each(|normal| {
2062*normal = (rotation * Vec3::from_slice(normal).normalize_or_zero()).to_array();
2063 });
2064 }
20652066if let Some(VertexAttributeValues::Float32x4(tangents)) =
2067self.try_attribute_mut_option(Mesh::ATTRIBUTE_TANGENT)?
2068{
2069// Transform tangents
2070tangents.iter_mut().for_each(|tangent| {
2071let handedness = tangent[3];
2072*tangent = (rotation * Vec3::from_slice(tangent).normalize_or_zero())
2073 .extend(handedness)
2074 .to_array();
2075 });
2076 }
20772078Ok(())
2079 }
20802081/// Scales the vertex positions, normals, and tangents of the mesh by the given [`Vec3`].
2082 ///
2083 /// `Aabb` of entities with modified mesh are not updated automatically.
2084 ///
2085 /// # Panics
2086 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2087 /// this as an error use [`Mesh::try_scaled_by`]
2088pub fn scaled_by(mut self, scale: Vec3) -> Self {
2089self.scale_by(scale);
2090self2091 }
20922093/// Scales the vertex positions, normals, and tangents of the mesh by the given [`Vec3`].
2094 ///
2095 /// `Aabb` of entities with modified mesh are not updated automatically.
2096pub fn try_scaled_by(mut self, scale: Vec3) -> Result<Self, MeshAccessError> {
2097self.try_scale_by(scale)?;
2098Ok(self)
2099 }
21002101/// Scales the vertex positions, normals, and tangents of the mesh in place by the given [`Vec3`].
2102 ///
2103 /// `Aabb` of entities with modified mesh are not updated automatically.
2104 ///
2105 /// # Panics
2106 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2107 /// this as an error use [`Mesh::try_scale_by`]
2108pub fn scale_by(&mut self, scale: Vec3) {
2109self.try_scale_by(scale).expect(MESH_EXTRACTED_ERROR);
2110 }
21112112/// Scales the vertex positions, normals, and tangents of the mesh in place by the given [`Vec3`].
2113 ///
2114 /// `Aabb` of entities with modified mesh are not updated automatically.
2115pub fn try_scale_by(&mut self, scale: Vec3) -> Result<(), MeshAccessError> {
2116// Needed when transforming normals and tangents
2117let scale_recip = 1. / scale;
2118if true {
if !(scale.yzx() * scale.zxy() != Vec3::ZERO) {
{
::core::panicking::panic_fmt(format_args!("mesh transform scale cannot be zero on more than one axis"));
}
};
};debug_assert!(
2119 scale.yzx() * scale.zxy() != Vec3::ZERO,
2120"mesh transform scale cannot be zero on more than one axis"
2121);
21222123if let Some(VertexAttributeValues::Float32x3(positions)) =
2124self.try_attribute_mut_option(Mesh::ATTRIBUTE_POSITION)?
2125{
2126// Apply scale to vertex positions
2127positions2128 .iter_mut()
2129 .for_each(|pos| *pos = (scale * Vec3::from_slice(pos)).to_array());
2130 }
21312132// No need to transform normals or tangents if scale is uniform
2133if scale.x == scale.y && scale.y == scale.z {
2134return Ok(());
2135 }
21362137if let Some(VertexAttributeValues::Float32x3(normals)) =
2138self.try_attribute_mut_option(Mesh::ATTRIBUTE_NORMAL)?
2139{
2140// Transform normals, taking into account non-uniform scaling
2141normals.iter_mut().for_each(|normal| {
2142*normal = scale_normal(Vec3::from_array(*normal), scale_recip).to_array();
2143 });
2144 }
21452146if let Some(VertexAttributeValues::Float32x4(tangents)) =
2147self.try_attribute_mut_option(Mesh::ATTRIBUTE_TANGENT)?
2148{
2149// Transform tangents, taking into account non-uniform scaling
2150tangents.iter_mut().for_each(|tangent| {
2151let handedness = tangent[3];
2152let scaled_tangent = Vec3::from_slice(tangent) * scale;
2153*tangent = scaled_tangent2154 .normalize_or_zero()
2155 .extend(handedness)
2156 .to_array();
2157 });
2158 }
21592160Ok(())
2161 }
21622163/// Normalize joint weights so they sum to 1.
2164 ///
2165 /// # Panics
2166 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2167 /// this as an error use [`Mesh::try_normalize_joint_weights`]
2168pub fn normalize_joint_weights(&mut self) {
2169self.try_normalize_joint_weights()
2170 .expect(MESH_EXTRACTED_ERROR);
2171 }
21722173/// Normalize joint weights so they sum to 1.
2174pub fn try_normalize_joint_weights(&mut self) -> Result<(), MeshAccessError> {
2175if let Some(VertexAttributeValues::Float32x4(joints)) =
2176self.try_attribute_mut_option(Self::ATTRIBUTE_JOINT_WEIGHT)?
2177{
2178for weights in joints.iter_mut() {
2179// force negative weights to zero
2180weights.iter_mut().for_each(|w| *w = w.max(0.0));
21812182let sum: f32 = weights.iter().sum();
2183if sum == 0.0 {
2184// all-zero weights are invalid
2185weights[0] = 1.0;
2186 } else {
2187let recip = sum.recip();
2188for weight in weights.iter_mut() {
2189*weight *= recip;
2190 }
2191 }
2192 }
2193 }
21942195Ok(())
2196 }
21972198/// Get a list of this Mesh's [triangles] as an iterator if possible.
2199 ///
2200 /// Returns an error if any of the following conditions are met (see [`MeshTrianglesError`]):
2201 /// * The Mesh's [primitive topology] is not `TriangleList` or `TriangleStrip`.
2202 /// * The Mesh is missing position or index data.
2203 /// * The Mesh's position data has the wrong format (not `Float32x3`).
2204 ///
2205 /// [primitive topology]: PrimitiveTopology
2206 /// [triangles]: Triangle3d
2207pub fn triangles(&self) -> Result<impl Iterator<Item = Triangle3d> + '_, MeshTrianglesError> {
2208fn indices_to_triangle<T: TryInto<usize> + Copy>(
2209 vertices: &[[f32; 3]],
2210 indices: &[T; 3],
2211 ) -> Option<Triangle3d> {
2212let vert0 = Vec3::from(*vertices.get(indices[0].try_into().ok()?)?);
2213let vert1 = Vec3::from(*vertices.get(indices[1].try_into().ok()?)?);
2214let vert2 = Vec3::from(*vertices.get(indices[2].try_into().ok()?)?);
2215Some(Triangle3d {
2216 vertices: [vert0, vert1, vert2],
2217 })
2218 }
22192220let position_data = self.try_attribute(Mesh::ATTRIBUTE_POSITION)?;
22212222let Some(vertices) = position_data.as_float3() else {
2223return Err(MeshTrianglesError::PositionsFormat);
2224 };
22252226let indices = self.try_indices()?;
22272228match self.primitive_topology {
2229 PrimitiveTopology::TriangleList => {
2230// When indices reference out-of-bounds vertex data, the triangle is omitted.
2231 // This implicitly truncates the indices to a multiple of 3.
2232let iterator = match indices {
2233 Indices::U16(vec) => FourIterators::First(
2234vec.as_chunks()
2235 .0
2236.iter()
2237 .flat_map(|indices| indices_to_triangle(vertices, indices)),
2238 ),
2239 Indices::U32(vec) => FourIterators::Second(
2240vec.as_chunks()
2241 .0
2242.iter()
2243 .flat_map(|indices| indices_to_triangle(vertices, indices)),
2244 ),
2245 };
22462247Ok(iterator)
2248 }
2249 PrimitiveTopology::TriangleStrip => {
2250// When indices reference out-of-bounds vertex data, the triangle is omitted.
2251 // If there aren't enough indices to make a triangle, then an empty vector will be
2252 // returned.
2253let iterator = match indices {
2254 Indices::U16(vec) => {
2255 FourIterators::Third(vec.array_windows().enumerate().flat_map(
2256 |(i, indices @ &[idx0, idx1, idx2])| {
2257if i % 2 == 0 {
2258indices_to_triangle(vertices, indices)
2259 } else {
2260indices_to_triangle(vertices, &[idx1, idx0, idx2])
2261 }
2262 },
2263 ))
2264 }
2265 Indices::U32(vec) => {
2266 FourIterators::Fourth(vec.array_windows().enumerate().flat_map(
2267 |(i, indices @ &[idx0, idx1, idx2])| {
2268if i % 2 == 0 {
2269indices_to_triangle(vertices, indices)
2270 } else {
2271indices_to_triangle(vertices, &[idx1, idx0, idx2])
2272 }
2273 },
2274 ))
2275 }
2276 };
22772278Ok(iterator)
2279 }
2280_ => Err(MeshTrianglesError::WrongTopology),
2281 }
2282 }
22832284/// Extracts the mesh vertex, index and morph target data for GPU upload.
2285 /// This function is called internally in render world extraction, it is
2286 /// unlikely to be useful outside of that context.
2287 ///
2288 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
2289pub fn take_gpu_data(&mut self) -> Result<Self, MeshAccessError> {
2290let attributes = self.attributes.extract()?;
2291let indices = self.indices.extract()?;
2292#[cfg(feature = "morph")]
2293let morph_targets = self.morph_targets.extract()?;
2294#[cfg(feature = "morph")]
2295let morph_target_names = self.morph_target_names.extract()?;
22962297// store the aabb extents as they cannot be computed after extraction
2298if let Some(MeshAttributeData {
2299 values: VertexAttributeValues::Float32x3(position_values),
2300 ..
2301 }) = attributes
2302 .as_ref_option()?
2303.and_then(|attrs| attrs.get(&Self::ATTRIBUTE_POSITION.id))
2304 && !position_values.is_empty()
2305 {
2306let mut iter = position_values.iter().map(|p| Vec3::from_slice(p));
2307let mut min = iter.next().unwrap();
2308let mut max = min;
2309for v in iter {
2310 min = Vec3::min(min, v);
2311 max = Vec3::max(max, v);
2312 }
2313self.final_aabb = Some(Aabb3d::from_min_max(min, max));
2314 }
23152316Ok(Self {
2317attributes,
2318indices,
2319#[cfg(feature = "morph")]
2320morph_targets,
2321#[cfg(feature = "morph")]
2322morph_target_names,
2323 ..self.clone()
2324 })
2325 }
23262327/// Get this mesh's [`SkinnedMeshBounds`].
2328pub fn skinned_mesh_bounds(&self) -> Option<&SkinnedMeshBounds> {
2329self.skinned_mesh_bounds.as_ref()
2330 }
23312332/// Set this mesh's [`SkinnedMeshBounds`].
2333pub fn set_skinned_mesh_bounds(&mut self, skinned_mesh_bounds: Option<SkinnedMeshBounds>) {
2334self.skinned_mesh_bounds = skinned_mesh_bounds;
2335 }
23362337/// Consumes the mesh and returns a mesh with the given [`SkinnedMeshBounds`].
2338pub fn with_skinned_mesh_bounds(
2339mut self,
2340 skinned_mesh_bounds: Option<SkinnedMeshBounds>,
2341 ) -> Self {
2342self.set_skinned_mesh_bounds(skinned_mesh_bounds);
2343self2344 }
23452346/// Generate [`SkinnedMeshBounds`] for this mesh.
2347pub fn generate_skinned_mesh_bounds(&mut self) -> Result<(), SkinnedMeshBoundsError> {
2348self.skinned_mesh_bounds = Some(SkinnedMeshBounds::from_mesh(self)?);
2349Ok(())
2350 }
23512352/// Consumes the mesh and returns a mesh with generated [`SkinnedMeshBounds`].
2353pub fn with_generated_skinned_mesh_bounds(mut self) -> Result<Self, SkinnedMeshBoundsError> {
2354self.generate_skinned_mesh_bounds()?;
2355Ok(self)
2356 }
2357}
23582359#[cfg(feature = "morph")]
2360impl Mesh {
2361/// Whether this mesh has morph targets.
2362 ///
2363 /// # Panics
2364 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2365 /// this as an error use [`Mesh::try_has_morph_targets`]
2366pub fn has_morph_targets(&self) -> bool {
2367self.try_has_morph_targets().expect(MESH_EXTRACTED_ERROR)
2368 }
23692370/// Whether this mesh has morph targets.
2371pub fn try_has_morph_targets(&self) -> Result<bool, MeshAccessError> {
2372Ok(self.morph_targets.as_ref_option()?.is_some())
2373 }
23742375/// Set the [morph target] displacements for this mesh.
2376 ///
2377 /// [morph target]: https://en.wikipedia.org/wiki/Morph_target_animation
2378 ///
2379 /// # Panics
2380 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2381 /// this as an error use [`Mesh::try_set_morph_targets`]
2382#[cfg(feature = "morph")]
2383pub fn set_morph_targets(&mut self, morph_targets: Vec<MorphAttributes>) {
2384self.try_set_morph_targets(morph_targets)
2385 .expect(MESH_EXTRACTED_ERROR);
2386 }
23872388/// Set the [morph target] displacements for this mesh.
2389 ///
2390 /// [morph targets]: https://en.wikipedia.org/wiki/Morph_target_animation
2391#[cfg(feature = "morph")]
2392pub fn try_set_morph_targets(
2393&mut self,
2394 morph_targets: Vec<MorphAttributes>,
2395 ) -> Result<(), MeshAccessError> {
2396self.morph_targets.replace(Some(morph_targets))?;
2397Ok(())
2398 }
23992400/// Retrieve the morph target displacements for this mesh, or None if there
2401 /// are no morph targets.
2402 ///
2403 /// # Panics
2404 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2405 /// this as an error use [`Mesh::try_morph_targets`]
2406#[cfg(feature = "morph")]
2407pub fn morph_targets(&self) -> Option<&Vec<MorphAttributes>> {
2408self.morph_targets
2409 .as_ref_option()
2410 .expect(MESH_EXTRACTED_ERROR)
2411 }
24122413/// Retrieve the morph displacements for this mesh, or None if there are no
2414 /// morph targets.
2415 ///
2416 /// Returns an error if the mesh data has been extracted to `RenderWorld`or
2417 /// if the morph targets do not exist.
2418#[cfg(feature = "morph")]
2419pub fn try_morph_targets(&self) -> Result<&Vec<MorphAttributes>, MeshAccessError> {
2420self.morph_targets.as_ref()
2421 }
24222423/// Consumes the mesh and returns a mesh with the given [morph target]
2424 /// displacements.
2425 ///
2426 /// (Alternatively, you can use [`Mesh::set_morph_targets`] to mutate an existing mesh in-place)
2427 ///
2428 /// [morph target]: https://en.wikipedia.org/wiki/Morph_target_animation
2429 ///
2430 /// # Panics
2431 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2432 /// this as an error use [`Mesh::try_with_morph_targets`]
2433#[must_use]
2434 #[cfg(feature = "morph")]
2435pub fn with_morph_targets(mut self, morph_targets: Vec<MorphAttributes>) -> Self {
2436self.set_morph_targets(morph_targets);
2437self2438 }
24392440/// Consumes the mesh and returns a mesh with the given [morph targets].
2441 ///
2442 /// (Alternatively, you can use [`Mesh::set_morph_targets`] to mutate an existing mesh in-place)
2443 ///
2444 /// [morph targets]: https://en.wikipedia.org/wiki/Morph_target_animation
2445 ///
2446 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
2447#[cfg(feature = "morph")]
2448pub fn try_with_morph_targets(
2449mut self,
2450 morph_targets: Vec<MorphAttributes>,
2451 ) -> Result<Self, MeshAccessError> {
2452self.try_set_morph_targets(morph_targets)?;
2453Ok(self)
2454 }
24552456/// Sets the names of each morph target. This should correspond to the order of the morph targets in `set_morph_targets`.
2457 ///
2458 /// # Panics
2459 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2460 /// this as an error use [`Mesh::try_set_morph_target_names`]
2461pub fn set_morph_target_names(&mut self, names: Vec<String>) {
2462self.try_set_morph_target_names(names)
2463 .expect(MESH_EXTRACTED_ERROR);
2464 }
24652466/// Sets the names of each morph target. This should correspond to the order of the morph targets in `set_morph_targets`.
2467 ///
2468 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
2469pub fn try_set_morph_target_names(
2470&mut self,
2471 names: Vec<String>,
2472 ) -> Result<(), MeshAccessError> {
2473self.morph_target_names.replace(Some(names))?;
2474Ok(())
2475 }
24762477/// Consumes the mesh and returns a mesh with morph target names.
2478 /// Names should correspond to the order of the morph targets in `set_morph_targets`.
2479 ///
2480 /// (Alternatively, you can use [`Mesh::set_morph_target_names`] to mutate an existing mesh in-place)
2481 ///
2482 /// # Panics
2483 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2484 /// this as an error use [`Mesh::try_set_morph_target_names`]
2485#[must_use]
2486pub fn with_morph_target_names(self, names: Vec<String>) -> Self {
2487self.try_with_morph_target_names(names)
2488 .expect(MESH_EXTRACTED_ERROR)
2489 }
24902491/// Consumes the mesh and returns a mesh with morph target names.
2492 /// Names should correspond to the order of the morph targets in `set_morph_targets`.
2493 ///
2494 /// (Alternatively, you can use [`Mesh::set_morph_target_names`] to mutate an existing mesh in-place)
2495 ///
2496 /// Returns an error if the mesh data has been extracted to `RenderWorld`.
2497pub fn try_with_morph_target_names(
2498mut self,
2499 names: Vec<String>,
2500 ) -> Result<Self, MeshAccessError> {
2501self.try_set_morph_target_names(names)?;
2502Ok(self)
2503 }
25042505/// Gets a list of all morph target names, if they exist.
2506 ///
2507 /// # Panics
2508 /// Panics when the mesh data has already been extracted to `RenderWorld`. To handle
2509 /// this as an error use [`Mesh::try_morph_target_names`]
2510pub fn morph_target_names(&self) -> Option<&[String]> {
2511self.try_morph_target_names().expect(MESH_EXTRACTED_ERROR)
2512 }
25132514/// Gets a list of all morph target names, if they exist.
2515 ///
2516 /// Returns an error if the mesh data has been extracted to `RenderWorld`or
2517 /// if the morph targets do not exist.
2518pub fn try_morph_target_names(&self) -> Result<Option<&[String]>, MeshAccessError> {
2519Ok(self
2520.morph_target_names
2521 .as_ref_option()?
2522.map(core::ops::Deref::deref))
2523 }
2524}
25252526/// An enum to define which UV attribute to use for a texture.
2527///
2528/// It only supports two UV attributes, [`Mesh::ATTRIBUTE_UV_0`] and
2529/// [`Mesh::ATTRIBUTE_UV_1`].
2530/// The default is [`UvChannel::Uv0`].
2531#[derive(const _: () =
{
impl bevy_reflect::GetTypeRegistration for UvChannel where {
fn get_type_registration() -> bevy_reflect::TypeRegistration {
let mut registration =
bevy_reflect::TypeRegistration::of::<Self>();
registration.insert::<bevy_reflect::ReflectFromPtr>(bevy_reflect::FromType::<Self>::from_type());
registration.insert::<bevy_reflect::ReflectFromReflect>(bevy_reflect::FromType::<Self>::from_type());
registration.register_type_data::<ReflectDefault, Self>();
registration
}
#[inline(never)]
fn register_type_dependencies(registry:
&mut bevy_reflect::TypeRegistry) {}
}
impl bevy_reflect::Typed for UvChannel where {
#[inline]
fn type_info() -> &'static bevy_reflect::TypeInfo {
static CELL: bevy_reflect::utility::NonGenericTypeInfoCell =
bevy_reflect::utility::NonGenericTypeInfoCell::new();
CELL.get_or_set(||
{
bevy_reflect::TypeInfo::Enum(bevy_reflect::enums::EnumInfo::new::<Self>(&[bevy_reflect::enums::VariantInfo::Unit(bevy_reflect::enums::UnitVariantInfo::new("Uv0")),
bevy_reflect::enums::VariantInfo::Unit(bevy_reflect::enums::UnitVariantInfo::new("Uv1"))]))
})
}
}
#[allow(deprecated, reason =
"derives on a deprecated type shouldn't be considered a usage")]
impl bevy_reflect::TypePath for UvChannel where {
fn type_path() -> &'static str { "bevy_mesh::mesh::UvChannel" }
fn short_type_path() -> &'static str { "UvChannel" }
fn type_ident() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("UvChannel")
}
fn crate_name() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("bevy_mesh::mesh".split(':').next().unwrap())
}
fn module_path() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("bevy_mesh::mesh")
}
}
impl bevy_reflect::Reflect for UvChannel where {
#[inline]
fn into_any(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn ::core::any::Any> {
self
}
#[inline]
fn as_any(&self) -> &dyn ::core::any::Any { self }
#[inline]
fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any { self }
#[inline]
fn into_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect> {
self
}
#[inline]
fn as_reflect(&self) -> &dyn bevy_reflect::Reflect { self }
#[inline]
fn as_reflect_mut(&mut self) -> &mut dyn bevy_reflect::Reflect {
self
}
#[inline]
fn set(&mut self,
value:
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>)
->
::core::result::Result<(),
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>> {
*self = <dyn bevy_reflect::Reflect>::take(value)?;
::core::result::Result::Ok(())
}
}
#[allow(non_upper_case_globals)]
const _: () =
{
static __INVENTORY: ::inventory::Node =
::inventory::Node {
value: &{
bevy_reflect::__macro_exports::auto_register::AutomaticReflectRegistrations(<UvChannel
as
bevy_reflect::__macro_exports::auto_register::RegisterForReflection>::__register)
},
next: ::inventory::__private::UnsafeCell::new(::inventory::__private::Option::None),
};
#[link_section = ".text.startup"]
unsafe extern "C" fn __ctor() {
unsafe {
::inventory::ErasedNode::submit(__INVENTORY.value,
&__INVENTORY)
}
}
#[used]
#[link_section = ".init_array"]
static __CTOR: unsafe extern "C" fn() = __ctor;
};
impl bevy_reflect::enums::Enum for UvChannel where {
fn field(&self, __name_param: &str)
-> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
match self { _ => ::core::option::Option::None, }
}
fn field_at(&self, __index_param: usize)
-> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
match self { _ => ::core::option::Option::None, }
}
fn field_mut(&mut self, __name_param: &str)
->
::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
match self { _ => ::core::option::Option::None, }
}
fn field_at_mut(&mut self, __index_param: usize)
->
::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
match self { _ => ::core::option::Option::None, }
}
fn index_of(&self, __name_param: &str)
-> ::core::option::Option<usize> {
match self { _ => ::core::option::Option::None, }
}
fn name_at(&self, __index_param: usize)
-> ::core::option::Option<&str> {
match self { _ => ::core::option::Option::None, }
}
fn iter_fields(&self) -> bevy_reflect::enums::VariantFieldIter {
bevy_reflect::enums::VariantFieldIter::new(self)
}
#[inline]
fn field_len(&self) -> usize {
match self {
UvChannel::Uv0 { .. } => 0usize,
UvChannel::Uv1 { .. } => 0usize,
_ => 0,
}
}
#[inline]
fn variant_name(&self) -> &str {
match self {
UvChannel::Uv0 { .. } => "Uv0",
UvChannel::Uv1 { .. } => "Uv1",
_ =>
::core::panicking::panic("internal error: entered unreachable code"),
}
}
#[inline]
fn variant_index(&self) -> usize {
match self {
UvChannel::Uv0 { .. } => 0usize,
UvChannel::Uv1 { .. } => 1usize,
_ =>
::core::panicking::panic("internal error: entered unreachable code"),
}
}
#[inline]
fn variant_type(&self) -> bevy_reflect::enums::VariantType {
match self {
UvChannel::Uv0 { .. } =>
bevy_reflect::enums::VariantType::Unit,
UvChannel::Uv1 { .. } =>
bevy_reflect::enums::VariantType::Unit,
_ =>
::core::panicking::panic("internal error: entered unreachable code"),
}
}
fn to_dynamic_enum(&self) -> bevy_reflect::enums::DynamicEnum {
bevy_reflect::enums::DynamicEnum::from_ref::<Self>(self)
}
}
impl bevy_reflect::PartialReflect for UvChannel where {
#[inline]
fn get_represented_type_info(&self)
-> ::core::option::Option<&'static bevy_reflect::TypeInfo> {
::core::option::Option::Some(<Self as
bevy_reflect::Typed>::type_info())
}
#[inline]
fn try_apply(&mut self,
__value_param: &dyn bevy_reflect::PartialReflect)
-> ::core::result::Result<(), bevy_reflect::ApplyError> {
if let bevy_reflect::ReflectRef::Enum(__value_param) =
bevy_reflect::PartialReflect::reflect_ref(__value_param) {
if bevy_reflect::enums::Enum::variant_name(self) ==
bevy_reflect::enums::Enum::variant_name(__value_param) {
match bevy_reflect::enums::Enum::variant_type(__value_param)
{
bevy_reflect::enums::VariantType::Struct => {
for field in
bevy_reflect::enums::Enum::iter_fields(__value_param) {
let name = field.name().unwrap();
if let ::core::option::Option::Some(v) =
bevy_reflect::enums::Enum::field_mut(self, name) {
bevy_reflect::PartialReflect::try_apply(v, field.value())?;
}
}
}
bevy_reflect::enums::VariantType::Tuple => {
for (index, field) in
::core::iter::Iterator::enumerate(bevy_reflect::enums::Enum::iter_fields(__value_param))
{
if let ::core::option::Option::Some(v) =
bevy_reflect::enums::Enum::field_at_mut(self, index) {
bevy_reflect::PartialReflect::try_apply(v, field.value())?;
}
}
}
_ => {}
}
} else {
match bevy_reflect::enums::Enum::variant_name(__value_param)
{
"Uv0" => { *self = UvChannel::Uv0 {} }
"Uv1" => { *self = UvChannel::Uv1 {} }
name => {
return ::core::result::Result::Err(bevy_reflect::ApplyError::UnknownVariant {
enum_name: ::core::convert::Into::into(bevy_reflect::DynamicTypePath::reflect_type_path(self)),
variant_name: ::core::convert::Into::into(name),
});
}
}
}
} else {
return ::core::result::Result::Err(bevy_reflect::ApplyError::MismatchedKinds {
from_kind: bevy_reflect::PartialReflect::reflect_kind(__value_param),
to_kind: bevy_reflect::ReflectKind::Enum,
});
}
::core::result::Result::Ok(())
}
fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
bevy_reflect::ReflectKind::Enum
}
fn reflect_ref(&self) -> bevy_reflect::ReflectRef {
bevy_reflect::ReflectRef::Enum(self)
}
fn reflect_mut(&mut self) -> bevy_reflect::ReflectMut {
bevy_reflect::ReflectMut::Enum(self)
}
fn reflect_owned(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
-> bevy_reflect::ReflectOwned {
bevy_reflect::ReflectOwned::Enum(self)
}
#[inline]
fn try_into_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect>> {
::core::result::Result::Ok(self)
}
#[inline]
fn try_as_reflect(&self)
-> ::core::option::Option<&dyn bevy_reflect::Reflect> {
::core::option::Option::Some(self)
}
#[inline]
fn try_as_reflect_mut(&mut self)
-> ::core::option::Option<&mut dyn bevy_reflect::Reflect> {
::core::option::Option::Some(self)
}
#[inline]
fn into_partial_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect> {
self
}
#[inline]
fn as_partial_reflect(&self)
-> &dyn bevy_reflect::PartialReflect {
self
}
#[inline]
fn as_partial_reflect_mut(&mut self)
-> &mut dyn bevy_reflect::PartialReflect {
self
}
fn reflect_hash(&self) -> ::core::option::Option<u64> {
(bevy_reflect::enums::enum_hash)(self)
}
fn reflect_partial_eq(&self,
value: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<bool> {
let value =
<dyn bevy_reflect::PartialReflect>::try_downcast_ref::<Self>(value);
if let ::core::option::Option::Some(value) = value {
::core::option::Option::Some(::core::cmp::PartialEq::eq(self,
value))
} else { ::core::option::Option::Some(false) }
}
fn reflect_partial_cmp(&self,
value: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<::core::cmp::Ordering> {
(bevy_reflect::enums::enum_partial_cmp)(self, value)
}
fn debug(&self, f: &mut ::core::fmt::Formatter<'_>)
-> ::core::fmt::Result {
::core::fmt::Debug::fmt(self, f)
}
#[inline]
fn reflect_clone(&self)
->
::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
bevy_reflect::ReflectCloneError> {
::core::result::Result::Ok(bevy_reflect::__macro_exports::alloc_utils::Box::new(::core::clone::Clone::clone(self)))
}
}
impl bevy_reflect::FromReflect for UvChannel where {
fn from_reflect(__param0: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<Self> {
if let bevy_reflect::ReflectRef::Enum(__param0) =
bevy_reflect::PartialReflect::reflect_ref(__param0) {
match bevy_reflect::enums::Enum::variant_name(__param0) {
"Uv0" => ::core::option::Option::Some(UvChannel::Uv0 {}),
"Uv1" => ::core::option::Option::Some(UvChannel::Uv1 {}),
name => ::core::option::Option::None,
}
} else { ::core::option::Option::None }
}
}
};Reflect, #[automatically_derived]
impl ::core::default::Default for UvChannel {
#[inline]
fn default() -> UvChannel { Self::Uv0 }
}Default, #[automatically_derived]
impl ::core::fmt::Debug for UvChannel {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self { UvChannel::Uv0 => "Uv0", UvChannel::Uv1 => "Uv1", })
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for UvChannel {
#[inline]
fn clone(&self) -> UvChannel {
match self {
UvChannel::Uv0 => UvChannel::Uv0,
UvChannel::Uv1 => UvChannel::Uv1,
}
}
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for UvChannel {
#[inline]
fn eq(&self, other: &UvChannel) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for UvChannel {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {}
}Eq)]
2532#[reflect(Default, Debug, Clone, PartialEq)]
2533pub enum UvChannel {
2534#[default]
2535Uv0,
2536 Uv1,
2537}
25382539/// Correctly scales and renormalizes an already normalized `normal` by the scale determined by its reciprocal `scale_recip`
2540pub(crate) fn scale_normal(normal: Vec3, scale_recip: Vec3) -> Vec3 {
2541// This is basically just `normal * scale_recip` but with the added rule that `0. * anything == 0.`
2542 // This is necessary because components of `scale_recip` may be infinities, which do not multiply to zero
2543let n = Vec3::select(normal.cmpeq(Vec3::ZERO), Vec3::ZERO, normal * scale_recip);
25442545// If n is finite, no component of `scale_recip` was infinite or the normal was perpendicular to the scale
2546 // else the scale had at least one zero-component and the normal needs to point along the direction of that component
2547if n.is_finite() {
2548n.normalize_or_zero()
2549 } else {
2550Vec3::select(n.abs().cmpeq(Vec3::INFINITY), n.signum(), Vec3::ZERO).normalize()
2551 }
2552}
25532554impl core::ops::Mul<Mesh> for Transform {
2555type Output = Mesh;
25562557fn mul(self, rhs: Mesh) -> Self::Output {
2558rhs.transformed_by(self)
2559 }
2560}
25612562/// A version of [`Mesh`] suitable for serializing for short-term transfer.
2563///
2564/// [`Mesh`] does not implement [`Serialize`] / [`Deserialize`] because it is made with the renderer in mind.
2565/// It is not a general-purpose mesh implementation, and its internals are subject to frequent change.
2566/// As such, storing a [`Mesh`] on disk is highly discouraged.
2567///
2568/// But there are still some valid use cases for serializing a [`Mesh`], namely transferring meshes between processes.
2569/// To support this, you can create a [`SerializedMesh`] from a [`Mesh`] with [`SerializedMesh::from_mesh`],
2570/// and then deserialize it with [`SerializedMesh::deserialize`]. The caveats are:
2571/// - The mesh representation is not valid across different versions of Bevy.
2572/// - This conversion is lossy. Only the following information is preserved:
2573/// - Primitive topology
2574/// - Vertex attributes
2575/// - Indices
2576/// - Custom attributes that were not specified with [`MeshDeserializer::add_custom_vertex_attribute`] will be ignored while deserializing.
2577#[cfg(feature = "serialize")]
2578#[derive(#[automatically_derived]
impl ::core::fmt::Debug for SerializedMesh {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field3_finish(f,
"SerializedMesh", "primitive_topology", &self.primitive_topology,
"attributes", &self.attributes, "indices", &&self.indices)
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for SerializedMesh {
#[inline]
fn clone(&self) -> SerializedMesh {
SerializedMesh {
primitive_topology: ::core::clone::Clone::clone(&self.primitive_topology),
attributes: ::core::clone::Clone::clone(&self.attributes),
indices: ::core::clone::Clone::clone(&self.indices),
}
}
}Clone, #[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
{
#[allow(unused_extern_crates, clippy :: useless_attribute)]
extern crate serde as _serde;
;
#[automatically_derived]
impl _serde::Serialize for SerializedMesh {
fn serialize<__S>(&self, __serializer: __S)
-> _serde::__private228::Result<__S::Ok, __S::Error> where
__S: _serde::Serializer {
let mut __serde_state =
_serde::Serializer::serialize_struct(__serializer,
"SerializedMesh", false as usize + 1 + 1 + 1)?;
_serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
"primitive_topology", &self.primitive_topology)?;
_serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
"attributes", &self.attributes)?;
_serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
"indices", &self.indices)?;
_serde::ser::SerializeStruct::end(__serde_state)
}
}
};Serialize, #[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
{
#[allow(unused_extern_crates, clippy :: useless_attribute)]
extern crate serde as _serde;
;
#[automatically_derived]
impl<'de> _serde::Deserialize<'de> for SerializedMesh {
fn deserialize<__D>(__deserializer: __D)
-> _serde::__private228::Result<Self, __D::Error> where
__D: _serde::Deserializer<'de> {
#[allow(non_camel_case_types)]
#[doc(hidden)]
enum __Field { __field0, __field1, __field2, __ignore, }
#[doc(hidden)]
struct __FieldVisitor;
#[automatically_derived]
impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
type Value = __Field;
fn expecting(&self,
__formatter: &mut _serde::__private228::Formatter)
-> _serde::__private228::fmt::Result {
_serde::__private228::Formatter::write_str(__formatter,
"field identifier")
}
fn visit_u64<__E>(self, __value: u64)
-> _serde::__private228::Result<Self::Value, __E> where
__E: _serde::de::Error {
match __value {
0u64 => _serde::__private228::Ok(__Field::__field0),
1u64 => _serde::__private228::Ok(__Field::__field1),
2u64 => _serde::__private228::Ok(__Field::__field2),
_ => _serde::__private228::Ok(__Field::__ignore),
}
}
fn visit_str<__E>(self, __value: &str)
-> _serde::__private228::Result<Self::Value, __E> where
__E: _serde::de::Error {
match __value {
"primitive_topology" =>
_serde::__private228::Ok(__Field::__field0),
"attributes" => _serde::__private228::Ok(__Field::__field1),
"indices" => _serde::__private228::Ok(__Field::__field2),
_ => { _serde::__private228::Ok(__Field::__ignore) }
}
}
fn visit_bytes<__E>(self, __value: &[u8])
-> _serde::__private228::Result<Self::Value, __E> where
__E: _serde::de::Error {
match __value {
b"primitive_topology" =>
_serde::__private228::Ok(__Field::__field0),
b"attributes" =>
_serde::__private228::Ok(__Field::__field1),
b"indices" => _serde::__private228::Ok(__Field::__field2),
_ => { _serde::__private228::Ok(__Field::__ignore) }
}
}
}
#[automatically_derived]
impl<'de> _serde::Deserialize<'de> for __Field {
#[inline]
fn deserialize<__D>(__deserializer: __D)
-> _serde::__private228::Result<Self, __D::Error> where
__D: _serde::Deserializer<'de> {
_serde::Deserializer::deserialize_identifier(__deserializer,
__FieldVisitor)
}
}
#[doc(hidden)]
struct __Visitor<'de> {
marker: _serde::__private228::PhantomData<SerializedMesh>,
lifetime: _serde::__private228::PhantomData<&'de ()>,
}
#[automatically_derived]
impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
type Value = SerializedMesh;
fn expecting(&self,
__formatter: &mut _serde::__private228::Formatter)
-> _serde::__private228::fmt::Result {
_serde::__private228::Formatter::write_str(__formatter,
"struct SerializedMesh")
}
#[inline]
fn visit_seq<__A>(self, mut __seq: __A)
-> _serde::__private228::Result<Self::Value, __A::Error>
where __A: _serde::de::SeqAccess<'de> {
let __field0 =
match _serde::de::SeqAccess::next_element::<PrimitiveTopology>(&mut __seq)?
{
_serde::__private228::Some(__value) => __value,
_serde::__private228::None =>
return _serde::__private228::Err(_serde::de::Error::invalid_length(0usize,
&"struct SerializedMesh with 3 elements")),
};
let __field1 =
match _serde::de::SeqAccess::next_element::<Vec<(MeshVertexAttributeId,
SerializedMeshAttributeData)>>(&mut __seq)? {
_serde::__private228::Some(__value) => __value,
_serde::__private228::None =>
return _serde::__private228::Err(_serde::de::Error::invalid_length(1usize,
&"struct SerializedMesh with 3 elements")),
};
let __field2 =
match _serde::de::SeqAccess::next_element::<Option<Indices>>(&mut __seq)?
{
_serde::__private228::Some(__value) => __value,
_serde::__private228::None =>
return _serde::__private228::Err(_serde::de::Error::invalid_length(2usize,
&"struct SerializedMesh with 3 elements")),
};
_serde::__private228::Ok(SerializedMesh {
primitive_topology: __field0,
attributes: __field1,
indices: __field2,
})
}
#[inline]
fn visit_map<__A>(self, mut __map: __A)
-> _serde::__private228::Result<Self::Value, __A::Error>
where __A: _serde::de::MapAccess<'de> {
let mut __field0:
_serde::__private228::Option<PrimitiveTopology> =
_serde::__private228::None;
let mut __field1:
_serde::__private228::Option<Vec<(MeshVertexAttributeId,
SerializedMeshAttributeData)>> = _serde::__private228::None;
let mut __field2:
_serde::__private228::Option<Option<Indices>> =
_serde::__private228::None;
while let _serde::__private228::Some(__key) =
_serde::de::MapAccess::next_key::<__Field>(&mut __map)? {
match __key {
__Field::__field0 => {
if _serde::__private228::Option::is_some(&__field0) {
return _serde::__private228::Err(<__A::Error as
_serde::de::Error>::duplicate_field("primitive_topology"));
}
__field0 =
_serde::__private228::Some(_serde::de::MapAccess::next_value::<PrimitiveTopology>(&mut __map)?);
}
__Field::__field1 => {
if _serde::__private228::Option::is_some(&__field1) {
return _serde::__private228::Err(<__A::Error as
_serde::de::Error>::duplicate_field("attributes"));
}
__field1 =
_serde::__private228::Some(_serde::de::MapAccess::next_value::<Vec<(MeshVertexAttributeId,
SerializedMeshAttributeData)>>(&mut __map)?);
}
__Field::__field2 => {
if _serde::__private228::Option::is_some(&__field2) {
return _serde::__private228::Err(<__A::Error as
_serde::de::Error>::duplicate_field("indices"));
}
__field2 =
_serde::__private228::Some(_serde::de::MapAccess::next_value::<Option<Indices>>(&mut __map)?);
}
_ => {
let _ =
_serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?;
}
}
}
let __field0 =
match __field0 {
_serde::__private228::Some(__field0) => __field0,
_serde::__private228::None =>
_serde::__private228::de::missing_field("primitive_topology")?,
};
let __field1 =
match __field1 {
_serde::__private228::Some(__field1) => __field1,
_serde::__private228::None =>
_serde::__private228::de::missing_field("attributes")?,
};
let __field2 =
match __field2 {
_serde::__private228::Some(__field2) => __field2,
_serde::__private228::None =>
_serde::__private228::de::missing_field("indices")?,
};
_serde::__private228::Ok(SerializedMesh {
primitive_topology: __field0,
attributes: __field1,
indices: __field2,
})
}
}
#[doc(hidden)]
const FIELDS: &'static [&'static str] =
&["primitive_topology", "attributes", "indices"];
_serde::Deserializer::deserialize_struct(__deserializer,
"SerializedMesh", FIELDS,
__Visitor {
marker: _serde::__private228::PhantomData::<SerializedMesh>,
lifetime: _serde::__private228::PhantomData,
})
}
}
};Deserialize)]
2579pub struct SerializedMesh {
2580 primitive_topology: PrimitiveTopology,
2581 attributes: Vec<(MeshVertexAttributeId, SerializedMeshAttributeData)>,
2582 indices: Option<Indices>,
2583}
25842585#[cfg(feature = "serialize")]
2586impl SerializedMesh {
2587/// Create a [`SerializedMesh`] from a [`Mesh`]. See the documentation for [`SerializedMesh`] for caveats.
2588pub fn from_mesh(mut mesh: Mesh) -> Self {
2589Self {
2590 primitive_topology: mesh.primitive_topology,
2591 attributes: mesh2592 .attributes
2593 .replace(None)
2594 .expect(MESH_EXTRACTED_ERROR)
2595 .unwrap()
2596 .into_iter()
2597 .map(|(id, data)| {
2598 (
2599id,
2600SerializedMeshAttributeData::from_mesh_attribute_data(data),
2601 )
2602 })
2603 .collect(),
2604 indices: mesh.indices.replace(None).expect(MESH_EXTRACTED_ERROR),
2605 }
2606 }
26072608/// Create a [`Mesh`] from a [`SerializedMesh`]. See the documentation for [`SerializedMesh`] for caveats.
2609 ///
2610 /// Use [`MeshDeserializer`] if you need to pass extra options to the deserialization process, such as specifying custom vertex attributes.
2611pub fn into_mesh(self) -> Mesh {
2612MeshDeserializer::default().deserialize(self)
2613 }
2614}
26152616/// Use to specify extra options when deserializing a [`SerializedMesh`] into a [`Mesh`].
2617#[cfg(feature = "serialize")]
2618pub struct MeshDeserializer {
2619 custom_vertex_attributes: HashMap<Box<str>, MeshVertexAttribute>,
2620}
26212622#[cfg(feature = "serialize")]
2623impl Defaultfor MeshDeserializer {
2624fn default() -> Self {
2625// Written like this so that the compiler can validate that we use all the built-in attributes.
2626 // If you just added a new attribute and got a compile error, please add it to this list :)
2627const BUILTINS: [MeshVertexAttribute; Mesh::FIRST_AVAILABLE_CUSTOM_ATTRIBUTE as usize] = [
2628Mesh::ATTRIBUTE_POSITION,
2629Mesh::ATTRIBUTE_NORMAL,
2630Mesh::ATTRIBUTE_UV_0,
2631Mesh::ATTRIBUTE_UV_1,
2632Mesh::ATTRIBUTE_TANGENT,
2633Mesh::ATTRIBUTE_COLOR,
2634Mesh::ATTRIBUTE_JOINT_WEIGHT,
2635Mesh::ATTRIBUTE_JOINT_INDEX,
2636 ];
2637Self {
2638 custom_vertex_attributes: BUILTINS2639 .into_iter()
2640 .map(|attribute| (attribute.name.into(), attribute))
2641 .collect(),
2642 }
2643 }
2644}
26452646#[cfg(feature = "serialize")]
2647impl MeshDeserializer {
2648/// Create a new [`MeshDeserializer`].
2649pub fn new() -> Self {
2650Self::default()
2651 }
26522653/// Register a custom vertex attribute to the deserializer. Custom vertex attributes that were not added with this method will be ignored while deserializing.
2654pub fn add_custom_vertex_attribute(
2655&mut self,
2656 name: &str,
2657 attribute: MeshVertexAttribute,
2658 ) -> &mut Self {
2659self.custom_vertex_attributes.insert(name.into(), attribute);
2660self2661 }
26622663/// Deserialize a [`SerializedMesh`] into a [`Mesh`].
2664 ///
2665 /// See the documentation for [`SerializedMesh`] for caveats.
2666pub fn deserialize(&self, serialized_mesh: SerializedMesh) -> Mesh {
2667Mesh {
2668 attributes: MeshExtractableData::Data(
2669serialized_mesh2670 .attributes
2671 .into_iter()
2672 .filter_map(|(id, data)| {
2673let attribute = data.attribute.clone();
2674let Some(data) =
2675data.try_into_mesh_attribute_data(&self.custom_vertex_attributes)
2676else {
2677{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event src/mesh.rs:2677",
"bevy_mesh::mesh", ::tracing::Level::WARN,
::tracing_core::__macro_support::Option::Some("src/mesh.rs"),
::tracing_core::__macro_support::Option::Some(2677u32),
::tracing_core::__macro_support::Option::Some("bevy_mesh::mesh"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::WARN <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::WARN <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("Deserialized mesh contains custom vertex attribute {0:?} that was not specified with `MeshDeserializer::add_custom_vertex_attribute`. Ignoring.",
attribute) as &dyn ::tracing::field::Value))])
});
} else { ; }
};warn!(
2678"Deserialized mesh contains custom vertex attribute {attribute:?} that \
2679 was not specified with `MeshDeserializer::add_custom_vertex_attribute`. Ignoring."
2680);
2681return None;
2682 };
2683Some((id, data))
2684 })
2685 .collect()),
2686 indices: serialized_mesh.indices.into(),
2687 ..Mesh::new(serialized_mesh.primitive_topology, RenderAssetUsages::default())
2688 }
2689 }
2690}
26912692/// Error that can occur when calling [`Mesh::merge_duplicate_vertices`]
2693#[derive(fn from(source: MeshAccessError) -> Self {
MeshMergeDuplicateVerticesError::MeshAccessError { 0: source }
}Error, #[automatically_derived]
impl ::core::fmt::Debug for MeshMergeDuplicateVerticesError {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
MeshMergeDuplicateVerticesError::IndicesAlreadySet =>
::core::fmt::Formatter::write_str(f, "IndicesAlreadySet"),
MeshMergeDuplicateVerticesError::MeshAccessError(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"MeshAccessError", &__self_0),
}
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for MeshMergeDuplicateVerticesError {
#[inline]
fn clone(&self) -> MeshMergeDuplicateVerticesError {
match self {
MeshMergeDuplicateVerticesError::IndicesAlreadySet =>
MeshMergeDuplicateVerticesError::IndicesAlreadySet,
MeshMergeDuplicateVerticesError::MeshAccessError(__self_0) =>
MeshMergeDuplicateVerticesError::MeshAccessError(::core::clone::Clone::clone(__self_0)),
}
}
}Clone)]
2694pub enum MeshMergeDuplicateVerticesError {
2695#[error("Index attribute already set.")]
2696IndicesAlreadySet,
2697#[error("Mesh access error: {0}")]
2698MeshAccessError(#[from] MeshAccessError),
2699}
27002701/// Error that can occur when calling [`Mesh::merge`].
2702#[derive(fn from(source: MeshAccessError) -> Self {
MeshMergeError::MeshAccessError { 0: source }
}Error, #[automatically_derived]
impl ::core::fmt::Debug for MeshMergeError {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
MeshMergeError::IncompatibleVertexAttributes {
self_attribute: __self_0, other_attribute: __self_1 } =>
::core::fmt::Formatter::debug_struct_field2_finish(f,
"IncompatibleVertexAttributes", "self_attribute", __self_0,
"other_attribute", &__self_1),
MeshMergeError::IncompatiblePrimitiveTopology {
self_primitive_topology: __self_0,
other_primitive_topology: __self_1 } =>
::core::fmt::Formatter::debug_struct_field2_finish(f,
"IncompatiblePrimitiveTopology", "self_primitive_topology",
__self_0, "other_primitive_topology", &__self_1),
MeshMergeError::MeshAccessError(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"MeshAccessError", &__self_0),
}
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for MeshMergeError {
#[inline]
fn clone(&self) -> MeshMergeError {
match self {
MeshMergeError::IncompatibleVertexAttributes {
self_attribute: __self_0, other_attribute: __self_1 } =>
MeshMergeError::IncompatibleVertexAttributes {
self_attribute: ::core::clone::Clone::clone(__self_0),
other_attribute: ::core::clone::Clone::clone(__self_1),
},
MeshMergeError::IncompatiblePrimitiveTopology {
self_primitive_topology: __self_0,
other_primitive_topology: __self_1 } =>
MeshMergeError::IncompatiblePrimitiveTopology {
self_primitive_topology: ::core::clone::Clone::clone(__self_0),
other_primitive_topology: ::core::clone::Clone::clone(__self_1),
},
MeshMergeError::MeshAccessError(__self_0) =>
MeshMergeError::MeshAccessError(::core::clone::Clone::clone(__self_0)),
}
}
}Clone)]
2703pub enum MeshMergeError {
2704#[error("Incompatible vertex attribute types: {} and {}", self_attribute.name, other_attribute.map(|a| a.name).unwrap_or("None"))]
2705IncompatibleVertexAttributes {
2706 self_attribute: MeshVertexAttribute,
2707 other_attribute: Option<MeshVertexAttribute>,
2708 },
2709#[error(
2710"Incompatible primitive topologies: {:?} and {:?}",
2711 self_primitive_topology,
2712 other_primitive_topology
2713 )]
2714IncompatiblePrimitiveTopology {
2715 self_primitive_topology: PrimitiveTopology,
2716 other_primitive_topology: PrimitiveTopology,
2717 },
2718#[error("Mesh access error: {0}")]
2719MeshAccessError(#[from] MeshAccessError),
2720}
27212722#[cfg(test)]
2723mod tests {
2724use super::Mesh;
2725#[cfg(feature = "serialize")]
2726use super::SerializedMesh;
2727use crate::mesh::{Indices, MeshWindingInvertError, VertexAttributeValues};
2728use crate::PrimitiveTopology;
2729use bevy_asset::RenderAssetUsages;
2730use bevy_math::bounding::Aabb3d;
2731use bevy_math::primitives::Triangle3d;
2732use bevy_math::Vec3;
2733use bevy_transform::components::Transform;
27342735#[test]
2736 #[should_panic]
2737fn panic_invalid_format() {
2738let _mesh = Mesh::new(
2739 PrimitiveTopology::TriangleList,
2740 RenderAssetUsages::default(),
2741 )
2742 .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, vec![[0.0, 0.0, 0.0]]);
2743 }
27442745#[test]
2746fn transform_mesh() {
2747let mesh = Mesh::new(
2748 PrimitiveTopology::TriangleList,
2749 RenderAssetUsages::default(),
2750 )
2751 .with_inserted_attribute(
2752 Mesh::ATTRIBUTE_POSITION,
2753vec![[-1., -1., 2.], [1., -1., 2.], [0., 1., 2.]],
2754 )
2755 .with_inserted_attribute(
2756 Mesh::ATTRIBUTE_NORMAL,
2757vec![
2758 Vec3::new(-1., -1., 1.).normalize().to_array(),
2759 Vec3::new(1., -1., 1.).normalize().to_array(),
2760 [0., 0., 1.],
2761 ],
2762 )
2763 .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, vec![[0., 0.], [1., 0.], [0.5, 1.]]);
27642765let mesh = mesh.transformed_by(
2766 Transform::from_translation(Vec3::splat(-2.)).with_scale(Vec3::new(2., 0., -1.)),
2767 );
27682769if let Some(VertexAttributeValues::Float32x3(positions)) =
2770 mesh.attribute(Mesh::ATTRIBUTE_POSITION)
2771 {
2772// All positions are first scaled resulting in `vec![[-2, 0., -2.], [2., 0., -2.], [0., 0., -2.]]`
2773 // and then shifted by `-2.` along each axis
2774assert_eq!(
2775 positions,
2776&vec![[-4.0, -2.0, -4.0], [0.0, -2.0, -4.0], [-2.0, -2.0, -4.0]]
2777 );
2778 } else {
2779panic!("Mesh does not have a position attribute");
2780 }
27812782if let Some(VertexAttributeValues::Float32x3(normals)) =
2783 mesh.attribute(Mesh::ATTRIBUTE_NORMAL)
2784 {
2785assert_eq!(normals, &vec![[0., -1., 0.], [0., -1., 0.], [0., 0., -1.]]);
2786 } else {
2787panic!("Mesh does not have a normal attribute");
2788 }
27892790if let Some(VertexAttributeValues::Float32x2(uvs)) = mesh.attribute(Mesh::ATTRIBUTE_UV_0) {
2791assert_eq!(uvs, &vec![[0., 0.], [1., 0.], [0.5, 1.]]);
2792 } else {
2793panic!("Mesh does not have a uv attribute");
2794 }
2795 }
27962797#[test]
2798fn point_list_mesh_invert_winding() {
2799let mesh = Mesh::new(PrimitiveTopology::PointList, RenderAssetUsages::default())
2800 .with_inserted_indices(Indices::U32(vec![]));
2801assert!(matches!(
2802 mesh.with_inverted_winding(),
2803Err(MeshWindingInvertError::WrongTopology)
2804 ));
2805 }
28062807#[test]
2808fn line_list_mesh_invert_winding() {
2809let mesh = Mesh::new(PrimitiveTopology::LineList, RenderAssetUsages::default())
2810 .with_inserted_indices(Indices::U32(vec![0, 1, 1, 2, 2, 3]));
2811let mesh = mesh.with_inverted_winding().unwrap();
2812assert_eq!(
2813 mesh.indices().unwrap().iter().collect::<Vec<usize>>(),
2814vec![3, 2, 2, 1, 1, 0]
2815 );
2816 }
28172818#[test]
2819fn line_list_mesh_invert_winding_fail() {
2820let mesh = Mesh::new(PrimitiveTopology::LineList, RenderAssetUsages::default())
2821 .with_inserted_indices(Indices::U32(vec![0, 1, 1]));
2822assert!(matches!(
2823 mesh.with_inverted_winding(),
2824Err(MeshWindingInvertError::AbruptIndicesEnd)
2825 ));
2826 }
28272828#[test]
2829fn line_strip_mesh_invert_winding() {
2830let mesh = Mesh::new(PrimitiveTopology::LineStrip, RenderAssetUsages::default())
2831 .with_inserted_indices(Indices::U32(vec![0, 1, 2, 3]));
2832let mesh = mesh.with_inverted_winding().unwrap();
2833assert_eq!(
2834 mesh.indices().unwrap().iter().collect::<Vec<usize>>(),
2835vec![3, 2, 1, 0]
2836 );
2837 }
28382839#[test]
2840fn triangle_list_mesh_invert_winding() {
2841let mesh = Mesh::new(
2842 PrimitiveTopology::TriangleList,
2843 RenderAssetUsages::default(),
2844 )
2845 .with_inserted_indices(Indices::U32(vec![
28460, 3, 1, // First triangle
28471, 3, 2, // Second triangle
2848]));
2849let mesh = mesh.with_inverted_winding().unwrap();
2850assert_eq!(
2851 mesh.indices().unwrap().iter().collect::<Vec<usize>>(),
2852vec![
28530, 1, 3, // First triangle
28541, 2, 3, // Second triangle
2855]
2856 );
2857 }
28582859#[test]
2860fn triangle_list_mesh_invert_winding_fail() {
2861let mesh = Mesh::new(
2862 PrimitiveTopology::TriangleList,
2863 RenderAssetUsages::default(),
2864 )
2865 .with_inserted_indices(Indices::U32(vec![0, 3, 1, 2]));
2866assert!(matches!(
2867 mesh.with_inverted_winding(),
2868Err(MeshWindingInvertError::AbruptIndicesEnd)
2869 ));
2870 }
28712872#[test]
2873fn triangle_strip_mesh_invert_winding() {
2874let mesh = Mesh::new(
2875 PrimitiveTopology::TriangleStrip,
2876 RenderAssetUsages::default(),
2877 )
2878 .with_inserted_indices(Indices::U32(vec![0, 1, 2, 3]));
2879let mesh = mesh.with_inverted_winding().unwrap();
2880assert_eq!(
2881 mesh.indices().unwrap().iter().collect::<Vec<usize>>(),
2882vec![3, 2, 1, 0]
2883 );
2884 }
28852886#[test]
2887fn compute_area_weighted_normals() {
2888let mut mesh = Mesh::new(
2889 PrimitiveTopology::TriangleList,
2890 RenderAssetUsages::default(),
2891 );
28922893// z y
2894 // | /
2895 // 3---2
2896 // | / \
2897 // 0-----1--x
28982899mesh.insert_attribute(
2900 Mesh::ATTRIBUTE_POSITION,
2901vec![[0., 0., 0.], [1., 0., 0.], [0., 1., 0.], [0., 0., 1.]],
2902 );
2903 mesh.insert_indices(Indices::U16(vec![0, 1, 2, 0, 2, 3]));
2904 mesh.compute_area_weighted_normals();
2905let normals = mesh
2906 .attribute(Mesh::ATTRIBUTE_NORMAL)
2907 .unwrap()
2908 .as_float3()
2909 .unwrap();
2910assert_eq!(4, normals.len());
2911// 0
2912assert_eq!(Vec3::new(1., 0., 1.).normalize().to_array(), normals[0]);
2913// 1
2914assert_eq!([0., 0., 1.], normals[1]);
2915// 2
2916assert_eq!(Vec3::new(1., 0., 1.).normalize().to_array(), normals[2]);
2917// 3
2918assert_eq!([1., 0., 0.], normals[3]);
2919 }
29202921#[test]
2922fn compute_area_weighted_normals_proportionate() {
2923let mut mesh = Mesh::new(
2924 PrimitiveTopology::TriangleList,
2925 RenderAssetUsages::default(),
2926 );
29272928// z y
2929 // | /
2930 // 3---2..
2931 // | / \
2932 // 0-------1---x
29332934mesh.insert_attribute(
2935 Mesh::ATTRIBUTE_POSITION,
2936vec![[0., 0., 0.], [2., 0., 0.], [0., 1., 0.], [0., 0., 1.]],
2937 );
2938 mesh.insert_indices(Indices::U16(vec![0, 1, 2, 0, 2, 3]));
2939 mesh.compute_area_weighted_normals();
2940let normals = mesh
2941 .attribute(Mesh::ATTRIBUTE_NORMAL)
2942 .unwrap()
2943 .as_float3()
2944 .unwrap();
2945assert_eq!(4, normals.len());
2946// 0
2947assert_eq!(Vec3::new(1., 0., 2.).normalize().to_array(), normals[0]);
2948// 1
2949assert_eq!([0., 0., 1.], normals[1]);
2950// 2
2951assert_eq!(Vec3::new(1., 0., 2.).normalize().to_array(), normals[2]);
2952// 3
2953assert_eq!([1., 0., 0.], normals[3]);
2954 }
29552956#[test]
2957fn compute_angle_weighted_normals() {
2958// CuboidMeshBuilder duplicates vertices (even though it is indexed)
29592960 // 5---------4
2961 // /| /|
2962 // 1-+-------0 |
2963 // | 6-------|-7
2964 // |/ |/
2965 // 2---------3
2966let verts = vec![
2967 [1.0, 1.0, 1.0],
2968 [-1.0, 1.0, 1.0],
2969 [-1.0, -1.0, 1.0],
2970 [1.0, -1.0, 1.0],
2971 [1.0, 1.0, -1.0],
2972 [-1.0, 1.0, -1.0],
2973 [-1.0, -1.0, -1.0],
2974 [1.0, -1.0, -1.0],
2975 ];
29762977let indices = Indices::U16(vec![
29780, 1, 2, 2, 3, 0, // front
29795, 4, 7, 7, 6, 5, // back
29801, 5, 6, 6, 2, 1, // left
29814, 0, 3, 3, 7, 4, // right
29824, 5, 1, 1, 0, 4, // top
29833, 2, 6, 6, 7, 3, // bottom
2984]);
2985let mut mesh = Mesh::new(
2986 PrimitiveTopology::TriangleList,
2987 RenderAssetUsages::default(),
2988 );
2989 mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, verts);
2990 mesh.insert_indices(indices);
2991 mesh.compute_smooth_normals();
29922993let normals = mesh
2994 .attribute(Mesh::ATTRIBUTE_NORMAL)
2995 .unwrap()
2996 .as_float3()
2997 .unwrap();
29982999for new in normals.iter().copied().flatten() {
3000// std impl is unstable
3001const FRAC_1_SQRT_3: f32 = 0.57735026;
3002const MIN: f32 = FRAC_1_SQRT_3 - f32::EPSILON;
3003const MAX: f32 = FRAC_1_SQRT_3 + f32::EPSILON;
3004assert!(new.abs() >= MIN, "{new} < {MIN}");
3005assert!(new.abs() <= MAX, "{new} > {MAX}");
3006 }
3007 }
30083009#[test]
3010fn triangles_from_triangle_list() {
3011let mut mesh = Mesh::new(
3012 PrimitiveTopology::TriangleList,
3013 RenderAssetUsages::default(),
3014 );
3015 mesh.insert_attribute(
3016 Mesh::ATTRIBUTE_POSITION,
3017vec![[0., 0., 0.], [1., 0., 0.], [1., 1., 0.], [0., 1., 0.]],
3018 );
3019 mesh.insert_indices(Indices::U32(vec![0, 1, 2, 2, 3, 0]));
3020assert_eq!(
3021vec![
3022 Triangle3d {
3023 vertices: [
3024 Vec3::new(0., 0., 0.),
3025 Vec3::new(1., 0., 0.),
3026 Vec3::new(1., 1., 0.),
3027 ]
3028 },
3029 Triangle3d {
3030 vertices: [
3031 Vec3::new(1., 1., 0.),
3032 Vec3::new(0., 1., 0.),
3033 Vec3::new(0., 0., 0.),
3034 ]
3035 }
3036 ],
3037 mesh.triangles().unwrap().collect::<Vec<Triangle3d>>()
3038 );
3039 }
30403041#[test]
3042fn triangles_from_triangle_strip() {
3043let mut mesh = Mesh::new(
3044 PrimitiveTopology::TriangleStrip,
3045 RenderAssetUsages::default(),
3046 );
3047// Triangles: (0, 1, 2), (2, 1, 3), (2, 3, 4), (4, 3, 5)
3048 //
3049 // 4 - 5
3050 // | \ |
3051 // 2 - 3
3052 // | \ |
3053 // 0 - 1
3054let positions: Vec<Vec3> = [
3055 [0., 0., 0.],
3056 [1., 0., 0.],
3057 [0., 1., 0.],
3058 [1., 1., 0.],
3059 [0., 2., 0.],
3060 [1., 2., 0.],
3061 ]
3062 .into_iter()
3063 .map(Vec3::from_array)
3064 .collect();
3065 mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions.clone());
3066 mesh.insert_indices(Indices::U32(vec![0, 1, 2, 3, 4, 5]));
3067assert_eq!(
3068vec![
3069 Triangle3d {
3070 vertices: [positions[0], positions[1], positions[2]]
3071 },
3072 Triangle3d {
3073 vertices: [positions[2], positions[1], positions[3]]
3074 },
3075 Triangle3d {
3076 vertices: [positions[2], positions[3], positions[4]]
3077 },
3078 Triangle3d {
3079 vertices: [positions[4], positions[3], positions[5]]
3080 },
3081 ],
3082 mesh.triangles().unwrap().collect::<Vec<Triangle3d>>()
3083 );
3084 }
30853086#[test]
3087fn take_gpu_data_calculates_aabb() {
3088let mut mesh = Mesh::new(
3089 PrimitiveTopology::TriangleList,
3090 RenderAssetUsages::default(),
3091 );
3092 mesh.insert_attribute(
3093 Mesh::ATTRIBUTE_POSITION,
3094vec![
3095 [-0.5, 0., 0.],
3096 [-1., 0., 0.],
3097 [-1., -1., 0.],
3098 [-0.5, -1., 0.],
3099 ],
3100 );
3101 mesh.insert_indices(Indices::U32(vec![0, 1, 2, 2, 3, 0]));
3102 mesh = mesh.take_gpu_data().unwrap();
3103assert_eq!(
3104 mesh.final_aabb,
3105Some(Aabb3d::from_min_max([-1., -1., 0.], [-0.5, 0., 0.]))
3106 );
3107 }
31083109#[cfg(feature = "serialize")]
3110 #[test]
3111fn serialize_deserialize_mesh() {
3112let mut mesh = Mesh::new(
3113 PrimitiveTopology::TriangleList,
3114 RenderAssetUsages::default(),
3115 );
31163117 mesh.insert_attribute(
3118 Mesh::ATTRIBUTE_POSITION,
3119vec![[0., 0., 0.], [2., 0., 0.], [0., 1., 0.], [0., 0., 1.]],
3120 );
3121 mesh.insert_indices(Indices::U16(vec![0, 1, 2, 0, 2, 3]));
31223123let serialized_mesh = SerializedMesh::from_mesh(mesh.clone());
3124let serialized_string = serde_json::to_string(&serialized_mesh).unwrap();
3125let serialized_mesh_from_string: SerializedMesh =
3126 serde_json::from_str(&serialized_string).unwrap();
3127let deserialized_mesh = serialized_mesh_from_string.into_mesh();
3128assert_eq!(mesh, deserialized_mesh);
3129 }
31303131#[test]
3132fn merge_duplicate_vertices() {
3133let mut mesh = Mesh::new(
3134 PrimitiveTopology::TriangleList,
3135 RenderAssetUsages::default(),
3136 );
3137// Quad made of two triangles.
3138let positions = vec![
3139 [0.0, 0.0, 0.0],
3140 [1.0, 0.0, 0.0],
3141 [1.0, 1.0, 0.0],
3142// This will be deduplicated.
3143[1.0, 1.0, 0.0],
3144 [0.0, 1.0, 0.0],
3145// Position is equal to the first one but UV is different so it won't be deduplicated.
3146[0.0, 0.0, 0.0],
3147 ];
3148let uvs = vec![
3149 [0.0, 0.0],
3150 [1.0, 0.0],
3151 [1.0, 1.0],
3152// This will be deduplicated.
3153[1.0, 1.0],
3154 [0.0, 1.0],
3155// Use different UV here so it won't be deduplicated.
3156[0.0, 0.5],
3157 ];
3158 mesh.insert_attribute(
3159 Mesh::ATTRIBUTE_POSITION,
3160 VertexAttributeValues::Float32x3(positions.clone()),
3161 );
3162 mesh.insert_attribute(
3163 Mesh::ATTRIBUTE_UV_0,
3164 VertexAttributeValues::Float32x2(uvs.clone()),
3165 );
31663167let res = mesh.merge_duplicate_vertices();
3168assert!(res.is_ok());
3169assert_eq!(6, mesh.indices().unwrap().len());
3170// Note we have 5 unique vertices, not 6.
3171assert_eq!(5, mesh.attribute(Mesh::ATTRIBUTE_POSITION).unwrap().len());
3172assert_eq!(5, mesh.attribute(Mesh::ATTRIBUTE_UV_0).unwrap().len());
31733174// Duplicate back.
3175mesh.duplicate_vertices();
3176assert!(mesh.indices().is_none());
3177let VertexAttributeValues::Float32x3(new_positions) =
3178 mesh.attribute(Mesh::ATTRIBUTE_POSITION).unwrap()
3179else {
3180panic!("Unexpected attribute type")
3181 };
3182let VertexAttributeValues::Float32x2(new_uvs) =
3183 mesh.attribute(Mesh::ATTRIBUTE_UV_0).unwrap()
3184else {
3185panic!("Unexpected attribute type")
3186 };
3187assert_eq!(&positions, new_positions);
3188assert_eq!(&uvs, new_uvs);
3189 }
3190}