2023-11-14 21:17:47 +08:00
|
|
|
|
using System.Linq;
|
|
|
|
|
using modular_avatar_tests;
|
2023-06-05 20:41:46 +08:00
|
|
|
|
using nadena.dev.modular_avatar.core.editor;
|
|
|
|
|
using NUnit.Framework;
|
2023-11-14 21:17:47 +08:00
|
|
|
|
using UnityEditor;
|
2023-06-05 20:41:46 +08:00
|
|
|
|
using UnityEngine;
|
2024-02-12 13:59:23 +08:00
|
|
|
|
using ModularAvatarMergeArmature = nadena.dev.modular_avatar.core.ModularAvatarMergeArmature;
|
|
|
|
|
|
|
|
|
|
#if MA_VRCSDK3_AVATARS
|
2023-11-14 21:17:47 +08:00
|
|
|
|
using VRC.SDK3.Avatars.Components;
|
|
|
|
|
using VRC.SDK3.Dynamics.PhysBone.Components;
|
2024-02-12 13:59:23 +08:00
|
|
|
|
#endif
|
2023-06-05 20:41:46 +08:00
|
|
|
|
|
|
|
|
|
public class MergeArmatureTests : TestBase
|
|
|
|
|
{
|
2023-11-14 21:17:47 +08:00
|
|
|
|
private const string SHAPELL_FBX_GUID = "1418fcab2d94f9d4982cd714b598900f";
|
|
|
|
|
|
2023-06-05 20:41:46 +08:00
|
|
|
|
[Test]
|
|
|
|
|
public void DontStripObjectsWithComponents()
|
|
|
|
|
{
|
|
|
|
|
var root = CreatePrefab("ColliderMergeTest.prefab");
|
|
|
|
|
|
|
|
|
|
AvatarProcessor.ProcessAvatar(root);
|
|
|
|
|
|
|
|
|
|
// We expect two children: Mergable and Hips$[uuid] (retained due to the BoxCollider)
|
|
|
|
|
var targetHips = root.transform.Find("TargetArmature/Hips");
|
|
|
|
|
Assert.AreEqual(2, targetHips.childCount);
|
|
|
|
|
Assert.AreEqual("Mergable", targetHips.GetChild(0).gameObject.name);
|
|
|
|
|
|
|
|
|
|
Assert.NotNull(targetHips.GetChild(1).GetComponent<BoxCollider>());
|
|
|
|
|
}
|
2023-11-14 21:17:47 +08:00
|
|
|
|
|
2024-02-12 13:59:23 +08:00
|
|
|
|
#if MA_VRCSDK3_AVATARS
|
|
|
|
|
|
2023-12-12 19:23:23 +08:00
|
|
|
|
[Test]
|
|
|
|
|
public void DontMergePartiallySamePhysBoneChain()
|
|
|
|
|
{
|
|
|
|
|
var root = CreatePrefab("PartiallySamePhysBoneChain.prefab");
|
|
|
|
|
var physBone = root.transform.Find("GameObject/PhysBone").GetComponent<VRCPhysBone>();
|
|
|
|
|
var physBoneTarget = root.transform.Find("GameObject/Armature (1)/L_1");
|
|
|
|
|
|
|
|
|
|
AvatarProcessor.ProcessAvatar(root);
|
|
|
|
|
|
|
|
|
|
var targetHips = root.transform.Find("Armature");
|
|
|
|
|
|
|
|
|
|
Assert.AreEqual(2, targetHips.childCount);
|
|
|
|
|
Assert.AreEqual("L_1", targetHips.GetChild(0).gameObject.name);
|
|
|
|
|
Assert.That(targetHips.GetChild(1).gameObject.name, Does.StartWith("L_1$"));
|
|
|
|
|
|
|
|
|
|
Assert.That(targetHips.GetChild(1), Is.EqualTo(physBoneTarget));
|
|
|
|
|
Assert.That(physBone.ignoreTransforms, Is.Empty);
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-14 21:17:47 +08:00
|
|
|
|
[Test]
|
|
|
|
|
public void PhysBonesNRETest()
|
|
|
|
|
{
|
|
|
|
|
var root = LoadShapell();
|
|
|
|
|
var avdesc = root.AddComponent<VRCAvatarDescriptor>();
|
|
|
|
|
avdesc.baseAnimationLayers = new VRCAvatarDescriptor.CustomAnimLayer[0];
|
|
|
|
|
avdesc.specialAnimationLayers = new VRCAvatarDescriptor.CustomAnimLayer[0];
|
|
|
|
|
|
|
|
|
|
var outfit1 = LoadShapell();
|
|
|
|
|
outfit1.transform.SetParent(root.transform, false);
|
|
|
|
|
|
|
|
|
|
var outfit2 = LoadShapell();
|
|
|
|
|
outfit2.transform.SetParent(root.transform, false);
|
|
|
|
|
|
|
|
|
|
var outfit1_hips = outfit1.transform.Find("Armature/Hips");
|
|
|
|
|
var outfit2_hips = outfit2.transform.Find("Armature/Hips");
|
|
|
|
|
var root_hips = root.transform.Find("Armature/Hips");
|
|
|
|
|
|
|
|
|
|
root_hips.gameObject.AddComponent<VRCPhysBone>();
|
|
|
|
|
outfit1_hips.gameObject.AddComponent<VRCPhysBone>();
|
|
|
|
|
outfit2_hips.gameObject.AddComponent<VRCPhysBone>();
|
|
|
|
|
|
|
|
|
|
var root_smr = root.transform.Find("Body").gameObject.GetComponent<SkinnedMeshRenderer>();
|
|
|
|
|
var outfit1_smr = outfit1.transform.Find("Body").gameObject.GetComponent<SkinnedMeshRenderer>();
|
|
|
|
|
var outfit2_smr = outfit2.transform.Find("Body").gameObject.GetComponent<SkinnedMeshRenderer>();
|
|
|
|
|
|
|
|
|
|
outfit1.transform.Find("Armature").gameObject.AddComponent<ModularAvatarMergeArmature>().mergeTarget.Set(
|
|
|
|
|
root.transform.Find("Armature").gameObject
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
outfit2.transform.Find("Armature").gameObject.AddComponent<ModularAvatarMergeArmature>().mergeTarget.Set(
|
|
|
|
|
root.transform.Find("Armature").gameObject
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
AvatarProcessor.ProcessAvatar(root);
|
|
|
|
|
|
|
|
|
|
foreach (var (root_bone, outfit_bone) in Enumerable.Zip(root_smr.bones, outfit1_smr.bones, (x, y) => (x, y)))
|
|
|
|
|
{
|
|
|
|
|
Assert.AreSame(root_bone, outfit_bone);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var (root_bone, outfit_bone) in Enumerable.Zip(root_smr.bones, outfit2_smr.bones, (x, y) => (x, y)))
|
|
|
|
|
{
|
|
|
|
|
Assert.AreSame(root_bone, outfit_bone);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-12 13:59:23 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
2023-11-14 21:17:47 +08:00
|
|
|
|
private static GameObject LoadShapell()
|
|
|
|
|
{
|
|
|
|
|
return GameObject.Instantiate(
|
|
|
|
|
AssetDatabase.LoadAssetAtPath<GameObject>(
|
|
|
|
|
AssetDatabase.GUIDToAssetPath(SHAPELL_FBX_GUID)
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
}
|
2023-06-05 20:41:46 +08:00
|
|
|
|
}
|