diff --git a/Assets/VRM/Editor/Format/InternalTPose.cs b/Assets/VRM/Editor/Format/InternalTPose.cs new file mode 100644 index 000000000..ec8ec6f5a --- /dev/null +++ b/Assets/VRM/Editor/Format/InternalTPose.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using UniGLTF; +using UnityEngine; + +namespace VRM +{ + public static class InternalTPose + { + struct TRS + { + public Vector3 T; + public Quaternion R; + public Vector3 S; + + public void Apply(Transform t) + { + t.localPosition = T; + t.localRotation = R; + t.localScale = S; + } + + public static TRS From(Transform t) + { + return new TRS + { + T = t.localPosition, + R = t.localRotation, + S = t.localScale, + }; + } + } + + static void BuildMap(Transform t, Dictionary map, Transform root = null) + { + if (root == null) + { + root = t; + } + + map.Add(t.RelativePathFrom(root), TRS.From(t)); + + foreach (Transform child in t) + { + BuildMap(child, map, root); + } + } + + static void ApplyMap(Transform t, Dictionary map, Transform root = null) + { + if (root == null) + { + root = t; + } + + map[t.RelativePathFrom(root)].Apply(t); + + foreach (Transform child in t) + { + ApplyMap(child, map, root); + } + } + + public static bool TrySampleBindPose(GameObject go) + { + // https://forum.unity.com/threads/mesh-bindposes.383752/ + var type = Type.GetType("UnityEditor.AvatarSetupTool, UnityEditor"); + if (type != null) + { + var info = type.GetMethod("SampleBindPose", BindingFlags.Static | BindingFlags.Public); + if (info != null) + { + // prefab cause error message. create copy + var clone = GameObject.Instantiate(go); + try + { + info.Invoke(null, new object[] { clone }); + var map = new Dictionary(); + BuildMap(clone.transform, map); + ApplyMap(go.transform, map); + } + finally + { + GameObject.DestroyImmediate(clone); + } + + return true; + } + } + + return false; + } + } +} \ No newline at end of file diff --git a/Assets/VRM/Editor/Format/InternalTPose.cs.meta b/Assets/VRM/Editor/Format/InternalTPose.cs.meta new file mode 100644 index 000000000..acfd503fc --- /dev/null +++ b/Assets/VRM/Editor/Format/InternalTPose.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 42e52c1a93301da4eb0435ed00bdf8c4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM/Editor/Format/VRMExportSettingsEditor.cs b/Assets/VRM/Editor/Format/VRMExportSettingsEditor.cs index e1e9c63d2..23f0796bb 100644 --- a/Assets/VRM/Editor/Format/VRMExportSettingsEditor.cs +++ b/Assets/VRM/Editor/Format/VRMExportSettingsEditor.cs @@ -4,6 +4,9 @@ using UnityEditor; using UnityEngine; using MeshUtility.M17N; using System.Reflection; +using System.Linq; +using System.Collections.Generic; +using UniGLTF; namespace VRM { @@ -49,7 +52,7 @@ namespace VRM return MeshUtility.M17N.Getter.Msg(key); } - enum Options + public enum Options { [LangMsg(Languages.ja, "エクスポート時に強制的にT-Pose化する。これを使わずに手動でT-Poseを作っても問題ありません")] [LangMsg(Languages.en, "Force T-Pose before export. Manually making T-Pose for model without enabling this is ok")] @@ -110,23 +113,6 @@ namespace VRM m_divideVertexBuffer = new CheckBoxProp(serializedObject.FindProperty(nameof(VRMExportSettings.DivideVertexBuffer)), Options.DIVIDE_VERTEX_BUFFER); } - static bool TrySampleBindPose(GameObject go) - { - // https://forum.unity.com/threads/mesh-bindposes.383752/ - var type = Type.GetType("UnityEditor.AvatarSetupTool, UnityEditor"); - if (type != null) - { - var info = type.GetMethod("SampleBindPose", BindingFlags.Static | BindingFlags.Public); - if (info != null) - { - var clone = GameObject.Instantiate(go); - info.Invoke(null, new object[] { clone }); - return true; - } - } - - return false; - } public override void OnInspectorGUI() { @@ -143,19 +129,26 @@ namespace VRM { EditorGUILayout.HelpBox(Options.DISABLE_TPOSE_BUTTON.Msg(), MessageType.Warning); } - if (GUILayout.Button(Options.DO_TPOSE.Msg())) + + // + // T-Pose + // + if (GUILayout.Button(VRMExportSettingsEditor.Options.DO_TPOSE.Msg())) { if (settings.Root != null) { // fallback + Undo.RecordObjects(settings.Root.GetComponentsInChildren(), "tpose"); VRMBoneNormalizer.EnforceTPose(settings.Root); } } - if (GUILayout.Button(Options.DO_TPOSE.Msg() + "(internal)")) + + if (GUILayout.Button(VRMExportSettingsEditor.Options.DO_TPOSE.Msg() + "(internal)")) { if (settings.Root != null) { - if (TrySampleBindPose(settings.Root)) + Undo.RecordObjects(settings.Root.GetComponentsInChildren(), "tpose.internal"); + if (InternalTPose.TrySampleBindPose(settings.Root)) { // done } @@ -165,6 +158,7 @@ namespace VRM } } } + GUI.enabled = backup; GUILayout.Space(20);