diff --git a/Scripts/Format/Editor/VRMExportObjectEditor.cs b/Scripts/Format/Editor/VRMExportObjectEditor.cs index 9a6fffd51..6f1ddb05b 100644 --- a/Scripts/Format/Editor/VRMExportObjectEditor.cs +++ b/Scripts/Format/Editor/VRMExportObjectEditor.cs @@ -56,7 +56,11 @@ namespace VRM "vrm"); if (!string.IsNullOrEmpty(path)) { - Export(path); + var target = m_target; + EditorApplication.delayCall += () => + { + target.Settings.Export(path); + }; } } } @@ -93,19 +97,5 @@ namespace VRM } } } - - void Export(string path) - { - Debug.LogFormat("export: {0}", path); - - /* - using (var instance = new DisposableInstance(m_source.objectReferenceValue as GameObject)) - { - var vrm = VRMExporter.Export(instance.GameObject); - var bytes = vrm.ToGlbBytes(); - File.WriteAllBytes(path, bytes); - } - */ - } } } diff --git a/Scripts/Format/Editor/VRMExporterMenu.cs b/Scripts/Format/Editor/VRMExporterMenu.cs index c60a7be1b..34790f8fa 100644 --- a/Scripts/Format/Editor/VRMExporterMenu.cs +++ b/Scripts/Format/Editor/VRMExporterMenu.cs @@ -1,10 +1,6 @@ -using System.Collections.Generic; -using System.Linq; +using System.Text; using UnityEditor; using UnityEngine; -using UniGLTF; -using System.IO; -using System.Text; namespace VRM @@ -43,36 +39,7 @@ namespace VRM } // export - var target = m_settings.Source; - if (m_settings.PoseFreeze) - { - Undo.RecordObjects(m_settings.Source.transform.Traverse().ToArray(), "before normalize"); - var map = new Dictionary(); - target = VRM.BoneNormalizer.Execute(m_settings.Source.gameObject, map, m_settings.ForceTPose); - VRMHumanoidNorimalizerMenu.CopyVRMComponents(m_settings.Source.gameObject, target, map); - Undo.PerformUndo(); - } - - var sw = System.Diagnostics.Stopwatch.StartNew(); - - var vrm = VRMExporter.Export(target); - vrm.extensions.VRM.meta.title = m_settings.Title; - vrm.extensions.VRM.meta.author = m_settings.Author; - - var bytes = vrm.ToGlbBytes(); - File.WriteAllBytes(path, bytes); - - Debug.LogFormat("Export elapsed {0}", sw.Elapsed); - - if (m_settings.Source.gameObject != target) - { - GameObject.DestroyImmediate(target); - } - - if (path.StartsWithUnityAssetPath()) - { - AssetDatabase.ImportAsset(path.ToUnityRelativePath()); - } + m_settings.Export(path); } void OnWizardUpdate() diff --git a/Scripts/Format/Editor/VRMHumanoidNormalizerMenu.cs b/Scripts/Format/Editor/VRMHumanoidNormalizerMenu.cs index 49b746384..aa098743f 100644 --- a/Scripts/Format/Editor/VRMHumanoidNormalizerMenu.cs +++ b/Scripts/Format/Editor/VRMHumanoidNormalizerMenu.cs @@ -50,122 +50,8 @@ namespace VRM Undo.RecordObjects(go.transform.Traverse().ToArray(), "before normalize"); var map = new Dictionary(); var normalized = VRM.BoneNormalizer.Execute(go, map, true); - CopyVRMComponents(go, normalized, map); + VRMExportSettings.CopyVRMComponents(go, normalized, map); Undo.PerformUndo(); } - - // - // トップレベルのMonoBehaviourを移植する - // - 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.Traverse().Select(x => x.GetComponent()).Where(x => x != null)) - { - 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.Traverse().SelectMany(x => x.GetComponents())) - { - var dst = dstSecondary.gameObject.AddComponent(); - dst.m_comment = src.m_comment; - dst.RootBones = src.RootBones.Select(x => map[x]).ToList(); - if (src.ColliderGroups != null) - { - dst.ColliderGroups = src.ColliderGroups.Select(x => map[x.transform].GetComponent()).ToArray(); - } - } - } - - { - // meta(obsolete) - var src = go.GetComponent(); - if (src != null) - { - src.CopyTo(root); - } - } - { - // 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); - } - } - - { - // lookAt - 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/Scripts/Format/VRMExporSettings.cs b/Scripts/Format/VRMExporSettings.cs index 747481cdd..a12176368 100644 --- a/Scripts/Format/VRMExporSettings.cs +++ b/Scripts/Format/VRMExporSettings.cs @@ -1,6 +1,10 @@ using System; using System.Collections.Generic; +using System.Linq; using UnityEngine; +using UniGLTF; +using UnityEditor; +using System.IO; namespace VRM @@ -84,5 +88,196 @@ namespace VRM //Author = ""; } } + + // + // トップレベルのMonoBehaviourを移植する + // + 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.Traverse().Select(x => x.GetComponent()).Where(x => x != null)) + { + 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.Traverse().SelectMany(x => x.GetComponents())) + { + var dst = dstSecondary.gameObject.AddComponent(); + dst.m_comment = src.m_comment; + dst.RootBones = src.RootBones.Select(x => map[x]).ToList(); + if (src.ColliderGroups != null) + { + dst.ColliderGroups = src.ColliderGroups.Select(x => map[x.transform].GetComponent()).ToArray(); + } + } + } + + { + // meta(obsolete) + var src = go.GetComponent(); + if (src != null) + { + src.CopyTo(root); + } + } + { + // 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); + } + } + + { + // lookAt + 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; + } + } + } + } + + public static bool IsPrefab(GameObject go) + { + return go.scene.name == null; + } + + struct RecordDisposer : IDisposable + { + public RecordDisposer(UnityEngine.Object[] objects, string msg) + { + Undo.RecordObjects(objects, msg); + } + + public void Dispose() + { + Undo.PerformUndo(); + } + } + +#if UNITY_EDITOR + public void Export(string path) + { + List destroy = new List(); + try + { + Export(path, destroy); + } + finally + { + foreach (var x in destroy) + { + Debug.LogFormat("destroy: {0}", x.name); + GameObject.DestroyImmediate(x); + } + } + } + + void Export(string path, List destroy) + { + var target = Source; + if (IsPrefab(target)) + { + using (new RecordDisposer(Source.transform.Traverse().ToArray(), "before normalize")) + { + target = GameObject.Instantiate(target); + destroy.Add(target); + } + } + if (PoseFreeze) + { + using (new RecordDisposer(target.transform.Traverse().ToArray(), "before normalize")) + { + var map = new Dictionary(); + var copy = BoneNormalizer.Execute(target, map, ForceTPose); + CopyVRMComponents(target, copy, map); + target = copy; + destroy.Add(target); + } + } + + { + var sw = System.Diagnostics.Stopwatch.StartNew(); + var vrm = VRMExporter.Export(target); + vrm.extensions.VRM.meta.title = Title; + vrm.extensions.VRM.meta.author = Author; + + var bytes = vrm.ToGlbBytes(); + File.WriteAllBytes(path, bytes); + Debug.LogFormat("Export elapsed {0}", sw.Elapsed); + } + + if (path.StartsWithUnityAssetPath()) + { + AssetDatabase.ImportAsset(path.ToUnityRelativePath()); + } + } +#endif } } diff --git a/Scripts/Format/VRMExportObject.cs b/Scripts/Format/VRMExportObject.cs index c278f1a52..e701ac1e9 100644 --- a/Scripts/Format/VRMExportObject.cs +++ b/Scripts/Format/VRMExportObject.cs @@ -7,6 +7,6 @@ namespace VRM public class VRMExportObject : ScriptableObject { [SerializeField] - public VRMExportSettings Settings; + public VRMExportSettings Settings = new VRMExportSettings(); } } diff --git a/Scripts/SkinnedMeshUtility/Editor/BoneNormalizer.cs b/Scripts/SkinnedMeshUtility/BoneNormalizer.cs similarity index 100% rename from Scripts/SkinnedMeshUtility/Editor/BoneNormalizer.cs rename to Scripts/SkinnedMeshUtility/BoneNormalizer.cs diff --git a/Scripts/SkinnedMeshUtility/Editor/BoneNormalizer.cs.meta b/Scripts/SkinnedMeshUtility/BoneNormalizer.cs.meta similarity index 100% rename from Scripts/SkinnedMeshUtility/Editor/BoneNormalizer.cs.meta rename to Scripts/SkinnedMeshUtility/BoneNormalizer.cs.meta