mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
Add slerp function for Dir2, Dir3, Dir3A (#13451)
# Objective - Fixes #13407 . ## Solution - Used Quat and Rotation2d. ## Testing - Added tests based on 0°, 30°, 45°, 60° and 90° angles
This commit is contained in:
parent
f9da5eecf2
commit
151e198d94
1 changed files with 155 additions and 0 deletions
|
@ -143,6 +143,35 @@ impl Dir2 {
|
|||
pub const fn as_vec2(&self) -> Vec2 {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Performs a spherical linear interpolation between `self` and `rhs`
|
||||
/// based on the value `s`.
|
||||
///
|
||||
/// This corresponds to interpolating between the two directions at a constant angular velocity.
|
||||
///
|
||||
/// When `s == 0.0`, the result will be equal to `self`.
|
||||
/// When `s == 1.0`, the result will be equal to `rhs`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_math::Dir2;
|
||||
/// # use approx::{assert_relative_eq, RelativeEq};
|
||||
/// #
|
||||
/// let dir1 = Dir2::X;
|
||||
/// let dir2 = Dir2::Y;
|
||||
///
|
||||
/// let result1 = dir1.slerp(dir2, 1.0 / 3.0);
|
||||
/// assert_relative_eq!(result1, Dir2::from_xy(0.75_f32.sqrt(), 0.5).unwrap());
|
||||
///
|
||||
/// let result2 = dir1.slerp(dir2, 0.5);
|
||||
/// assert_relative_eq!(result2, Dir2::from_xy(0.5_f32.sqrt(), 0.5_f32.sqrt()).unwrap());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn slerp(self, rhs: Self, s: f32) -> Self {
|
||||
let angle = self.angle_between(rhs.0);
|
||||
Rotation2d::radians(angle * s) * self
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Vec2> for Dir2 {
|
||||
|
@ -307,6 +336,39 @@ impl Dir3 {
|
|||
pub const fn as_vec3(&self) -> Vec3 {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Performs a spherical linear interpolation between `self` and `rhs`
|
||||
/// based on the value `s`.
|
||||
///
|
||||
/// This corresponds to interpolating between the two directions at a constant angular velocity.
|
||||
///
|
||||
/// When `s == 0.0`, the result will be equal to `self`.
|
||||
/// When `s == 1.0`, the result will be equal to `rhs`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_math::Dir3;
|
||||
/// # use approx::{assert_relative_eq, RelativeEq};
|
||||
/// #
|
||||
/// let dir1 = Dir3::X;
|
||||
/// let dir2 = Dir3::Y;
|
||||
///
|
||||
/// let result1 = dir1.slerp(dir2, 1.0 / 3.0);
|
||||
/// assert_relative_eq!(
|
||||
/// result1,
|
||||
/// Dir3::from_xyz(0.75_f32.sqrt(), 0.5, 0.0).unwrap(),
|
||||
/// epsilon = 0.000001
|
||||
/// );
|
||||
///
|
||||
/// let result2 = dir1.slerp(dir2, 0.5);
|
||||
/// assert_relative_eq!(result2, Dir3::from_xyz(0.5_f32.sqrt(), 0.5_f32.sqrt(), 0.0).unwrap());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn slerp(self, rhs: Self, s: f32) -> Self {
|
||||
let quat = Quat::IDENTITY.slerp(Quat::from_rotation_arc(self.0, rhs.0), s);
|
||||
Dir3(quat.mul_vec3(self.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Vec3> for Dir3 {
|
||||
|
@ -474,6 +536,42 @@ impl Dir3A {
|
|||
pub const fn as_vec3a(&self) -> Vec3A {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Performs a spherical linear interpolation between `self` and `rhs`
|
||||
/// based on the value `s`.
|
||||
///
|
||||
/// This corresponds to interpolating between the two directions at a constant angular velocity.
|
||||
///
|
||||
/// When `s == 0.0`, the result will be equal to `self`.
|
||||
/// When `s == 1.0`, the result will be equal to `rhs`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_math::Dir3A;
|
||||
/// # use approx::{assert_relative_eq, RelativeEq};
|
||||
/// #
|
||||
/// let dir1 = Dir3A::X;
|
||||
/// let dir2 = Dir3A::Y;
|
||||
///
|
||||
/// let result1 = dir1.slerp(dir2, 1.0 / 3.0);
|
||||
/// assert_relative_eq!(
|
||||
/// result1,
|
||||
/// Dir3A::from_xyz(0.75_f32.sqrt(), 0.5, 0.0).unwrap(),
|
||||
/// epsilon = 0.000001
|
||||
/// );
|
||||
///
|
||||
/// let result2 = dir1.slerp(dir2, 0.5);
|
||||
/// assert_relative_eq!(result2, Dir3A::from_xyz(0.5_f32.sqrt(), 0.5_f32.sqrt(), 0.0).unwrap());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn slerp(self, rhs: Self, s: f32) -> Self {
|
||||
let quat = Quat::IDENTITY.slerp(
|
||||
Quat::from_rotation_arc(Vec3::from(self.0), Vec3::from(rhs.0)),
|
||||
s,
|
||||
);
|
||||
Dir3A(quat.mul_vec3a(self.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Dir3> for Dir3A {
|
||||
|
@ -582,6 +680,7 @@ impl approx::UlpsEq for Dir3A {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use approx::assert_relative_eq;
|
||||
|
||||
#[test]
|
||||
fn dir2_creation() {
|
||||
|
@ -605,6 +704,24 @@ mod tests {
|
|||
assert_eq!(Dir2::new_and_length(Vec2::X * 6.5), Ok((Dir2::X, 6.5)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dir2_slerp() {
|
||||
assert_relative_eq!(
|
||||
Dir2::X.slerp(Dir2::Y, 0.5),
|
||||
Dir2::from_xy(0.5_f32.sqrt(), 0.5_f32.sqrt()).unwrap()
|
||||
);
|
||||
assert_eq!(Dir2::Y.slerp(Dir2::X, 0.0), Dir2::Y);
|
||||
assert_relative_eq!(Dir2::X.slerp(Dir2::Y, 1.0), Dir2::Y);
|
||||
assert_relative_eq!(
|
||||
Dir2::Y.slerp(Dir2::X, 1.0 / 3.0),
|
||||
Dir2::from_xy(0.5, 0.75_f32.sqrt()).unwrap()
|
||||
);
|
||||
assert_relative_eq!(
|
||||
Dir2::X.slerp(Dir2::Y, 2.0 / 3.0),
|
||||
Dir2::from_xy(0.5, 0.75_f32.sqrt()).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dir3_creation() {
|
||||
assert_eq!(Dir3::new(Vec3::X * 12.5), Ok(Dir3::X));
|
||||
|
@ -633,6 +750,25 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dir3_slerp() {
|
||||
assert_relative_eq!(
|
||||
Dir3::X.slerp(Dir3::Y, 0.5),
|
||||
Dir3::from_xyz(0.5f32.sqrt(), 0.5f32.sqrt(), 0.0).unwrap()
|
||||
);
|
||||
assert_relative_eq!(Dir3::Y.slerp(Dir3::Z, 0.0), Dir3::Y);
|
||||
assert_relative_eq!(Dir3::Z.slerp(Dir3::X, 1.0), Dir3::X, epsilon = 0.000001);
|
||||
assert_relative_eq!(
|
||||
Dir3::X.slerp(Dir3::Z, 1.0 / 3.0),
|
||||
Dir3::from_xyz(0.75f32.sqrt(), 0.0, 0.5).unwrap(),
|
||||
epsilon = 0.000001
|
||||
);
|
||||
assert_relative_eq!(
|
||||
Dir3::Z.slerp(Dir3::Y, 2.0 / 3.0),
|
||||
Dir3::from_xyz(0.0, 0.75f32.sqrt(), 0.5).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dir3a_creation() {
|
||||
assert_eq!(Dir3A::new(Vec3A::X * 12.5), Ok(Dir3A::X));
|
||||
|
@ -660,4 +796,23 @@ mod tests {
|
|||
.abs_diff_eq(Vec3A::Y, 10e-6)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dir3a_slerp() {
|
||||
assert_relative_eq!(
|
||||
Dir3A::X.slerp(Dir3A::Y, 0.5),
|
||||
Dir3A::from_xyz(0.5f32.sqrt(), 0.5f32.sqrt(), 0.0).unwrap()
|
||||
);
|
||||
assert_relative_eq!(Dir3A::Y.slerp(Dir3A::Z, 0.0), Dir3A::Y);
|
||||
assert_relative_eq!(Dir3A::Z.slerp(Dir3A::X, 1.0), Dir3A::X, epsilon = 0.000001);
|
||||
assert_relative_eq!(
|
||||
Dir3A::X.slerp(Dir3A::Z, 1.0 / 3.0),
|
||||
Dir3A::from_xyz(0.75f32.sqrt(), 0.0, 0.5).unwrap(),
|
||||
epsilon = 0.000001
|
||||
);
|
||||
assert_relative_eq!(
|
||||
Dir3A::Z.slerp(Dir3A::Y, 2.0 / 3.0),
|
||||
Dir3A::from_xyz(0.0, 0.75f32.sqrt(), 0.5).unwrap()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue