diff --git a/Assets/VRM/UniVRM/Editor/Tests/NormalizeTests.cs b/Assets/VRM/UniVRM/Editor/Tests/NormalizeTests.cs new file mode 100644 index 000000000..51510cfb7 --- /dev/null +++ b/Assets/VRM/UniVRM/Editor/Tests/NormalizeTests.cs @@ -0,0 +1,89 @@ +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using UnityEngine; + +namespace VRM +{ + public class NormalizeTests + { + class BoneMap + { + public List SrcBones = new List(); + public List DstBones = new List(); + public Dictionary Map = new Dictionary(); + + public void Add(GameObject src, GameObject dst) + { + SrcBones.Add(src?.transform); + if (dst != null) + { + DstBones.Add(dst.transform); + } + if (src != null) + { + Map.Add(src?.transform, dst?.transform); + } + } + + public IEnumerable CreateBoneWeight(int vertexCount) + { + int j = 0; + for (int i = 0; i < vertexCount; ++i) + { + yield return new BoneWeight + { + boneIndex0 = j++, + boneIndex1 = j++, + boneIndex2 = j++, + boneIndex3 = j++, + weight0 = 0.25f, + weight1 = 0.25f, + weight2 = 0.25f, + weight3 = 0.25f, + }; + } + } + } + + [Test] + public void MapBoneWeightTest() + { + { + var map = new BoneMap(); + map.Add(new GameObject("a"), new GameObject("A")); + map.Add(new GameObject("b"), new GameObject("B")); + map.Add(new GameObject("c"), new GameObject("C")); + map.Add(new GameObject("d"), new GameObject("D")); + map.Add(null, new GameObject("null")); + // map.Add(new GameObject("c"), null); // ありえないので Exception にしてある + var boneWeights = map.CreateBoneWeight(64).ToArray(); + var newBoneWeight = BoneNormalizer.MapBoneWeight(boneWeights, map.Map, + map.SrcBones.ToArray(), map.DstBones.ToArray()); + + // 正常系 + // exception が出なければよい + } + + { + var map = new BoneMap(); + map.Add(new GameObject("a"), new GameObject("A")); + map.Add(new GameObject("b"), new GameObject("B")); + map.Add(new GameObject("c"), new GameObject("C")); + map.Add(new GameObject("d"), new GameObject("D")); + map.Add(null, new GameObject("null")); + // map.Add(new GameObject("c"), null); // ありえないので Exception にしてある + var boneWeights = map.CreateBoneWeight(64).ToArray(); + var newBoneWeight = BoneNormalizer.MapBoneWeight(boneWeights, map.Map, + map.SrcBones.ToArray(), map.DstBones.ToArray()); + + // 4 つめが 0 になる + Assert.AreEqual(0, newBoneWeight[1].boneIndex0); + Assert.AreEqual(0, newBoneWeight[1].weight0); + // 5 つめ以降が 0 になる。out of range + Assert.AreEqual(0, newBoneWeight[1].boneIndex1); + Assert.AreEqual(0, newBoneWeight[1].weight1); + } + } + } +} diff --git a/Assets/VRM/UniVRM/Editor/Tests/NormalizeTests.cs.meta b/Assets/VRM/UniVRM/Editor/Tests/NormalizeTests.cs.meta new file mode 100644 index 000000000..b3822bbd4 --- /dev/null +++ b/Assets/VRM/UniVRM/Editor/Tests/NormalizeTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4014814a6ed5bf84faa36c7b99d6d4b8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/BoneNormalizer.cs b/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/BoneNormalizer.cs index 609549912..b4b51ee25 100644 --- a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/BoneNormalizer.cs +++ b/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/BoneNormalizer.cs @@ -181,6 +181,13 @@ namespace VRM /// static bool CopyOrDropWeight(int[] indexMap, int srcIndex, float weight, Action setter) { + if (srcIndex < 0 || srcIndex >= indexMap.Length) + { + // ありえるかどうかわからないが BoneWeight.boneIndexN に変な値が入っている. + setter(0, 0); + return false; + } + var dstIndex = indexMap[srcIndex]; if (dstIndex != -1) { @@ -204,7 +211,7 @@ namespace VRM /// 変更前のボーン配列 /// 変更後のボーン配列。除去されたボーンがある場合、変更前より短い /// - static BoneWeight[] MapBoneWeight(BoneWeight[] src, + public static BoneWeight[] MapBoneWeight(BoneWeight[] src, Dictionary boneMap, Transform[] srcBones, Transform[] dstBones