streamingle-unity-utilities/Tests/Editor/Gaze/GazeDirectionSolverTests.cs

150 lines
5.4 KiB
C#

using System;
using System.Collections.Generic;
using NUnit.Framework;
using UnityEngine;
namespace Streamingle.Gaze.Tests
{
public sealed class GazeDirectionSolverTests
{
[Test]
public void Calculate_ClampsAndNormalizesAsymmetricRanges()
{
var result = GazeDirectionSolver.Calculate(
Quaternion.identity,
GazeDirectionSolver.DirectionFromAngles(60f, 30f),
-20f,
40f,
-10f,
20f);
Assert.That(result.RawYaw, Is.EqualTo(60f).Within(0.01f));
Assert.That(result.RawPitch, Is.EqualTo(30f).Within(0.01f));
Assert.That(result.ClampedYaw, Is.EqualTo(40f).Within(0.01f));
Assert.That(result.ClampedPitch, Is.EqualTo(20f).Within(0.01f));
Assert.That(result.NormalizedYaw, Is.EqualTo(1f).Within(0.001f));
Assert.That(result.NormalizedPitch, Is.EqualTo(1f).Within(0.001f));
Assert.That(result.WasClamped, Is.True);
}
[Test]
public void Calculate_UsesCharacterLocalReference()
{
var reference = Quaternion.Euler(5f, 73f, 0f);
var localDirection = GazeDirectionSolver.DirectionFromAngles(-10f, -5f);
var result = GazeDirectionSolver.Calculate(
reference,
reference * localDirection,
-20f,
40f,
-10f,
20f);
Assert.That(result.RawYaw, Is.EqualTo(-10f).Within(0.01f));
Assert.That(result.RawPitch, Is.EqualTo(-5f).Within(0.01f));
Assert.That(result.NormalizedYaw, Is.EqualTo(-0.5f).Within(0.001f));
Assert.That(result.NormalizedPitch, Is.EqualTo(-0.5f).Within(0.001f));
Assert.That(result.WasClamped, Is.False);
}
[Test]
public void Profile_BilinearlyInterpolatesTheThreeByThreeGrid()
{
var profile = ScriptableObject.CreateInstance<BlendshapeGazeProfile>();
try
{
profile.ReplaceChannels(new[]
{
new GazeBlendShapeChannel("eyeLookUpLeft")
});
for (var index = 0; index < 9; index++)
profile.SetSample((GazeCalibrationPoint)index, new[] { (float)index });
var output = new float[1];
var direction = DirectionWithNormalizedCoordinates(-0.5f, -0.5f);
Assert.That(profile.TryEvaluate(direction, false, output), Is.True);
// Bottom-left/center cell: lerp of sample values 0,1,3,4.
Assert.That(output[0], Is.EqualTo(2f).Within(0.001f));
direction = DirectionWithNormalizedCoordinates(0.5f, 0.5f);
Assert.That(profile.TryEvaluate(direction, false, output), Is.True);
// Center/top-right cell: lerp of sample values 4,5,7,8.
Assert.That(output[0], Is.EqualTo(6f).Within(0.001f));
}
finally
{
UnityEngine.Object.DestroyImmediate(profile);
}
}
[Test]
public void Profile_ExcludesCorrectiveChannelsUnlessRequested()
{
var profile = ScriptableObject.CreateInstance<BlendshapeGazeProfile>();
try
{
profile.ReplaceChannels(new List<GazeBlendShapeChannel>
{
new GazeBlendShapeChannel("eyeLookUpLeft"),
new GazeBlendShapeChannel("eyeBlinkLeft", GazeChannelUsage.Corrective)
});
for (var index = 0; index < 9; index++)
profile.SetSample((GazeCalibrationPoint)index, new[] { 10f, 20f });
var output = new float[2];
Assert.That(profile.TryEvaluate(DirectionWithNormalizedCoordinates(0f, 0f), false, output), Is.True);
Assert.That(output[0], Is.EqualTo(10f));
Assert.That(float.IsNaN(output[1]), Is.True);
Assert.That(profile.TryEvaluate(DirectionWithNormalizedCoordinates(0f, 0f), true, output), Is.True);
Assert.That(output[1], Is.EqualTo(20f));
}
finally
{
UnityEngine.Object.DestroyImmediate(profile);
}
}
[Test]
public void Profile_DoesNotEvaluateAnIncompleteCalibration()
{
var profile = ScriptableObject.CreateInstance<BlendshapeGazeProfile>();
try
{
profile.ReplaceChannels(new[]
{
new GazeBlendShapeChannel("eyeLookUpLeft")
});
profile.SetSample(GazeCalibrationPoint.Center, new[] { 50f });
Assert.That(
profile.TryEvaluate(
DirectionWithNormalizedCoordinates(0f, 0f),
false,
new float[1]),
Is.False);
}
finally
{
UnityEngine.Object.DestroyImmediate(profile);
}
}
private static GazeDirectionResult DirectionWithNormalizedCoordinates(float yaw, float pitch)
{
return new GazeDirectionResult(
Vector3.forward,
Vector3.forward,
0f,
0f,
0f,
0f,
yaw,
pitch);
}
}
}