Skip to content

Commit

Permalink
yeet allow + inspiration from Quat::slerp
Browse files Browse the repository at this point in the history
  • Loading branch information
tim-blackbird committed Nov 13, 2024
1 parent e987355 commit f550df1
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 100 deletions.
10 changes: 10 additions & 0 deletions benches/vec3a.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,15 @@ bench_select!(
from => random_vec3a
);

bench_trinop!(
vec3a_slerp,
"vec3a slerp",
op => slerp,
from1 => random_vec3a,
from2 => random_vec3a,
from3 => random_f32
);

criterion_group!(
benches,
vec3a_normalize_bench,
Expand All @@ -171,6 +180,7 @@ criterion_group!(
vec3a_to_rgb,
vec3a_to_tuple_into,
vec3a_to_vec3,
vec3a_slerp,
);

criterion_main!(benches);
28 changes: 14 additions & 14 deletions codegen/templates/vec.rs.tera
Original file line number Diff line number Diff line change
Expand Up @@ -2181,34 +2181,34 @@ impl {{ self_t }} {
let self_length = self.length();
let rhs_length = rhs.length();
// Cosine of the angle between the vectors [-1, 1], or NaN if either vector has a zero length
let cos_alpha = self.dot(rhs) / (self_length * rhs_length);
// If cos_alpha is close to 1 or -1, or is NaN the calculations for t1 and t2 break down
if math::abs(cos_alpha) < 1.0 - 3e-7 {
let dot = self.dot(rhs) / (self_length * rhs_length);
// If dot is close to 1 or -1, or is NaN the calculations for t1 and t2 break down
if math::abs(dot) < 1.0 - 3e-7 {
// Angle between the vectors [0, +π]
let alpha = math::acos_approx(cos_alpha);
let theta = math::acos_approx(dot);
// Sine of the angle between vectors [0, 1]
let sin_alpha = math::sin(alpha);
let t1 = math::sin((1. - s) * alpha) / sin_alpha;
let t2 = math::sin(s * alpha) / sin_alpha;
let sin_theta = math::sin(theta);
let t1 = math::sin(theta * (1. - s));
let t2 = math::sin(theta * s);

// Interpolate vector lengths
let result_length = self_length.lerp(rhs_length, s);
// Scale the vectors to the target length and interpolate them
return self * (result_length / self_length) * t1
+ rhs * (result_length / rhs_length) * t2;
return (self * (result_length / self_length) * t1
+ rhs * (result_length / rhs_length) * t2)
* sin_theta.recip();
}
if cos_alpha < 0.0 {
if dot < 0.0 {
// Vectors are almost parallel in opposing directions

// Create a rotation from self to rhs along some axis
#[allow(clippy::useless_conversion)]
let axis = self.any_orthogonal_vector().normalize().into();
let axis = self.any_orthogonal_vector().normalize(){% if is_align %}.into(){% endif %};
let rotation = {{ quat_t }}::from_axis_angle(axis, core::{{ scalar_t }}::consts::PI * s);
// Interpolate vector lengths
let result_length = self_length.lerp(rhs_length, s);
rotation * self * (result_length / self_length)
rotation * self * (result_length / self_length)
} else {
// Vectors are almost parallel in the same direction, or cos_alpha was NaN
// Vectors are almost parallel in the same direction, or dot was NaN
self.lerp(rhs, s)
}
}
Expand Down
24 changes: 12 additions & 12 deletions src/f32/coresimd/vec3a.rs
Original file line number Diff line number Diff line change
Expand Up @@ -950,34 +950,34 @@ impl Vec3A {
let self_length = self.length();
let rhs_length = rhs.length();
// Cosine of the angle between the vectors [-1, 1], or NaN if either vector has a zero length
let cos_alpha = self.dot(rhs) / (self_length * rhs_length);
// If cos_alpha is close to 1 or -1, or is NaN the calculations for t1 and t2 break down
if math::abs(cos_alpha) < 1.0 - 3e-7 {
let dot = self.dot(rhs) / (self_length * rhs_length);
// If dot is close to 1 or -1, or is NaN the calculations for t1 and t2 break down
if math::abs(dot) < 1.0 - 3e-7 {
// Angle between the vectors [0, +π]
let alpha = math::acos_approx(cos_alpha);
let theta = math::acos_approx(dot);
// Sine of the angle between vectors [0, 1]
let sin_alpha = math::sin(alpha);
let t1 = math::sin((1. - s) * alpha) / sin_alpha;
let t2 = math::sin(s * alpha) / sin_alpha;
let sin_theta = math::sin(theta);
let t1 = math::sin(theta * (1. - s));
let t2 = math::sin(theta * s);

// Interpolate vector lengths
let result_length = self_length.lerp(rhs_length, s);
// Scale the vectors to the target length and interpolate them
return self * (result_length / self_length) * t1
+ rhs * (result_length / rhs_length) * t2;
return (self * (result_length / self_length) * t1
+ rhs * (result_length / rhs_length) * t2)
* sin_theta.recip();
}
if cos_alpha < 0.0 {
if dot < 0.0 {
// Vectors are almost parallel in opposing directions

// Create a rotation from self to rhs along some axis
#[allow(clippy::useless_conversion)]
let axis = self.any_orthogonal_vector().normalize().into();
let rotation = Quat::from_axis_angle(axis, core::f32::consts::PI * s);
// Interpolate vector lengths
let result_length = self_length.lerp(rhs_length, s);
rotation * self * (result_length / self_length)
} else {
// Vectors are almost parallel in the same direction, or cos_alpha was NaN
// Vectors are almost parallel in the same direction, or dot was NaN
self.lerp(rhs, s)
}
}
Expand Down
24 changes: 12 additions & 12 deletions src/f32/neon/vec3a.rs
Original file line number Diff line number Diff line change
Expand Up @@ -994,34 +994,34 @@ impl Vec3A {
let self_length = self.length();
let rhs_length = rhs.length();
// Cosine of the angle between the vectors [-1, 1], or NaN if either vector has a zero length
let cos_alpha = self.dot(rhs) / (self_length * rhs_length);
// If cos_alpha is close to 1 or -1, or is NaN the calculations for t1 and t2 break down
if math::abs(cos_alpha) < 1.0 - 3e-7 {
let dot = self.dot(rhs) / (self_length * rhs_length);
// If dot is close to 1 or -1, or is NaN the calculations for t1 and t2 break down
if math::abs(dot) < 1.0 - 3e-7 {
// Angle between the vectors [0, +π]
let alpha = math::acos_approx(cos_alpha);
let theta = math::acos_approx(dot);
// Sine of the angle between vectors [0, 1]
let sin_alpha = math::sin(alpha);
let t1 = math::sin((1. - s) * alpha) / sin_alpha;
let t2 = math::sin(s * alpha) / sin_alpha;
let sin_theta = math::sin(theta);
let t1 = math::sin(theta * (1. - s));
let t2 = math::sin(theta * s);

// Interpolate vector lengths
let result_length = self_length.lerp(rhs_length, s);
// Scale the vectors to the target length and interpolate them
return self * (result_length / self_length) * t1
+ rhs * (result_length / rhs_length) * t2;
return (self * (result_length / self_length) * t1
+ rhs * (result_length / rhs_length) * t2)
* sin_theta.recip();
}
if cos_alpha < 0.0 {
if dot < 0.0 {
// Vectors are almost parallel in opposing directions

// Create a rotation from self to rhs along some axis
#[allow(clippy::useless_conversion)]
let axis = self.any_orthogonal_vector().normalize().into();
let rotation = Quat::from_axis_angle(axis, core::f32::consts::PI * s);
// Interpolate vector lengths
let result_length = self_length.lerp(rhs_length, s);
rotation * self * (result_length / self_length)
} else {
// Vectors are almost parallel in the same direction, or cos_alpha was NaN
// Vectors are almost parallel in the same direction, or dot was NaN
self.lerp(rhs, s)
}
}
Expand Down
24 changes: 12 additions & 12 deletions src/f32/scalar/vec3a.rs
Original file line number Diff line number Diff line change
Expand Up @@ -997,34 +997,34 @@ impl Vec3A {
let self_length = self.length();
let rhs_length = rhs.length();
// Cosine of the angle between the vectors [-1, 1], or NaN if either vector has a zero length
let cos_alpha = self.dot(rhs) / (self_length * rhs_length);
// If cos_alpha is close to 1 or -1, or is NaN the calculations for t1 and t2 break down
if math::abs(cos_alpha) < 1.0 - 3e-7 {
let dot = self.dot(rhs) / (self_length * rhs_length);
// If dot is close to 1 or -1, or is NaN the calculations for t1 and t2 break down
if math::abs(dot) < 1.0 - 3e-7 {
// Angle between the vectors [0, +π]
let alpha = math::acos_approx(cos_alpha);
let theta = math::acos_approx(dot);
// Sine of the angle between vectors [0, 1]
let sin_alpha = math::sin(alpha);
let t1 = math::sin((1. - s) * alpha) / sin_alpha;
let t2 = math::sin(s * alpha) / sin_alpha;
let sin_theta = math::sin(theta);
let t1 = math::sin(theta * (1. - s));
let t2 = math::sin(theta * s);

// Interpolate vector lengths
let result_length = self_length.lerp(rhs_length, s);
// Scale the vectors to the target length and interpolate them
return self * (result_length / self_length) * t1
+ rhs * (result_length / rhs_length) * t2;
return (self * (result_length / self_length) * t1
+ rhs * (result_length / rhs_length) * t2)
* sin_theta.recip();
}
if cos_alpha < 0.0 {
if dot < 0.0 {
// Vectors are almost parallel in opposing directions

// Create a rotation from self to rhs along some axis
#[allow(clippy::useless_conversion)]
let axis = self.any_orthogonal_vector().normalize().into();
let rotation = Quat::from_axis_angle(axis, core::f32::consts::PI * s);
// Interpolate vector lengths
let result_length = self_length.lerp(rhs_length, s);
rotation * self * (result_length / self_length)
} else {
// Vectors are almost parallel in the same direction, or cos_alpha was NaN
// Vectors are almost parallel in the same direction, or dot was NaN
self.lerp(rhs, s)
}
}
Expand Down
24 changes: 12 additions & 12 deletions src/f32/sse2/vec3a.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1002,34 +1002,34 @@ impl Vec3A {
let self_length = self.length();
let rhs_length = rhs.length();
// Cosine of the angle between the vectors [-1, 1], or NaN if either vector has a zero length
let cos_alpha = self.dot(rhs) / (self_length * rhs_length);
// If cos_alpha is close to 1 or -1, or is NaN the calculations for t1 and t2 break down
if math::abs(cos_alpha) < 1.0 - 3e-7 {
let dot = self.dot(rhs) / (self_length * rhs_length);
// If dot is close to 1 or -1, or is NaN the calculations for t1 and t2 break down
if math::abs(dot) < 1.0 - 3e-7 {
// Angle between the vectors [0, +π]
let alpha = math::acos_approx(cos_alpha);
let theta = math::acos_approx(dot);
// Sine of the angle between vectors [0, 1]
let sin_alpha = math::sin(alpha);
let t1 = math::sin((1. - s) * alpha) / sin_alpha;
let t2 = math::sin(s * alpha) / sin_alpha;
let sin_theta = math::sin(theta);
let t1 = math::sin(theta * (1. - s));
let t2 = math::sin(theta * s);

// Interpolate vector lengths
let result_length = self_length.lerp(rhs_length, s);
// Scale the vectors to the target length and interpolate them
return self * (result_length / self_length) * t1
+ rhs * (result_length / rhs_length) * t2;
return (self * (result_length / self_length) * t1
+ rhs * (result_length / rhs_length) * t2)
* sin_theta.recip();
}
if cos_alpha < 0.0 {
if dot < 0.0 {
// Vectors are almost parallel in opposing directions

// Create a rotation from self to rhs along some axis
#[allow(clippy::useless_conversion)]
let axis = self.any_orthogonal_vector().normalize().into();
let rotation = Quat::from_axis_angle(axis, core::f32::consts::PI * s);
// Interpolate vector lengths
let result_length = self_length.lerp(rhs_length, s);
rotation * self * (result_length / self_length)
} else {
// Vectors are almost parallel in the same direction, or cos_alpha was NaN
// Vectors are almost parallel in the same direction, or dot was NaN
self.lerp(rhs, s)
}
}
Expand Down
26 changes: 13 additions & 13 deletions src/f32/vec3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -987,34 +987,34 @@ impl Vec3 {
let self_length = self.length();
let rhs_length = rhs.length();
// Cosine of the angle between the vectors [-1, 1], or NaN if either vector has a zero length
let cos_alpha = self.dot(rhs) / (self_length * rhs_length);
// If cos_alpha is close to 1 or -1, or is NaN the calculations for t1 and t2 break down
if math::abs(cos_alpha) < 1.0 - 3e-7 {
let dot = self.dot(rhs) / (self_length * rhs_length);
// If dot is close to 1 or -1, or is NaN the calculations for t1 and t2 break down
if math::abs(dot) < 1.0 - 3e-7 {
// Angle between the vectors [0, +π]
let alpha = math::acos_approx(cos_alpha);
let theta = math::acos_approx(dot);
// Sine of the angle between vectors [0, 1]
let sin_alpha = math::sin(alpha);
let t1 = math::sin((1. - s) * alpha) / sin_alpha;
let t2 = math::sin(s * alpha) / sin_alpha;
let sin_theta = math::sin(theta);
let t1 = math::sin(theta * (1. - s));
let t2 = math::sin(theta * s);

// Interpolate vector lengths
let result_length = self_length.lerp(rhs_length, s);
// Scale the vectors to the target length and interpolate them
return self * (result_length / self_length) * t1
+ rhs * (result_length / rhs_length) * t2;
return (self * (result_length / self_length) * t1
+ rhs * (result_length / rhs_length) * t2)
* sin_theta.recip();
}
if cos_alpha < 0.0 {
if dot < 0.0 {
// Vectors are almost parallel in opposing directions

// Create a rotation from self to rhs along some axis
#[allow(clippy::useless_conversion)]
let axis = self.any_orthogonal_vector().normalize().into();
let axis = self.any_orthogonal_vector().normalize();
let rotation = Quat::from_axis_angle(axis, core::f32::consts::PI * s);
// Interpolate vector lengths
let result_length = self_length.lerp(rhs_length, s);
rotation * self * (result_length / self_length)
} else {
// Vectors are almost parallel in the same direction, or cos_alpha was NaN
// Vectors are almost parallel in the same direction, or dot was NaN
self.lerp(rhs, s)
}
}
Expand Down
24 changes: 12 additions & 12 deletions src/f32/wasm32/vec3a.rs
Original file line number Diff line number Diff line change
Expand Up @@ -965,34 +965,34 @@ impl Vec3A {
let self_length = self.length();
let rhs_length = rhs.length();
// Cosine of the angle between the vectors [-1, 1], or NaN if either vector has a zero length
let cos_alpha = self.dot(rhs) / (self_length * rhs_length);
// If cos_alpha is close to 1 or -1, or is NaN the calculations for t1 and t2 break down
if math::abs(cos_alpha) < 1.0 - 3e-7 {
let dot = self.dot(rhs) / (self_length * rhs_length);
// If dot is close to 1 or -1, or is NaN the calculations for t1 and t2 break down
if math::abs(dot) < 1.0 - 3e-7 {
// Angle between the vectors [0, +π]
let alpha = math::acos_approx(cos_alpha);
let theta = math::acos_approx(dot);
// Sine of the angle between vectors [0, 1]
let sin_alpha = math::sin(alpha);
let t1 = math::sin((1. - s) * alpha) / sin_alpha;
let t2 = math::sin(s * alpha) / sin_alpha;
let sin_theta = math::sin(theta);
let t1 = math::sin(theta * (1. - s));
let t2 = math::sin(theta * s);

// Interpolate vector lengths
let result_length = self_length.lerp(rhs_length, s);
// Scale the vectors to the target length and interpolate them
return self * (result_length / self_length) * t1
+ rhs * (result_length / rhs_length) * t2;
return (self * (result_length / self_length) * t1
+ rhs * (result_length / rhs_length) * t2)
* sin_theta.recip();
}
if cos_alpha < 0.0 {
if dot < 0.0 {
// Vectors are almost parallel in opposing directions

// Create a rotation from self to rhs along some axis
#[allow(clippy::useless_conversion)]
let axis = self.any_orthogonal_vector().normalize().into();
let rotation = Quat::from_axis_angle(axis, core::f32::consts::PI * s);
// Interpolate vector lengths
let result_length = self_length.lerp(rhs_length, s);
rotation * self * (result_length / self_length)
} else {
// Vectors are almost parallel in the same direction, or cos_alpha was NaN
// Vectors are almost parallel in the same direction, or dot was NaN
self.lerp(rhs, s)
}
}
Expand Down
Loading

0 comments on commit f550df1

Please sign in to comment.