228 lines
8.8 KiB
C#
228 lines
8.8 KiB
C#
using System.Reflection;
|
|
using NUnit.Framework;
|
|
using UnityEngine;
|
|
|
|
namespace Streamingle.Gaze.Tests
|
|
{
|
|
public sealed class GazeProfileAuthoringTests
|
|
{
|
|
private static readonly string[] StandardChannels =
|
|
{
|
|
"eyeLookUpLeft",
|
|
"eyeLookUpRight",
|
|
"eyeLookDownLeft",
|
|
"eyeLookDownRight",
|
|
"eyeLookInLeft",
|
|
"eyeLookInRight",
|
|
"eyeLookOutLeft",
|
|
"eyeLookOutRight"
|
|
};
|
|
|
|
[Test]
|
|
public void SeedStandardEyeLook_CreatesFivePointsAndFourCorners()
|
|
{
|
|
var profile = CreateStandardProfile();
|
|
try
|
|
{
|
|
Assert.That(profile.SeedStandardEyeLook(80f), Is.True);
|
|
for (var index = 0; index < 9; index++)
|
|
Assert.That(profile.IsSampleCaptured((GazeCalibrationPoint)index), Is.True);
|
|
|
|
Assert.That(
|
|
profile.GetSampleWeightsCopy(GazeCalibrationPoint.Center),
|
|
Is.EqualTo(new[] { 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f }));
|
|
Assert.That(
|
|
profile.GetSampleWeightsCopy(GazeCalibrationPoint.CenterLeft),
|
|
Is.EqualTo(new[] { 0f, 0f, 0f, 0f, 0f, 80f, 80f, 0f }));
|
|
Assert.That(
|
|
profile.GetSampleWeightsCopy(GazeCalibrationPoint.UpRight),
|
|
Is.EqualTo(new[] { 80f, 80f, 0f, 0f, 80f, 0f, 0f, 80f }));
|
|
}
|
|
finally
|
|
{
|
|
Object.DestroyImmediate(profile);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void GenerateCorners_CombinesCardinalDeltasAndClampsByUsage()
|
|
{
|
|
var profile = ScriptableObject.CreateInstance<BlendshapeGazeProfile>();
|
|
try
|
|
{
|
|
profile.ReplaceChannels(new[]
|
|
{
|
|
new GazeBlendShapeChannel("eyeLookUpLeft"),
|
|
new GazeBlendShapeChannel("eyeLidCorrective", GazeChannelUsage.Corrective)
|
|
});
|
|
profile.SetSample(GazeCalibrationPoint.Center, new[] { 80f, 0f });
|
|
profile.SetSample(GazeCalibrationPoint.CenterLeft, new[] { 100f, 100f });
|
|
profile.SetSample(GazeCalibrationPoint.CenterRight, new[] { 0f, -100f });
|
|
profile.SetSample(GazeCalibrationPoint.UpCenter, new[] { 100f, 100f });
|
|
profile.SetSample(GazeCalibrationPoint.DownCenter, new[] { 0f, -100f });
|
|
|
|
Assert.That(profile.CanGenerateCorners, Is.True);
|
|
Assert.That(profile.GenerateCornersFromCardinals(), Is.True);
|
|
Assert.That(
|
|
profile.GetSampleWeightsCopy(GazeCalibrationPoint.UpLeft),
|
|
Is.EqualTo(new[] { 100f, 100f }));
|
|
Assert.That(
|
|
profile.GetSampleWeightsCopy(GazeCalibrationPoint.DownRight),
|
|
Is.EqualTo(new[] { 0f, -100f }));
|
|
}
|
|
finally
|
|
{
|
|
Object.DestroyImmediate(profile);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void GenerateCorners_UsesCardinalDeltasRelativeToCenter()
|
|
{
|
|
var profile = ScriptableObject.CreateInstance<BlendshapeGazeProfile>();
|
|
try
|
|
{
|
|
profile.ReplaceChannels(new[]
|
|
{
|
|
new GazeBlendShapeChannel("eyeLookTest")
|
|
});
|
|
profile.SetSample(GazeCalibrationPoint.Center, new[] { 10f });
|
|
profile.SetSample(GazeCalibrationPoint.CenterLeft, new[] { 30f });
|
|
profile.SetSample(GazeCalibrationPoint.CenterRight, new[] { 10f });
|
|
profile.SetSample(GazeCalibrationPoint.UpCenter, new[] { 40f });
|
|
profile.SetSample(GazeCalibrationPoint.DownCenter, new[] { 10f });
|
|
|
|
Assert.That(profile.GenerateCornersFromCardinals(), Is.True);
|
|
Assert.That(
|
|
profile.GetSampleWeight(GazeCalibrationPoint.UpLeft, 0),
|
|
Is.EqualTo(60f));
|
|
}
|
|
finally
|
|
{
|
|
Object.DestroyImmediate(profile);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void DirectionLimits_SanitizeNonFiniteValuesAndClampToSupportedRanges()
|
|
{
|
|
var profile = ScriptableObject.CreateInstance<BlendshapeGazeProfile>();
|
|
try
|
|
{
|
|
profile.SetDirectionLimits(
|
|
float.NaN,
|
|
float.PositiveInfinity,
|
|
float.NegativeInfinity,
|
|
float.NaN);
|
|
|
|
Assert.That(profile.MinYaw, Is.EqualTo(-35f));
|
|
Assert.That(profile.MaxYaw, Is.EqualTo(35f));
|
|
Assert.That(profile.MinPitch, Is.EqualTo(-25f));
|
|
Assert.That(profile.MaxPitch, Is.EqualTo(20f));
|
|
|
|
profile.SetDirectionLimits(-180f, -5f, 10f, 180f);
|
|
|
|
Assert.That(profile.MinYaw, Is.EqualTo(-90f));
|
|
Assert.That(profile.MaxYaw, Is.EqualTo(0.1f));
|
|
Assert.That(profile.MinPitch, Is.EqualTo(-0.1f));
|
|
Assert.That(profile.MaxPitch, Is.EqualTo(90f));
|
|
|
|
SetPrivateField(profile, "minYaw", float.PositiveInfinity);
|
|
SetPrivateField(profile, "maxYaw", float.NegativeInfinity);
|
|
SetPrivateField(profile, "minPitch", float.NaN);
|
|
SetPrivateField(profile, "maxPitch", float.NaN);
|
|
InvokeOnValidate(profile);
|
|
|
|
Assert.That(profile.MinYaw, Is.EqualTo(-35f));
|
|
Assert.That(profile.MaxYaw, Is.EqualTo(35f));
|
|
Assert.That(profile.MinPitch, Is.EqualTo(-25f));
|
|
Assert.That(profile.MaxPitch, Is.EqualTo(20f));
|
|
}
|
|
finally
|
|
{
|
|
Object.DestroyImmediate(profile);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void CopySample_WithMirrorSwapsLeftAndRightChannels()
|
|
{
|
|
var profile = CreateStandardProfile();
|
|
try
|
|
{
|
|
profile.SetSample(
|
|
GazeCalibrationPoint.CenterLeft,
|
|
new[] { 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f });
|
|
|
|
Assert.That(
|
|
profile.CopySample(
|
|
GazeCalibrationPoint.CenterLeft,
|
|
GazeCalibrationPoint.CenterRight,
|
|
true),
|
|
Is.True);
|
|
Assert.That(
|
|
profile.GetSampleWeightsCopy(GazeCalibrationPoint.CenterRight),
|
|
Is.EqualTo(new[] { 2f, 1f, 4f, 3f, 6f, 5f, 8f, 7f }));
|
|
}
|
|
finally
|
|
{
|
|
Object.DestroyImmediate(profile);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void SetSample_RejectsNonFiniteWeights()
|
|
{
|
|
var profile = ScriptableObject.CreateInstance<BlendshapeGazeProfile>();
|
|
try
|
|
{
|
|
profile.ReplaceChannels(new[]
|
|
{
|
|
new GazeBlendShapeChannel("eyeLookUpLeft")
|
|
});
|
|
|
|
Assert.Throws<System.ArgumentException>(() =>
|
|
profile.SetSample(GazeCalibrationPoint.Center, new[] { float.NaN }));
|
|
Assert.Throws<System.ArgumentException>(() =>
|
|
profile.SetSample(GazeCalibrationPoint.Center, new[] { float.PositiveInfinity }));
|
|
Assert.That(profile.IsSampleCaptured(GazeCalibrationPoint.Center), Is.False);
|
|
}
|
|
finally
|
|
{
|
|
Object.DestroyImmediate(profile);
|
|
}
|
|
}
|
|
|
|
private static BlendshapeGazeProfile CreateStandardProfile()
|
|
{
|
|
var profile = ScriptableObject.CreateInstance<BlendshapeGazeProfile>();
|
|
var channels = new GazeBlendShapeChannel[StandardChannels.Length];
|
|
for (var index = 0; index < channels.Length; index++)
|
|
channels[index] = new GazeBlendShapeChannel(StandardChannels[index]);
|
|
profile.ReplaceChannels(channels);
|
|
return profile;
|
|
}
|
|
|
|
private static void SetPrivateField(
|
|
BlendshapeGazeProfile profile,
|
|
string fieldName,
|
|
float value)
|
|
{
|
|
var field = typeof(BlendshapeGazeProfile).GetField(
|
|
fieldName,
|
|
BindingFlags.Instance | BindingFlags.NonPublic);
|
|
Assert.That(field, Is.Not.Null, $"Expected private field '{fieldName}'.");
|
|
field.SetValue(profile, value);
|
|
}
|
|
|
|
private static void InvokeOnValidate(BlendshapeGazeProfile profile)
|
|
{
|
|
var method = typeof(BlendshapeGazeProfile).GetMethod(
|
|
"OnValidate",
|
|
BindingFlags.Instance | BindingFlags.NonPublic);
|
|
Assert.That(method, Is.Not.Null, "Expected private OnValidate method.");
|
|
method.Invoke(profile, null);
|
|
}
|
|
}
|
|
}
|