From b31a4fd3014d202a033e68d96a3c0b12421ca5d8 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Mon, 3 Sep 2018 17:15:11 +0900 Subject: [PATCH] Added BoneNormalizer.MapBoneWeight #31 --- Scripts/SkinnedMeshUtility/BoneNormalizer.cs | 117 +++++++++++++++++-- 1 file changed, 107 insertions(+), 10 deletions(-) diff --git a/Scripts/SkinnedMeshUtility/BoneNormalizer.cs b/Scripts/SkinnedMeshUtility/BoneNormalizer.cs index 90ddcbefc..6b3a68e59 100644 --- a/Scripts/SkinnedMeshUtility/BoneNormalizer.cs +++ b/Scripts/SkinnedMeshUtility/BoneNormalizer.cs @@ -85,14 +85,34 @@ namespace VRM { var src = go.GetComponent(); - var map = Enum.GetValues(typeof(HumanBodyBones)) + var srcHumanBones = Enum.GetValues(typeof(HumanBodyBones)) .Cast() .Where(x => x != HumanBodyBones.LastBone) .Select(x => new { Key = x, Value = src.GetBoneTransform(x) }) .Where(x => x.Value != null) - .ToDictionary(x => x.Key, x => boneMap[x.Value]) ; + var map = default(Dictionary); + + try + { + map= + srcHumanBones + .ToDictionary(x => x.Key, x => boneMap[x.Value]) + ; + } + catch (KeyNotFoundException) + { + foreach(var kv in srcHumanBones) + { + if (!boneMap.ContainsKey(kv.Value)) + { + Debug.LogWarningFormat("{0} not found", kv.Key); + } + } + throw; + } + var animator = normalized.AddComponent(); var vrmHuman = go.GetComponent(); var avatarDescription = AvatarDescription.Create(); @@ -151,7 +171,7 @@ namespace VRM { m_stats.Add(new BlendShapeStat { - Index =index, + Index = index, Name = name, VertexCount = v, NormalCount = n, @@ -167,6 +187,81 @@ namespace VRM } } + static BoneWeight[] MapBoneWeight(BoneWeight[] src, + Dictionary boneMap, + Transform[] srcBones, + Transform[] dstBones + ) + { + var indexMap = + srcBones + .Select((x, i) => new { i, x }) + .Select(x => dstBones.IndexOf(boneMap[x.x])) + .ToArray(); + + for(int i=0; i 0) + { + Debug.LogWarningFormat("{0} weight0 is lost", i); + dst[i].weight0 = 0; + } + + if (indexMap[x.boneIndex1] != -1) + { + dst[i].boneIndex1 = indexMap[x.boneIndex1]; + dst[i].weight1 = x.weight1; + } + else if (x.weight1 > 0) + { + Debug.LogWarningFormat("{0} weight0 is lost", i); + dst[i].weight1 = 0; + } + + if (indexMap[x.boneIndex2] != -1) + { + dst[i].boneIndex2 = indexMap[x.boneIndex2]; + dst[i].weight2 = x.weight2; + } + else if (x.weight2 > 0) + { + Debug.LogWarningFormat("{0} weight0 is lost", i); + dst[i].weight2 = 0; + } + + if (indexMap[x.boneIndex3] != -1) + { + dst[i].boneIndex3 = indexMap[x.boneIndex3]; + dst[i].weight3 = x.weight3; + } + else if (x.weight3 > 0) + { + Debug.LogWarningFormat("{0} weight0 is lost", i); + dst[i].weight3 = 0; + } + } + + return dst; + } + /// /// srcのSkinnedMeshRendererを正規化して、dstにアタッチする /// @@ -176,7 +271,7 @@ namespace VRM static void NormalizeSkinnedMesh(Transform src, Transform dst, Dictionary boneMap, bool clearBlendShape) { var srcRenderer = src.GetComponent(); - if (srcRenderer == null + if (srcRenderer == null || !srcRenderer.enabled || srcRenderer.sharedMesh == null || srcRenderer.sharedMesh.vertexCount == 0) @@ -197,8 +292,8 @@ namespace VRM } } - var bones = srcRenderer.bones.Select(x => boneMap[x]).ToArray(); - var hasBoneWeight = srcRenderer.bones!=null && srcRenderer.bones.Length > 0; + var dstBones = srcRenderer.bones.Select(x => boneMap[x]).ToArray(); + var hasBoneWeight = srcRenderer.bones != null && srcRenderer.bones.Length > 0; if (!hasBoneWeight) { // Before bake, bind no weight bones @@ -220,7 +315,7 @@ namespace VRM srcMesh.bindposes = new Matrix4x4[] { Matrix4x4.identity }; srcRenderer.rootBone = srcRenderer.transform; - bones = new[] { boneMap[srcRenderer.transform] }; + dstBones = new[] { boneMap[srcRenderer.transform] }; srcRenderer.bones = new[] { srcRenderer.transform }; srcRenderer.sharedMesh = srcMesh; } @@ -229,9 +324,11 @@ namespace VRM var mesh = srcMesh.Copy(false); mesh.name = srcMesh.name + ".baked"; srcRenderer.BakeMesh(mesh); - mesh.boneWeights = srcMesh.boneWeights; // restore weights. clear when BakeMesh + + mesh.boneWeights = MapBoneWeight(srcMesh.boneWeights, boneMap, srcRenderer.bones, dstBones); // restore weights. clear when BakeMesh + // recalc bindposes - mesh.bindposes = bones.Select(x => x.worldToLocalMatrix * dst.transform.localToWorldMatrix).ToArray(); + mesh.bindposes = dstBones.Select(x => x.worldToLocalMatrix * dst.transform.localToWorldMatrix).ToArray(); //var m = src.localToWorldMatrix; // include scaling var m = default(Matrix4x4); @@ -353,7 +450,7 @@ namespace VRM { dstRenderer.rootBone = boneMap[srcRenderer.rootBone]; } - dstRenderer.bones = bones; + dstRenderer.bones = dstBones; dstRenderer.sharedMesh = mesh; if (!hasBoneWeight)