Add GetRotationFromTo and FindBetween utilities to C# Quaternion API
#1885
This commit is contained in:
@@ -382,9 +382,8 @@ void Quaternion::GetRotationFromTo(const Float3& from, const Float3& to, Quatern
|
||||
v0.Normalize();
|
||||
v1.Normalize();
|
||||
|
||||
const float d = Float3::Dot(v0, v1);
|
||||
|
||||
// If dot == 1, vectors are the same
|
||||
const float d = Float3::Dot(v0, v1);
|
||||
if (d >= 1.0f)
|
||||
{
|
||||
result = Identity;
|
||||
|
||||
@@ -1077,6 +1077,115 @@ namespace FlaxEngine
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the shortest arc quaternion to rotate this vector to the destination vector.
|
||||
/// </summary>
|
||||
/// <param name="from">The source vector.</param>
|
||||
/// <param name="to">The destination vector.</param>
|
||||
/// <param name="result">The result.</param>
|
||||
/// <param name="fallbackAxis">The fallback axis.</param>
|
||||
public static void GetRotationFromTo(ref Float3 from, ref Float3 to, out Quaternion result, ref Float3 fallbackAxis)
|
||||
{
|
||||
// Based on Stan Melax's article in Game Programming Gems
|
||||
|
||||
Float3 v0 = from;
|
||||
Float3 v1 = to;
|
||||
v0.Normalize();
|
||||
v1.Normalize();
|
||||
|
||||
// If dot == 1, vectors are the same
|
||||
float d = Float3.Dot(ref v0, ref v1);
|
||||
if (d >= 1.0f)
|
||||
{
|
||||
result = Identity;
|
||||
return;
|
||||
}
|
||||
|
||||
if (d < 1e-6f - 1.0f)
|
||||
{
|
||||
if (fallbackAxis != Float3.Zero)
|
||||
{
|
||||
// Rotate 180 degrees about the fallback axis
|
||||
RotationAxis(ref fallbackAxis, Mathf.Pi, out result);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Generate an axis
|
||||
Float3 axis = Float3.Cross(Float3.UnitX, from);
|
||||
if (axis.LengthSquared < Mathf.Epsilon) // Pick another if colinear
|
||||
axis = Float3.Cross(Float3.UnitY, from);
|
||||
axis.Normalize();
|
||||
RotationAxis(ref axis, Mathf.Pi, out result);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float s = Mathf.Sqrt((1 + d) * 2);
|
||||
float invS = 1 / s;
|
||||
Float3.Cross(ref v0, ref v1, out var c);
|
||||
result.X = c.X * invS;
|
||||
result.Y = c.Y * invS;
|
||||
result.Z = c.Z * invS;
|
||||
result.W = s * 0.5f;
|
||||
result.Normalize();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the shortest arc quaternion to rotate this vector to the destination vector.
|
||||
/// </summary>
|
||||
/// <param name="from">The source vector.</param>
|
||||
/// <param name="to">The destination vector.</param>
|
||||
/// <param name="fallbackAxis">The fallback axis.</param>
|
||||
/// <returns>The rotation.</returns>
|
||||
public static Quaternion GetRotationFromTo(Float3 from, Float3 to, Float3 fallbackAxis)
|
||||
{
|
||||
GetRotationFromTo(ref from, ref to, out var result, ref fallbackAxis);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the quaternion that will rotate vector from into vector to, around their plan perpendicular axis.The input vectors don't need to be normalized.
|
||||
/// </summary>
|
||||
/// <param name="from">The source vector.</param>
|
||||
/// <param name="to">The destination vector.</param>
|
||||
/// <param name="result">The result.</param>
|
||||
public static void FindBetween(ref Float3 from, ref Float3 to, out Quaternion result)
|
||||
{
|
||||
// http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final
|
||||
float normFromNormTo = Mathf.Sqrt(from.LengthSquared * to.LengthSquared);
|
||||
if (normFromNormTo < Mathf.Epsilon)
|
||||
{
|
||||
result = Identity;
|
||||
return;
|
||||
}
|
||||
float w = normFromNormTo + Float3.Dot(from, to);
|
||||
if (w < 1.0-6f * normFromNormTo)
|
||||
{
|
||||
result = Mathf.Abs(from.X) > Mathf.Abs(from.Z)
|
||||
? new Quaternion(-from.Y, from.X, 0.0f, 0.0f)
|
||||
: new Quaternion(0.0f, -from.Z, from.Y, 0.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
Float3 cross = Float3.Cross(from, to);
|
||||
result = new Quaternion(cross.X, cross.Y, cross.Z, w);
|
||||
}
|
||||
result.Normalize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the quaternion that will rotate vector from into vector to, around their plan perpendicular axis.The input vectors don't need to be normalized.
|
||||
/// </summary>
|
||||
/// <param name="from">The source vector.</param>
|
||||
/// <param name="to">The destination vector.</param>
|
||||
/// <returns>The rotation.</returns>
|
||||
public static Quaternion FindBetween(Float3 from, Float3 to)
|
||||
{
|
||||
FindBetween(ref from, ref to, out var result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a left-handed spherical billboard that rotates around a specified object position.
|
||||
/// </summary>
|
||||
|
||||
@@ -218,10 +218,10 @@ float4 ClampedPow(float4 x, float4 y)
|
||||
|
||||
float4 FindQuatBetween(float3 from, float3 to)
|
||||
{
|
||||
// http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final
|
||||
float normAB = 1.0f;
|
||||
float w = normAB + dot(from, to);
|
||||
float4 result;
|
||||
|
||||
if (w >= 1e-6f * normAB)
|
||||
{
|
||||
result = float4
|
||||
@@ -234,12 +234,10 @@ float4 FindQuatBetween(float3 from, float3 to)
|
||||
}
|
||||
else
|
||||
{
|
||||
w = 0.f;
|
||||
result = abs(from.x) > abs(from.y)
|
||||
? float4(-from.z, 0.f, from.x, w)
|
||||
: float4(0.f, -from.z, from.y, w);
|
||||
? float4(-from.z, 0.f, from.x, 0.0f)
|
||||
: float4(0.f, -from.z, from.y, 0.0f);
|
||||
}
|
||||
|
||||
return normalize(result);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user