Skip to content

Commit

Permalink
Merge pull request #642 from anatawa12/write-tests
Browse files Browse the repository at this point in the history
Write tests
  • Loading branch information
anatawa12 authored Nov 3, 2023
2 parents aa3fcf8 + d3453b9 commit c8d315e
Show file tree
Hide file tree
Showing 8 changed files with 268 additions and 2 deletions.
1 change: 1 addition & 0 deletions Editor/ObjectMapping/ObjectMappingContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ private Object CustomClone(Object o)
newMask.SetTransformActive(dstI, mask.GetTransformActive(srcI));
dstI++;
}
if (path != newPath) _mapped = true;
}
newMask.transformCount = dstI;

Expand Down
2 changes: 1 addition & 1 deletion Editor/Processors/MergeBoneProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ public override int GetHashCode() =>
}


struct MergeBoneTransParentInfo
public struct MergeBoneTransParentInfo
{
public Quaternion ParentRotation;
public Matrix4x4 ParentMatrix;
Expand Down
126 changes: 126 additions & 0 deletions Test~/ApplyObjectMappingTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
using NUnit.Framework;
using UnityEditor;
using UnityEditor.Animations;
using UnityEngine;

namespace Anatawa12.AvatarOptimizer.Test
{
public class ApplyObjectMappingTest
{
[Test]
public void AvatarMask()
{
var root = new GameObject();
var child1 = Utils.NewGameObject("child1", root.transform);
var child11 = Utils.NewGameObject("child11", child1.transform);
var builder = new ObjectMappingBuilder(root);

child11.name = "child12";

var built = builder.BuildObjectMapping();

var rootMapper = new AnimatorControllerMapper(built.CreateAnimationMapper(root));

var avatarMask = new AvatarMask();
avatarMask.transformCount = 1;
avatarMask.SetHumanoidBodyPartActive(AvatarMaskBodyPart.Head, true);
avatarMask.SetHumanoidBodyPartActive(AvatarMaskBodyPart.LeftLeg, false);
avatarMask.SetTransformPath(0, "child1/child11");

var animatorController = new AnimatorController();
animatorController.AddLayer(new AnimatorControllerLayer()
{
name = "layer",
avatarMask = avatarMask,
stateMachine = new AnimatorStateMachine() { name = "layer" },
});

var mappedController = rootMapper.MapAnimatorController(animatorController);
Assert.That(mappedController, Is.Not.EqualTo(animatorController));
Assert.That(mappedController.layers[0].avatarMask.GetTransformPath(0),
Is.EqualTo("child1/child12"));
Assert.That(avatarMask.GetHumanoidBodyPartActive(AvatarMaskBodyPart.Head), Is.True);
Assert.That(avatarMask.GetHumanoidBodyPartActive(AvatarMaskBodyPart.LeftLeg), Is.False);
}

[Test]
public void PreserveAnimationLength()
{
var root = new GameObject();
var child1 = Utils.NewGameObject("child1", root.transform);
var child11 = Utils.NewGameObject("child11", child1.transform);
var builder = new ObjectMappingBuilder(root);

Object.DestroyImmediate(child11);

var built = builder.BuildObjectMapping();

var rootMapper = new AnimatorControllerMapper(built.CreateAnimationMapper(root));

var animatorController = new AnimatorController();
var layer = new AnimatorControllerLayer()
{
name = "layer",
stateMachine = new AnimatorStateMachine() { name = "layer" },
};
var state = layer.stateMachine.AddState("theState");
var clip = new AnimationClip();
clip.SetCurve("child1/child11", typeof(GameObject), "m_IsActive", AnimationCurve.Constant(0, 0.3f, 1));
state.motion = clip;
animatorController.AddLayer(layer);

var mappedController = rootMapper.MapAnimatorController(animatorController);
Assert.That(mappedController, Is.Not.EqualTo(animatorController));
var mappedClip = mappedController.layers[0].stateMachine.states[0].state.motion as AnimationClip;
Assert.That(mappedClip, Is.Not.Null);

Assert.That(mappedClip.length, Is.EqualTo(0.3f));
Assert.That(AnimationUtility.GetCurveBindings(mappedClip)[0].path,
Contains.Substring("AvatarOptimizerClipLengthDummy"));
}

[Test]
public void PreserveProxyAnimation()
{
var root = new GameObject();
var child1 = Utils.NewGameObject("child1", root.transform);
var child11 = Utils.NewGameObject("child11", child1.transform);
var builder = new ObjectMappingBuilder(root);

Object.DestroyImmediate(child11);

var built = builder.BuildObjectMapping();

var rootMapper = new AnimatorControllerMapper(built.CreateAnimationMapper(root));

var animatorController = new AnimatorController();
var layer = new AnimatorControllerLayer()
{
name = "layer",
stateMachine = new AnimatorStateMachine() { name = "layer" },
};
var state = layer.stateMachine.AddState("theState");
var clip = new AnimationClip();
clip.SetCurve("child1/child11", typeof(GameObject), "m_IsActive", AnimationCurve.Constant(0, 0.3f, 1));
state.motion = clip;

var proxyMotion =
AssetDatabase.LoadAssetAtPath<AnimationClip>(
AssetDatabase.GUIDToAssetPath("806c242c97b686d4bac4ad50defd1fdb"));
state = layer.stateMachine.AddState("afk");
state.motion = proxyMotion;

animatorController.AddLayer(layer);

var mappedController = rootMapper.MapAnimatorController(animatorController);
Assert.That(mappedController, Is.Not.EqualTo(animatorController));

// ensure non-proxy mapped
var mappedClip = mappedController.layers[0].stateMachine.states[0].state.motion as AnimationClip;
Assert.That(mappedClip, Is.Not.EqualTo(clip));

mappedClip = mappedController.layers[0].stateMachine.states[1].state.motion as AnimationClip;
Assert.That(mappedClip, Is.EqualTo(proxyMotion));
}
}
}
3 changes: 3 additions & 0 deletions Test~/ApplyObjectMappingTest.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 34 additions & 0 deletions Test~/MergeBoneTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Anatawa12.AvatarOptimizer.Processors;
using NUnit.Framework;
using UnityEngine;

namespace Anatawa12.AvatarOptimizer.Test
{
public class MergeBoneTest
{
[Test]
public void ExtremeSmall()
{
var epsilonVector3 = new Vector3(float.Epsilon, float.Epsilon, float.Epsilon);
var root = TestUtils.NewAvatar();
var merged = Utils.NewGameObject("merged", root.transform);
merged.transform.localScale = epsilonVector3;

var identity = Utils.NewGameObject("identity", merged.transform);
var moved = Utils.NewGameObject("moved", merged.transform);
moved.transform.localPosition = Vector3.one;

var transInfo = MergeBoneProcessor.MergeBoneTransParentInfo.Compute(merged.transform, root.transform);

var identityAfter = transInfo.ComputeInfoFor(identity.transform);
Assert.That(identityAfter.scale, Is.EqualTo(epsilonVector3));
Assert.That(identityAfter.position, Is.EqualTo(Vector3.zero));
Assert.That(identityAfter.rotation, Is.EqualTo(Quaternion.identity));

var movedAfter = transInfo.ComputeInfoFor(moved.transform);
Assert.That(movedAfter.scale, Is.EqualTo(epsilonVector3));
Assert.That(movedAfter.position, Is.EqualTo(epsilonVector3));
Assert.That(movedAfter.rotation, Is.EqualTo(Quaternion.identity));
}
}
}
3 changes: 3 additions & 0 deletions Test~/MergeBoneTest.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

98 changes: 98 additions & 0 deletions Test~/MeshInfo2/MeshInfo2Test.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using Anatawa12.AvatarOptimizer.Processors.SkinnedMeshes;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.Rendering;

namespace Anatawa12.AvatarOptimizer.Test
{
Expand Down Expand Up @@ -95,5 +97,101 @@ public void RootBoneWithNoneMeshSkinnedMeshRenderer()
var meshInfo2 = new MeshInfo2(smr);
Assert.That(meshInfo2.RootBone, Is.EqualTo(secondGo.transform));
}

[Test]
public void MultiFrameBlendShapeWithPartiallyIdentity()
{
var mesh = BoxMesh();
var deltas = new Vector3[8];
deltas.AsSpan().Fill(new Vector3(1, 2, 3));
mesh.AddBlendShapeFrame("shape", 0, new Vector3[8], null, null);
mesh.AddBlendShapeFrame("shape", 1, new Vector3[8], null, null);
mesh.AddBlendShapeFrame("shape", 2, new Vector3[8], null, null);
mesh.AddBlendShapeFrame("shape", 3, deltas, null, null);
mesh.AddBlendShapeFrame("shape", 4, new Vector3[8], null, null);

var go = new GameObject();
var smr = go.AddComponent<SkinnedMeshRenderer>();
smr.sharedMesh = mesh;

var meshInfo2 = new MeshInfo2(smr);

foreach (var vertex in meshInfo2.Vertices)
{
var frames = vertex.BlendShapes["shape"];
Assert.That(frames.Length, Is.EqualTo(5));
for (var i = 0; i < frames.Length; i++)
{
Assert.That(frames[i].Weight, Is.EqualTo((float)i));
Assert.That(frames[i].Position, Is.EqualTo(i == 3 ? new Vector3(1, 2, 3) : new Vector3()));
}
}
}

[Test]
public void BlendShapeWithFrameAtZero()
{
var mesh = BoxMesh();
var deltas = new Vector3[8];
deltas.AsSpan().Fill(new Vector3(1, 2, 3));
mesh.AddBlendShapeFrame("shape", 0, deltas, null, null);
mesh.AddBlendShapeFrame("shape", 1, deltas, null, null);

var go = new GameObject();
var smr = go.AddComponent<SkinnedMeshRenderer>();
smr.sharedMesh = mesh;

var meshInfo2 = new MeshInfo2(smr);

Vector3 position;
var vertex = meshInfo2.Vertices[0];
Assert.That(vertex.TryGetBlendShape("shape", 0, out position, out _, out _), Is.True);
Assert.That(position, Is.EqualTo(new Vector3(0, 0, 0)));

Assert.That(vertex.TryGetBlendShape("shape", 0, out position, out _, out _, getDefined: true), Is.True);
Assert.That(position, Is.EqualTo(new Vector3(1, 2, 3)));
}

private Mesh BoxMesh()
{
var mesh = new Mesh
{
vertices = new[]
{
new Vector3(-1, -1, -1),
new Vector3(+1, -1, -1),
new Vector3(-1, +1, -1),
new Vector3(+1, +1, -1),
new Vector3(-1, -1, +1),
new Vector3(+1, -1, +1),
new Vector3(-1, +1, +1),
new Vector3(+1, +1, +1),
},
triangles = new[]
{
0, 1, 2,
1, 3, 2,

4, 6, 5,
5, 6, 7,

0, 4, 1,

1, 4, 5,
1, 5, 3,

3, 5, 7,
3, 7, 2,

2, 7, 6,
2, 6, 0,
},
};

mesh.subMeshCount = 1;
mesh.SetSubMesh(0, new SubMeshDescriptor(0, mesh.triangles.Length));

return mesh;
}
}
}
3 changes: 2 additions & 1 deletion Test~/com.anatawa12.avatar-optimizer.test.asmdef
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"VRC.SDK3.Dynamics.PhysBone.dll",
"VRC.Dynamics.dll",
"VRCSDK3A.dll",
"VRCSDKBase.dll"
"VRCSDKBase.dll",
"System.Memory.dll"
],
"autoReferenced": false,
"defineConstraints": [],
Expand Down

0 comments on commit c8d315e

Please sign in to comment.