mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-08-23 11:05:29 -05:00
FromToRotationの判定をより厳密にする
This commit is contained in:
@@ -27,7 +27,10 @@ namespace UniGLTF.Runtime.Utils
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static quaternion FromToRotation(in float3 fromVector, in float3 toVector)
|
||||
{
|
||||
if (math.lengthsq(fromVector) == 0 || math.lengthsq(toVector) == 0)
|
||||
const float epsilon = 1e-6f;
|
||||
const float epsilonSq = epsilon * epsilon;
|
||||
|
||||
if (math.lengthsq(fromVector) < epsilonSq || math.lengthsq(toVector) < epsilonSq)
|
||||
{
|
||||
return quaternion.identity;
|
||||
}
|
||||
@@ -35,15 +38,15 @@ namespace UniGLTF.Runtime.Utils
|
||||
float3 from = math.normalize(fromVector);
|
||||
float3 to = math.normalize(toVector);
|
||||
|
||||
var dot = math.dot(from, to);
|
||||
switch(dot)
|
||||
var dot = math.clamp(math.dot(from, to), -1.0f, 1.0f);
|
||||
switch (dot)
|
||||
{
|
||||
case >= 1.0f:
|
||||
return quaternion.identity;
|
||||
case <= -1.0f:
|
||||
case > 1.0f - epsilon:
|
||||
return quaternion.identity;
|
||||
case < -1.0f + epsilon:
|
||||
{
|
||||
var axis = math.cross(from, new float3(1, 0, 0));
|
||||
if (math.lengthsq(axis) < 0.0001f)
|
||||
if (math.lengthsq(axis) < epsilonSq)
|
||||
{
|
||||
axis = math.cross(from, new float3(0, 1, 0));
|
||||
}
|
||||
|
||||
@@ -45,5 +45,66 @@ namespace UniGLTF
|
||||
var expected = Quaternion.FromToRotation(_vector1, _vector2);
|
||||
Assert.That(MathHelper.Approximately(result, expected), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FromToRotationMatchesUnityForStandardCasesTest()
|
||||
{
|
||||
AssertFromToRotationMatchesUnity(new float3(1, 0, 0), new float3(0, 1, 0));
|
||||
AssertFromToRotationMatchesUnity(new float3(0, 1, 0), new float3(0, 0, 1));
|
||||
AssertFromToRotationMatchesUnity(new float3(1, 2, 3), new float3(4, 5, 6));
|
||||
AssertFromToRotationMatchesUnity(new float3(-2, 0.5f, 3), new float3(1, -4, 0.25f));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FromToRotationSameDirectionTest()
|
||||
{
|
||||
AssertFromToRotation(new float3(1, 0, 0), new float3(2, 0, 0));
|
||||
AssertFromToRotation(new float3(1, 2, 3), new float3(2, 4, 6));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FromToRotationOppositeDirectionTest()
|
||||
{
|
||||
AssertFromToRotation(new float3(1, 0, 0), new float3(-1, 0, 0));
|
||||
AssertFromToRotation(new float3(0, 1, 0), new float3(0, -1, 0));
|
||||
AssertFromToRotation(new float3(0, 0, 1), new float3(0, 0, -1));
|
||||
AssertFromToRotation(new float3(1, 2, 3), new float3(-1, -2, -3));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FromToRotationNearlyOppositeDirectionTest()
|
||||
{
|
||||
AssertFromToRotation(new float3(1, 0, 0), math.normalize(new float3(-1, 0.0001f, 0)));
|
||||
AssertFromToRotation(new float3(1, 2, 3), math.normalize(new float3(-1.0001f, -2, -3)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FromToRotationZeroVectorTest()
|
||||
{
|
||||
Assert.That(MathHelper.Approximately(MathHelper.FromToRotation(float3.zero, new float3(0, 1, 0)), quaternion.identity), Is.True);
|
||||
Assert.That(MathHelper.Approximately(MathHelper.FromToRotation(new float3(1, 0, 0), float3.zero), quaternion.identity), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FromToRotationTinyVectorTest()
|
||||
{
|
||||
var result = MathHelper.FromToRotation(new float3(1e-12f, 0, 0), new float3(0, 1, 0));
|
||||
Assert.That(MathHelper.Approximately(result, quaternion.identity), Is.True);
|
||||
}
|
||||
|
||||
private static void AssertFromToRotation(float3 from, float3 to)
|
||||
{
|
||||
var result = MathHelper.FromToRotation(from, to);
|
||||
var rotated = math.mul(result, math.normalize(from));
|
||||
var dot = math.dot(math.normalize(rotated), math.normalize(to));
|
||||
Assert.That(dot, Is.GreaterThan(0.9999f));
|
||||
}
|
||||
|
||||
private static void AssertFromToRotationMatchesUnity(float3 from, float3 to)
|
||||
{
|
||||
var result = MathHelper.FromToRotation(from, to);
|
||||
var expected = Quaternion.FromToRotation(from, to);
|
||||
Assert.That(MathHelper.Approximately(result, expected), Is.True);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user