Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add helpers for translate, rotate, and scale operations - Mesh #11675

Merged
merged 1 commit into from
Feb 3, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions crates/bevy_render/src/mesh/mesh/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,120 @@ impl Mesh {
}
}

/// Translates the vertex positions of the mesh by the given [`Vec3`].
pub fn translated_by(mut self, translation: Vec3) -> Self {
self.translate_by(translation);
self
}

/// Translates the vertex positions of the mesh in place by the given [`Vec3`].
pub fn translate_by(&mut self, translation: Vec3) {
if translation == Vec3::ZERO {
return;
}

if let Some(VertexAttributeValues::Float32x3(ref mut positions)) =
self.attribute_mut(Mesh::ATTRIBUTE_POSITION)
{
// Apply translation to vertex positions
positions
.iter_mut()
.for_each(|pos| *pos = (Vec3::from_slice(pos) + translation).to_array());
}
}

/// Rotates the vertex positions, normals, and tangents of the mesh by the given [`Quat`].
pub fn rotated_by(mut self, rotation: Quat) -> Self {
self.rotate_by(rotation);
self
}

/// Rotates the vertex positions, normals, and tangents of the mesh in place by the given [`Quat`].
pub fn rotate_by(&mut self, rotation: Quat) {
if let Some(VertexAttributeValues::Float32x3(ref mut positions)) =
self.attribute_mut(Mesh::ATTRIBUTE_POSITION)
{
// Apply rotation to vertex positions
positions
.iter_mut()
.for_each(|pos| *pos = (rotation * Vec3::from_slice(pos)).to_array());
}

// No need to transform normals or tangents if rotation is near identity
if rotation.is_near_identity() {
return;
}

if let Some(VertexAttributeValues::Float32x3(ref mut normals)) =
self.attribute_mut(Mesh::ATTRIBUTE_NORMAL)
{
// Transform normals
normals.iter_mut().for_each(|normal| {
*normal = (rotation * Vec3::from_slice(normal).normalize_or_zero()).to_array();
});
}

if let Some(VertexAttributeValues::Float32x3(ref mut tangents)) =
self.attribute_mut(Mesh::ATTRIBUTE_TANGENT)
{
// Transform tangents
tangents.iter_mut().for_each(|tangent| {
*tangent = (rotation * Vec3::from_slice(tangent).normalize_or_zero()).to_array();
});
}
}

/// Scales the vertex positions, normals, and tangents of the mesh by the given [`Vec3`].
pub fn scaled_by(mut self, scale: Vec3) -> Self {
self.scale_by(scale);
self
}

/// Scales the vertex positions, normals, and tangents of the mesh in place by the given [`Vec3`].
pub fn scale_by(&mut self, scale: Vec3) {
// Needed when transforming normals and tangents
let covector_scale = scale.yzx() * scale.zxy();

debug_assert!(
covector_scale != Vec3::ZERO,
"mesh transform scale cannot be zero on more than one axis"
);

if let Some(VertexAttributeValues::Float32x3(ref mut positions)) =
self.attribute_mut(Mesh::ATTRIBUTE_POSITION)
{
// Apply scale to vertex positions
positions
.iter_mut()
.for_each(|pos| *pos = (scale * Vec3::from_slice(pos)).to_array());
}

// No need to transform normals or tangents if scale is uniform
if scale.x == scale.y && scale.y == scale.z {
return;
}

if let Some(VertexAttributeValues::Float32x3(ref mut normals)) =
self.attribute_mut(Mesh::ATTRIBUTE_NORMAL)
{
// Transform normals, taking into account non-uniform scaling
normals.iter_mut().for_each(|normal| {
let scaled_normal = Vec3::from_slice(normal) * covector_scale;
*normal = scaled_normal.normalize_or_zero().to_array();
});
}

if let Some(VertexAttributeValues::Float32x3(ref mut tangents)) =
self.attribute_mut(Mesh::ATTRIBUTE_TANGENT)
{
// Transform tangents, taking into account non-uniform scaling
tangents.iter_mut().for_each(|tangent| {
let scaled_tangent = Vec3::from_slice(tangent) * covector_scale;
*tangent = scaled_tangent.normalize_or_zero().to_array();
});
}
}

/// Compute the Axis-Aligned Bounding Box of the mesh vertices in model space
///
/// Returns `None` if `self` doesn't have [`Mesh::ATTRIBUTE_POSITION`] of
Expand Down