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

225 lines
9.9 KiB
C#

using NUnit.Framework;
using Streamingle.Gaze.Editor;
using UnityEngine;
namespace Streamingle.Gaze.Tests
{
public sealed class GazeCalibrationPreviewSessionTests
{
[Test]
public void Session_UsesRuntimeBlendSemantics_BlocksDriverAndRestoresWeights()
{
var root = new GameObject("CalibrationPreviewSessionTest");
var mesh = CreateMesh();
var profile = ScriptableObject.CreateInstance<BlendshapeGazeProfile>();
var session = new GazeCalibrationPreviewSession();
try
{
var renderer = root.AddComponent<SkinnedMeshRenderer>();
renderer.sharedMesh = mesh;
renderer.SetBlendShapeWeight(0, 25f);
renderer.SetBlendShapeWeight(1, 30f);
renderer.SetBlendShapeWeight(2, 45f);
renderer.SetBlendShapeWeight(3, 55f);
profile.ReplaceChannels(new[]
{
new GazeBlendShapeChannel("eyeLookUpLeft"),
new GazeBlendShapeChannel(
"eyeCorrectiveAdd",
GazeChannelUsage.Corrective,
GazeCorrectiveBlendMode.AdditiveFromCenter),
new GazeBlendShapeChannel(
"eyeCorrectiveOverride",
GazeChannelUsage.Corrective,
GazeCorrectiveBlendMode.Override)
});
for (var index = 0; index < 9; index++)
{
profile.SetSample(
(GazeCalibrationPoint)index,
new[]
{
index * 10f,
10f + index * 2f,
100f - index * 5f
});
}
var driver = root.AddComponent<BlendshapeGazeDriver>();
driver.TargetRenderer = renderer;
driver.Profile = profile;
var gazeOrigin = new GameObject("GazeOrigin").transform;
gazeOrigin.SetParent(root.transform, false);
driver.GazeOrigin = gazeOrigin;
Assert.That(session.Start(driver, out var error), Is.True, error);
Assert.That(session.GetOriginalWeightsCopy(), Is.EqualTo(new[] { 25f, 30f, 45f }));
session.PreviewSample(GazeCalibrationPoint.UpRight);
Assert.That(renderer.GetBlendShapeWeight(0), Is.EqualTo(80f).Within(0.001f));
Assert.That(renderer.GetBlendShapeWeight(1), Is.EqualTo(38f).Within(0.001f));
Assert.That(renderer.GetBlendShapeWeight(2), Is.EqualTo(60f).Within(0.001f));
Assert.That(renderer.GetBlendShapeWeight(3), Is.EqualTo(55f).Within(0.001f));
session.PreviewWeights(new[] { 67f, 23f, 72f }, GazeCalibrationPoint.CenterRight);
Assert.That(session.IsFreePreview, Is.False);
Assert.That(session.PreviewCoordinates, Is.EqualTo(Vector2.right));
Assert.That(renderer.GetBlendShapeWeight(0), Is.EqualTo(67f).Within(0.001f));
Assert.That(renderer.GetBlendShapeWeight(1), Is.EqualTo(35f).Within(0.001f));
Assert.That(renderer.GetBlendShapeWeight(2), Is.EqualTo(72f).Within(0.001f));
// The four surrounding samples are deliberately distinct. At
// (0.5, -0.5), indices 1/2/4/5 contribute equally.
session.PreviewNormalized(new Vector2(0.5f, -0.5f));
Assert.That(session.IsFreePreview, Is.True);
Assert.That(renderer.GetBlendShapeWeight(0), Is.EqualTo(30f).Within(0.001f));
Assert.That(renderer.GetBlendShapeWeight(1), Is.EqualTo(28f).Within(0.001f));
Assert.That(renderer.GetBlendShapeWeight(2), Is.EqualTo(85f).Within(0.001f));
driver.SetTimelineState(1234, new GazeTimelineState
{
TargetPosition = new Vector3(1f, 0f, 1f),
HasTargetPosition = true,
Influence = 1f,
EnableCorrectives = true
});
driver.EvaluateNow(true);
Assert.That(renderer.GetBlendShapeWeight(0), Is.EqualTo(30f).Within(0.001f));
Assert.That(renderer.GetBlendShapeWeight(1), Is.EqualTo(28f).Within(0.001f));
Assert.That(renderer.GetBlendShapeWeight(2), Is.EqualTo(85f).Within(0.001f));
session.Stop();
Assert.That(renderer.GetBlendShapeWeight(0), Is.EqualTo(25f).Within(0.001f));
Assert.That(renderer.GetBlendShapeWeight(1), Is.EqualTo(30f).Within(0.001f));
Assert.That(renderer.GetBlendShapeWeight(2), Is.EqualTo(45f).Within(0.001f));
Assert.That(renderer.GetBlendShapeWeight(3), Is.EqualTo(55f).Within(0.001f));
// Releasing the session also releases the driver override. A yaw
// beyond the profile limit resolves to CenterRight (sample 5).
driver.EvaluateNow(true);
Assert.That(renderer.GetBlendShapeWeight(0), Is.EqualTo(50f).Within(0.001f));
Assert.That(renderer.GetBlendShapeWeight(1), Is.EqualTo(32f).Within(0.001f));
Assert.That(renderer.GetBlendShapeWeight(2), Is.EqualTo(75f).Within(0.001f));
}
finally
{
session.Dispose();
Object.DestroyImmediate(root);
Object.DestroyImmediate(mesh);
Object.DestroyImmediate(profile);
}
}
[Test]
public void Session_DoesNotRestoreIntoAnIndexWhoseResolvedNameChanged()
{
var root = new GameObject("CalibrationPreviewResolvedNameTest");
var mesh = CreateMesh();
var profile = ScriptableObject.CreateInstance<BlendshapeGazeProfile>();
var session = new GazeCalibrationPreviewSession();
try
{
var renderer = root.AddComponent<SkinnedMeshRenderer>();
renderer.sharedMesh = mesh;
renderer.SetBlendShapeWeight(0, 25f);
profile.ReplaceChannels(new[] { new GazeBlendShapeChannel("eyeLookUpLeft") });
for (var index = 0; index < 9; index++)
profile.SetSample((GazeCalibrationPoint)index, new[] { 80f });
var driver = root.AddComponent<BlendshapeGazeDriver>();
driver.TargetRenderer = renderer;
driver.Profile = profile;
Assert.That(session.Start(driver, out var error), Is.True, error);
session.PreviewSample(GazeCalibrationPoint.Center);
Assert.That(renderer.GetBlendShapeWeight(0), Is.EqualTo(80f).Within(0.001f));
mesh.ClearBlendShapes();
AddBlendShape(mesh, "replacementShape");
renderer.SetBlendShapeWeight(0, 66f);
session.Stop();
Assert.That(renderer.GetBlendShapeWeight(0), Is.EqualTo(66f).Within(0.001f));
}
finally
{
session.Dispose();
Object.DestroyImmediate(root);
Object.DestroyImmediate(mesh);
Object.DestroyImmediate(profile);
}
}
[Test]
public void Session_AdditiveDraftUsesOriginalWeightUntilCenterIsCaptured()
{
var root = new GameObject("CalibrationPreviewDraftCorrectiveTest");
var mesh = CreateMesh();
var profile = ScriptableObject.CreateInstance<BlendshapeGazeProfile>();
var session = new GazeCalibrationPreviewSession();
try
{
var renderer = root.AddComponent<SkinnedMeshRenderer>();
renderer.sharedMesh = mesh;
renderer.SetBlendShapeWeight(1, 30f);
profile.ReplaceChannels(new[]
{
new GazeBlendShapeChannel(
"eyeCorrectiveAdd",
GazeChannelUsage.Corrective,
GazeCorrectiveBlendMode.AdditiveFromCenter)
});
var driver = root.AddComponent<BlendshapeGazeDriver>();
driver.TargetRenderer = renderer;
driver.Profile = profile;
Assert.That(session.Start(driver, out var error), Is.True, error);
session.PreviewWeights(new[] { 42f }, GazeCalibrationPoint.UpRight);
Assert.That(renderer.GetBlendShapeWeight(1), Is.EqualTo(42f).Within(0.001f));
session.Stop();
Assert.That(renderer.GetBlendShapeWeight(1), Is.EqualTo(30f).Within(0.001f));
}
finally
{
session.Dispose();
Object.DestroyImmediate(root);
Object.DestroyImmediate(mesh);
Object.DestroyImmediate(profile);
}
}
private static Mesh CreateMesh()
{
var mesh = new Mesh { name = "CalibrationPreviewSessionMesh" };
mesh.vertices = new[]
{
new Vector3(-0.1f, 0f, 0f),
new Vector3(0.1f, 0f, 0f),
new Vector3(0f, 0.1f, 0f)
};
mesh.triangles = new[] { 0, 1, 2 };
AddBlendShape(mesh, "Face.eyeLookUpLeft");
AddBlendShape(mesh, "Face.eyeCorrectiveAdd");
AddBlendShape(mesh, "Face.eyeCorrectiveOverride");
AddBlendShape(mesh, "unrelatedFaceShape");
return mesh;
}
private static void AddBlendShape(Mesh mesh, string name)
{
mesh.AddBlendShapeFrame(
name,
100f,
new[] { Vector3.up * 0.01f, Vector3.up * 0.01f, Vector3.up * 0.01f },
new Vector3[3],
new Vector3[3]);
}
}
}