150 lines
5.4 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|