diff --git a/Assets/VRM/UniVRM/Editor/Format/RecordDisposer.cs b/Assets/VRM/UniVRM/Editor/Format/RecordDisposer.cs index a824ac8bc..cc3f0557d 100644 --- a/Assets/VRM/UniVRM/Editor/Format/RecordDisposer.cs +++ b/Assets/VRM/UniVRM/Editor/Format/RecordDisposer.cs @@ -1,11 +1,13 @@ using System; -using System.Collections.Generic; -using System.Linq; using UnityEditor; -using UnityEngine; namespace VRM { + /// + /// UndoをGroupを開始して、DisposeでUndoする。 + /// using で使うのを想定。 + /// using ブロック内で Undo されるべき操作をする。 + /// public struct RecordDisposer : IDisposable { int _group; @@ -20,128 +22,5 @@ namespace VRM { Undo.RevertAllDownToGroup(_group); } - - /// - /// VRMを構成するコンポーネントをコピーする。 - /// - /// コピー元 - /// コピー先 - /// コピー元とコピー先の対応関係 - public static void CopyVRMComponents(GameObject go, GameObject root, - Dictionary map) - { - { - // blendshape - var src = go.GetComponent(); - if (src != null) - { - var dst = root.AddComponent(); - dst.BlendShapeAvatar = src.BlendShapeAvatar; - } - } - - { - var secondary = go.transform.Find("secondary"); - if (secondary == null) - { - secondary = go.transform; - } - - var dstSecondary = root.transform.Find("secondary"); - if (dstSecondary == null) - { - dstSecondary = new GameObject("secondary").transform; - dstSecondary.SetParent(root.transform, false); - } - - // 揺れモノ - foreach (var src in go.transform.GetComponentsInChildren()) - { - var dst = map[src.transform]; - var dstColliderGroup = dst.gameObject.AddComponent(); - dstColliderGroup.Colliders = src.Colliders.Select(y => - { - var offset = dst.worldToLocalMatrix.MultiplyPoint(src.transform.localToWorldMatrix.MultiplyPoint(y.Offset)); - return new VRMSpringBoneColliderGroup.SphereCollider - { - Offset = offset, - Radius = y.Radius - }; - }).ToArray(); - } - - foreach (var src in go.transform.GetComponentsInChildren()) - { - // Copy VRMSpringBone - var dst = dstSecondary.gameObject.AddComponent(); - dst.m_comment = src.m_comment; - dst.m_stiffnessForce = src.m_stiffnessForce; - dst.m_gravityPower = src.m_gravityPower; - dst.m_gravityDir = src.m_gravityDir; - dst.m_dragForce = src.m_dragForce; - if (src.m_center != null) - { - dst.m_center = map[src.m_center]; - } - - dst.RootBones = src.RootBones.Select(x => map[x]).ToList(); - dst.m_hitRadius = src.m_hitRadius; - if (src.ColliderGroups != null) - { - dst.ColliderGroups = src.ColliderGroups - .Select(x => map[x.transform].GetComponent()).ToArray(); - } - } - } - -#pragma warning disable 0618 - { - // meta(obsolete) - var src = go.GetComponent(); - if (src != null) - { - src.CopyTo(root); - } - } -#pragma warning restore 0618 - - { - // meta - var src = go.GetComponent(); - if (src != null) - { - var dst = root.AddComponent(); - dst.Meta = src.Meta; - } - } - - { - // firstPerson - var src = go.GetComponent(); - if (src != null) - { - src.CopyTo(root, map); - } - } - - { - // humanoid - var dst = root.AddComponent(); - var src = go.GetComponent(); - if (src != null) - { - dst.Avatar = src.Avatar; - dst.Description = src.Description; - } - else - { - var animator = go.GetComponent(); - if (animator != null) - { - dst.Avatar = animator.avatar; - } - } - } - } } } diff --git a/Assets/VRM/UniVRM/Editor/Format/VRMEditorExporter.cs b/Assets/VRM/UniVRM/Editor/Format/VRMEditorExporter.cs index 0386f89eb..98f7ddac9 100644 --- a/Assets/VRM/UniVRM/Editor/Format/VRMEditorExporter.cs +++ b/Assets/VRM/UniVRM/Editor/Format/VRMEditorExporter.cs @@ -86,7 +86,7 @@ namespace VRM var normals = new Vector3[vCount]; var tangents = new Vector3[vCount]; mesh.GetBlendShapeFrameVertices(i, 0, vertices, normals, tangents); - + copyMesh.AddBlendShapeFrame(name, 100f, vertices, normals, tangents); } @@ -109,28 +109,26 @@ namespace VRM smr.sharedMesh = copyMesh; } + /// + /// + /// + /// + /// + /// 作業が終わったらDestoryするべき一時オブジェクト static void Export(string path, VRMExportSettings settings, List destroy) { var target = settings.Source; - if (IsPrefab(target)) - { - using (new RecordDisposer(settings.Source.transform.Traverse().ToArray(), "before normalize")) - { - target = GameObject.Instantiate(target); - destroy.Add(target); - } - } + + // 常にコピーする。シーンを変化させない + target = GameObject.Instantiate(target); + destroy.Add(target); // 正規化 if (settings.PoseFreeze) { - using (new RecordDisposer(target.transform.Traverse().ToArray(), "before normalize")) - { - var normalized = BoneNormalizer.Execute(target, settings.ForceTPose, false); - RecordDisposer.CopyVRMComponents(target, normalized.Root, normalized.BoneMap); - target = normalized.Root; - destroy.Add(target); - } + // BoneNormalizer.Execute は Copy を作って正規化する。UNDO無用 + target = BoneNormalizer.Execute(target, settings.ForceTPose, false); + destroy.Add(target); } // 元のBlendShapeClipに変更を加えないように複製 diff --git a/Assets/VRM/UniVRM/Editor/Format/VRMHumanoidNormalizerMenu.cs b/Assets/VRM/UniVRM/Editor/Format/VRMHumanoidNormalizerMenu.cs index fbb6d8a32..b02b6ce4e 100644 --- a/Assets/VRM/UniVRM/Editor/Format/VRMHumanoidNormalizerMenu.cs +++ b/Assets/VRM/UniVRM/Editor/Format/VRMHumanoidNormalizerMenu.cs @@ -48,14 +48,8 @@ namespace VRM { var go = Selection.activeObject as GameObject; - GameObject normalizedRoot = null; - using (new RecordDisposer(go.transform.Traverse().ToArray(), "before normalize")) - { - var normalized = BoneNormalizer.Execute(go, true, false); - RecordDisposer.CopyVRMComponents(go, normalized.Root, normalized.BoneMap); - normalizedRoot = normalized.Root; - } - Selection.activeGameObject = normalizedRoot; + // BoneNormalizer.Execute はコピーを正規化する。UNDO無用 + Selection.activeGameObject = BoneNormalizer.Execute(go, true, false); } } } diff --git a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/BoneNormalizer.cs b/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/BoneNormalizer.cs index 513ed38dd..295561774 100644 --- a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/BoneNormalizer.cs +++ b/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/BoneNormalizer.cs @@ -181,9 +181,10 @@ namespace VRM var indexMap = srcBones .Select((x, i) => new { i, x }) - .Select(x => { + .Select(x => + { Transform dstBone; - if(boneMap.TryGetValue(x.x, out dstBone)) + if (boneMap.TryGetValue(x.x, out dstBone)) { return dstBones.IndexOf(dstBone); } @@ -191,7 +192,7 @@ namespace VRM { return -1; } - }) + }) .ToArray(); for (int i = 0; i < srcBones.Length; ++i) @@ -322,14 +323,14 @@ namespace VRM var mesh = srcMesh.Copy(false); mesh.name = srcMesh.name + ".baked"; srcRenderer.BakeMesh(mesh); - - var blendShapeValues = new Dictionary(); + + var blendShapeValues = new Dictionary(); for (int i = 0; i < srcMesh.blendShapeCount; i++) { var val = srcRenderer.GetBlendShapeWeight(i); if (val > 0) blendShapeValues.Add(i, val); } - + mesh.boneWeights = MapBoneWeight(srcMesh.boneWeights, boneMap, srcRenderer.bones, dstBones); // restore weights. clear when BakeMesh // recalc bindposes @@ -385,7 +386,7 @@ namespace VRM srcRenderer.SetBlendShapeWeight(i, value); Vector3[] vertices = blendShapeMesh.vertices; - + for (int j = 0; j < vertices.Length; ++j) { if (originalBlendShapePositions[j] == Vector3.zero) @@ -404,7 +405,7 @@ namespace VRM if (originalBlendShapeNormals[j] == Vector3.zero) { normals[j] = Vector3.zero; - + } else { @@ -428,7 +429,7 @@ namespace VRM #endif var frameCount = srcMesh.GetBlendShapeFrameCount(i); - for(int f=0; f対象モデルのルート /// 強制的にT-Pose化するか /// 正規化済みのモデル - public static NormalizedResult Execute(GameObject go, bool forceTPose, bool clearBlendShapeBeforeNormalize) + public static GameObject Execute(GameObject go, bool forceTPose, bool clearBlendShapeBeforeNormalize) { Dictionary boneMap = new Dictionary(); @@ -564,11 +565,137 @@ namespace VRM NormalizeNoneSkinnedMesh(src, dst); } - return new NormalizedResult + CopyVRMComponents(go, normalized, boneMap); + + // return new NormalizedResult + // { + // Root = normalized, + // BoneMap = boneMap + // }; + return normalized; + } + + /// + /// VRMを構成するコンポーネントをコピーする。 + /// + /// コピー元 + /// コピー先 + /// コピー元とコピー先の対応関係 + static void CopyVRMComponents(GameObject go, GameObject root, + Dictionary map) + { { - Root = normalized, - BoneMap = boneMap - }; + // blendshape + var src = go.GetComponent(); + if (src != null) + { + var dst = root.AddComponent(); + dst.BlendShapeAvatar = src.BlendShapeAvatar; + } + } + + { + var secondary = go.transform.Find("secondary"); + if (secondary == null) + { + secondary = go.transform; + } + + var dstSecondary = root.transform.Find("secondary"); + if (dstSecondary == null) + { + dstSecondary = new GameObject("secondary").transform; + dstSecondary.SetParent(root.transform, false); + } + + // 揺れモノ + foreach (var src in go.transform.GetComponentsInChildren()) + { + var dst = map[src.transform]; + var dstColliderGroup = dst.gameObject.AddComponent(); + dstColliderGroup.Colliders = src.Colliders.Select(y => + { + var offset = dst.worldToLocalMatrix.MultiplyPoint(src.transform.localToWorldMatrix.MultiplyPoint(y.Offset)); + return new VRMSpringBoneColliderGroup.SphereCollider + { + Offset = offset, + Radius = y.Radius + }; + }).ToArray(); + } + + foreach (var src in go.transform.GetComponentsInChildren()) + { + // Copy VRMSpringBone + var dst = dstSecondary.gameObject.AddComponent(); + dst.m_comment = src.m_comment; + dst.m_stiffnessForce = src.m_stiffnessForce; + dst.m_gravityPower = src.m_gravityPower; + dst.m_gravityDir = src.m_gravityDir; + dst.m_dragForce = src.m_dragForce; + if (src.m_center != null) + { + dst.m_center = map[src.m_center]; + } + + dst.RootBones = src.RootBones.Select(x => map[x]).ToList(); + dst.m_hitRadius = src.m_hitRadius; + if (src.ColliderGroups != null) + { + dst.ColliderGroups = src.ColliderGroups + .Select(x => map[x.transform].GetComponent()).ToArray(); + } + } + } + +#pragma warning disable 0618 + { + // meta(obsolete) + var src = go.GetComponent(); + if (src != null) + { + src.CopyTo(root); + } + } +#pragma warning restore 0618 + + { + // meta + var src = go.GetComponent(); + if (src != null) + { + var dst = root.AddComponent(); + dst.Meta = src.Meta; + } + } + + { + // firstPerson + var src = go.GetComponent(); + if (src != null) + { + src.CopyTo(root, map); + } + } + + { + // humanoid + var dst = root.AddComponent(); + var src = go.GetComponent(); + if (src != null) + { + dst.Avatar = src.Avatar; + dst.Description = src.Description; + } + else + { + var animator = go.GetComponent(); + if (animator != null) + { + dst.Avatar = animator.avatar; + } + } + } } } }