diff --git a/Assets/UniGLTF/Editor/MeshUtility/MeshProcessDialog.cs b/Assets/UniGLTF/Editor/MeshUtility/MeshProcessDialog.cs index eda9391d6..ef15a9d84 100644 --- a/Assets/UniGLTF/Editor/MeshUtility/MeshProcessDialog.cs +++ b/Assets/UniGLTF/Editor/MeshUtility/MeshProcessDialog.cs @@ -1,5 +1,3 @@ -using System; -using System.IO; using System.Linq; using System.Reflection; using UnityEngine; @@ -37,7 +35,6 @@ namespace UniGLTF.MeshUtility private BoneMeshEraser.EraseBone[] _eraseBones; private MethodInfo _processFunction; - private bool _isInvokeSuccess = false; GUIStyle _tabButtonStyle => "LargeButton"; GUI.ToolbarButtonSize _tabButtonSize => GUI.ToolbarButtonSize.Fixed; @@ -68,23 +65,53 @@ namespace UniGLTF.MeshUtility LanguageGetter.OnGuiSelectLang(); _tab = TabBar.OnGUI(_tab, _tabButtonStyle, _tabButtonSize); - + var processed = false; switch (_tab) { case Tabs.MeshSeparator: EditorGUILayout.LabelField(MeshProcessingMessages.MESH_SEPARATOR.Msg()); + OnGUI_ExportTarget(); + processed = TabMeshSeparator.OnGUI(_exportTarget); break; case Tabs.MeshIntegrator: EditorGUILayout.LabelField(MeshProcessingMessages.MESH_INTEGRATOR.Msg()); + OnGUI_ExportTarget(); + processed = TabMeshIntegrator.OnGUI(_exportTarget); break; case Tabs.StaticMeshIntegrator: EditorGUILayout.LabelField(MeshProcessingMessages.STATIC_MESH_INTEGRATOR.Msg()); + OnGUI_ExportTarget(); + processed = TabStaticMeshIntegrator.OnGUI(_exportTarget); break; case Tabs.BoneMeshEraser: EditorGUILayout.LabelField(MeshProcessingMessages.BONE_MESH_ERASER.Msg()); + OnGUI_ExportTarget(); + if (_boneMeshEraserEditor) + { + _boneMeshEraserEditor.OnInspectorGUI(); + } + // any better way we can detect component change? + if (_cSkinnedMesh != _pSkinnedMesh || _cAnimator != _pAnimator || _cEraseRoot != _pEraseRoot) + { + BoneMeshEraserValidate(); + } + _pSkinnedMesh = _cSkinnedMesh; + _pAnimator = _cAnimator; + _pEraseRoot = _cEraseRoot; + processed = TabBoneMeshRemover.OnGUI(_exportTarget, _cSkinnedMesh, _cEraseRoot, _eraseBones); break; } + EditorGUILayout.EndScrollView(); + if (processed) + { + Close(); + GUIUtility.ExitGUI(); + } + } + + private void OnGUI_ExportTarget() + { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(MeshProcessingMessages.TARGET_OBJECT.Msg(), GUILayout.MaxWidth(146.0f)); _exportTarget = (GameObject)EditorGUILayout.ObjectField(_exportTarget, typeof(GameObject), true); @@ -93,175 +120,6 @@ namespace UniGLTF.MeshUtility { _exportTarget = Selection.activeObject as GameObject; } - - if (_tab == Tabs.BoneMeshEraser) - { - if (_boneMeshEraserEditor) - { - _boneMeshEraserEditor.OnInspectorGUI(); - } - // any better way we can detect component change? - if (_cSkinnedMesh != _pSkinnedMesh || _cAnimator != _pAnimator || _cEraseRoot != _pEraseRoot) - { - BoneMeshEraserValidate(); - } - _pSkinnedMesh = _cSkinnedMesh; - _pAnimator = _cAnimator; - _pEraseRoot = _cEraseRoot; - } - - // Create Other Buttons - { - GUILayout.BeginVertical(); - { - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - - if (GUILayout.Button("Process", GUILayout.MinWidth(100))) - { - switch (_tab) - { - case Tabs.MeshSeparator: - _isInvokeSuccess = InvokeWizardUpdate("MeshSeparator"); - break; - case Tabs.MeshIntegrator: - _isInvokeSuccess = InvokeWizardUpdate("MeshIntegrator"); - break; - case Tabs.StaticMeshIntegrator: - _isInvokeSuccess = InvokeWizardUpdate("StaticMeshIntegrator"); - break; - case Tabs.BoneMeshEraser: - _isInvokeSuccess = InvokeWizardUpdate("BoneMeshRemover"); - break; - } - if (_isInvokeSuccess) - { - Close(); - GUIUtility.ExitGUI(); - } - } - GUI.enabled = true; - - GUILayout.EndHorizontal(); - } - GUILayout.EndVertical(); - } - EditorGUILayout.EndScrollView(); - } - - private bool InvokeWizardUpdate(string processFuntion) - { - const BindingFlags kInstanceInvokeFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy; - _processFunction = GetType().GetMethod(processFuntion, kInstanceInvokeFlags); - if (_processFunction != null) - { - return (Boolean)_processFunction.Invoke(this, null); - } - else - { - Debug.LogError("This function has not been implemented in script"); - return false; - } - } - - private bool GameObjectNull() - { - EditorUtility.DisplayDialog("Failed", MeshProcessingMessages.NO_GAMEOBJECT_SELECTED.Msg(), "ok"); - return false; - } - - private bool MeshSeparator() - { - if (_exportTarget == null) return GameObjectNull(); - var go = _exportTarget; - - if (go.GetComponentsInChildren().Length > 0) - { - // copy - var outputObject = GameObject.Instantiate(go); - outputObject.name = outputObject.name + "_mesh_separation"; - // 改変と asset の作成 - var list = MeshUtility.SeparationProcessing(outputObject); - foreach (var (src, with, without) in list) - { - // asset の永続化 - MeshUtility.SaveMesh(src, with, MeshUtility.BlendShapeLogic.WithBlendShape); - MeshUtility.SaveMesh(src, without, MeshUtility.BlendShapeLogic.WithoutBlendShape); - } - return true; - } - else - { - EditorUtility.DisplayDialog("Failed", MeshProcessingMessages.NO_SKINNED_MESH.Msg(), "ok"); - return false; - } - } - - private bool MeshIntegrator() - { - if (_exportTarget == null) return GameObjectNull(); - var go = _exportTarget; - - Component[] allComponents = go.GetComponents(typeof(Component)); - var keyWord = "VRMMeta"; - - foreach (var component in allComponents) - { - if (component == null) continue; - var sourceString = component.ToString(); - if (sourceString.Contains(keyWord)) - { - EditorUtility.DisplayDialog("Failed", MeshProcessingMessages.VRM_DETECTED.Msg(), "ok"); - return false; - } - } - - if (go.GetComponentsInChildren().Length > 0 || go.GetComponentsInChildren().Length > 0) - { - MeshUtility.MeshIntegrator(go); - return true; - } - else - { - EditorUtility.DisplayDialog("Failed", MeshProcessingMessages.NO_MESH.Msg(), "ok"); - return false; - } - } - - private bool StaticMeshIntegrator() - { - if (_exportTarget == null) return GameObjectNull(); - var go = _exportTarget; - if (go.GetComponentsInChildren().Length > 0) - { - MeshUtility.IntegrateSelected(go); - return true; - } - else - { - EditorUtility.DisplayDialog("Failed", MeshProcessingMessages.NO_STATIC_MESH.Msg(), "ok"); - return false; - } - } - - private bool BoneMeshRemover() - { - if (_exportTarget == null) return GameObjectNull(); - var go = _exportTarget; - - if (_cSkinnedMesh == null) - { - EditorUtility.DisplayDialog("Failed", MeshProcessingMessages.SELECT_SKINNED_MESH.Msg(), "ok"); - return false; - } - else if (_cEraseRoot == null) - { - EditorUtility.DisplayDialog("Failed", MeshProcessingMessages.SELECT_ERASE_ROOT.Msg(), "ok"); - return false; - } - BoneMeshRemove(go); - - return true; } private void BoneMeshEraserValidate() @@ -302,68 +160,5 @@ namespace UniGLTF.MeshUtility }) .ToArray(); } - - private void BoneMeshRemove(GameObject go) - { - var renderer = Remove(go); - var outputObject = GameObject.Instantiate(go); - outputObject.name = outputObject.name + "_bone_mesh_erase"; - if (renderer == null) - { - return; - } - - // save mesh to Assets - var assetPath = string.Format("{0}{1}", go.name, MeshUtility.ASSET_SUFFIX); - var prefab = MeshUtility.GetPrefab(go); - if (prefab != null) - { - var prefabPath = AssetDatabase.GetAssetPath(prefab); - assetPath = string.Format("{0}/{1}{2}", - Path.GetDirectoryName(prefabPath), - Path.GetFileNameWithoutExtension(prefabPath), - MeshUtility.ASSET_SUFFIX - ); - } - - Debug.LogFormat("CreateAsset: {0}", assetPath); - AssetDatabase.CreateAsset(renderer.sharedMesh, assetPath); - - // destroy BoneMeshEraser in the source - foreach (var skinnedMesh in go.GetComponentsInChildren()) - { - if (skinnedMesh.gameObject.name == BoneMeshEraserWizard.BONE_MESH_ERASER_NAME) - { - GameObject.DestroyImmediate(skinnedMesh.gameObject); - } - } - // destroy the original mesh in the copied GameObject - foreach (var skinnedMesh in outputObject.GetComponentsInChildren()) - { - if (skinnedMesh.sharedMesh == _cSkinnedMesh.sharedMesh) - { - GameObject.DestroyImmediate(skinnedMesh); - } - } - } - - private SkinnedMeshRenderer Remove(GameObject go) - { - var bones = _cSkinnedMesh.bones; - var eraseBones = _eraseBones - .Where(x => x.Erase) - .Select(x => Array.IndexOf(bones, x.Bone)) - .ToArray(); - - var meshNode = new GameObject(BoneMeshEraserWizard.BONE_MESH_ERASER_NAME); - meshNode.transform.SetParent(go.transform, false); - - var erased = meshNode.AddComponent(); - erased.sharedMesh = BoneMeshEraser.CreateErasedMesh(_cSkinnedMesh.sharedMesh, eraseBones); - erased.sharedMaterials = _cSkinnedMesh.sharedMaterials; - erased.bones = _cSkinnedMesh.bones; - - return erased; - } } } \ No newline at end of file diff --git a/Assets/UniGLTF/Editor/MeshUtility/TabBoneMeshRemover.cs b/Assets/UniGLTF/Editor/MeshUtility/TabBoneMeshRemover.cs new file mode 100644 index 000000000..b4400fa2f --- /dev/null +++ b/Assets/UniGLTF/Editor/MeshUtility/TabBoneMeshRemover.cs @@ -0,0 +1,116 @@ +using System; +using System.IO; +using System.Linq; +using UniGLTF.M17N; +using UnityEditor; +using UnityEngine; + +namespace UniGLTF.MeshUtility +{ + public static class TabBoneMeshRemover + { + public static bool OnGUI(GameObject _exportTarget, SkinnedMeshRenderer _cSkinnedMesh, Transform _cEraseRoot, BoneMeshEraser.EraseBone[] _eraseBones) + { + var _isInvokeSuccess = false; + GUILayout.BeginVertical(); + { + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + if (GUILayout.Button("Process", GUILayout.MinWidth(100))) + { + _isInvokeSuccess = TabBoneMeshRemover.Execute(_exportTarget, _cSkinnedMesh, _cEraseRoot, _eraseBones); + } + GUILayout.EndHorizontal(); + } + GUILayout.EndVertical(); + return _isInvokeSuccess; + } + + public static bool Execute(GameObject _exportTarget, SkinnedMeshRenderer _cSkinnedMesh, Transform _cEraseRoot, BoneMeshEraser.EraseBone[] _eraseBones) + { + if (_exportTarget == null) + { + EditorUtility.DisplayDialog("Failed", MeshProcessingMessages.NO_GAMEOBJECT_SELECTED.Msg(), "ok"); + return false; + } + var go = _exportTarget; + + if (_cSkinnedMesh == null) + { + EditorUtility.DisplayDialog("Failed", MeshProcessingMessages.SELECT_SKINNED_MESH.Msg(), "ok"); + return false; + } + else if (_cEraseRoot == null) + { + EditorUtility.DisplayDialog("Failed", MeshProcessingMessages.SELECT_ERASE_ROOT.Msg(), "ok"); + return false; + } + BoneMeshRemove(go, _cSkinnedMesh, _eraseBones); + + return true; + } + + private static void BoneMeshRemove(GameObject go, SkinnedMeshRenderer _cSkinnedMesh, BoneMeshEraser.EraseBone[] _eraseBones) + { + var renderer = Remove(go, _cSkinnedMesh, _eraseBones); + var outputObject = GameObject.Instantiate(go); + outputObject.name = outputObject.name + "_bone_mesh_erase"; + if (renderer == null) + { + return; + } + + // save mesh to Assets + var assetPath = string.Format("{0}{1}", go.name, MeshUtility.ASSET_SUFFIX); + var prefab = MeshUtility.GetPrefab(go); + if (prefab != null) + { + var prefabPath = AssetDatabase.GetAssetPath(prefab); + assetPath = string.Format("{0}/{1}{2}", + Path.GetDirectoryName(prefabPath), + Path.GetFileNameWithoutExtension(prefabPath), + MeshUtility.ASSET_SUFFIX + ); + } + + Debug.LogFormat("CreateAsset: {0}", assetPath); + AssetDatabase.CreateAsset(renderer.sharedMesh, assetPath); + + // destroy BoneMeshEraser in the source + foreach (var skinnedMesh in go.GetComponentsInChildren()) + { + if (skinnedMesh.gameObject.name == BoneMeshEraserWizard.BONE_MESH_ERASER_NAME) + { + GameObject.DestroyImmediate(skinnedMesh.gameObject); + } + } + // destroy the original mesh in the copied GameObject + foreach (var skinnedMesh in outputObject.GetComponentsInChildren()) + { + if (skinnedMesh.sharedMesh == _cSkinnedMesh.sharedMesh) + { + GameObject.DestroyImmediate(skinnedMesh); + } + } + } + + private static SkinnedMeshRenderer Remove(GameObject go, SkinnedMeshRenderer _cSkinnedMesh, BoneMeshEraser.EraseBone[] _eraseBones) + { + var bones = _cSkinnedMesh.bones; + var eraseBones = _eraseBones + .Where(x => x.Erase) + .Select(x => Array.IndexOf(bones, x.Bone)) + .ToArray(); + + var meshNode = new GameObject(BoneMeshEraserWizard.BONE_MESH_ERASER_NAME); + meshNode.transform.SetParent(go.transform, false); + + var erased = meshNode.AddComponent(); + erased.sharedMesh = BoneMeshEraser.CreateErasedMesh(_cSkinnedMesh.sharedMesh, eraseBones); + erased.sharedMaterials = _cSkinnedMesh.sharedMaterials; + erased.bones = _cSkinnedMesh.bones; + + return erased; + } + } +} \ No newline at end of file diff --git a/Assets/UniGLTF/Editor/MeshUtility/TabBoneMeshRemover.cs.meta b/Assets/UniGLTF/Editor/MeshUtility/TabBoneMeshRemover.cs.meta new file mode 100644 index 000000000..29e107335 --- /dev/null +++ b/Assets/UniGLTF/Editor/MeshUtility/TabBoneMeshRemover.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4094f82d7ee108a4997d80a692116033 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UniGLTF/Editor/MeshUtility/TabMeshIntegrator.cs b/Assets/UniGLTF/Editor/MeshUtility/TabMeshIntegrator.cs new file mode 100644 index 000000000..9befa651b --- /dev/null +++ b/Assets/UniGLTF/Editor/MeshUtility/TabMeshIntegrator.cs @@ -0,0 +1,61 @@ +using UniGLTF.M17N; +using UnityEditor; +using UnityEngine; + +namespace UniGLTF.MeshUtility +{ + public static class TabMeshIntegrator + { + public static bool OnGUI(GameObject _exportTarget) + { + var _isInvokeSuccess = false; + GUILayout.BeginVertical(); + { + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + if (GUILayout.Button("Process", GUILayout.MinWidth(100))) + { + _isInvokeSuccess = TabMeshIntegrator.Execute(_exportTarget); + } + GUILayout.EndHorizontal(); + } + GUILayout.EndVertical(); + return _isInvokeSuccess; + } + + static bool Execute(GameObject _exportTarget) + { + if (_exportTarget == null) + { + EditorUtility.DisplayDialog("Failed", MeshProcessingMessages.NO_GAMEOBJECT_SELECTED.Msg(), "ok"); + return false; + } + var go = _exportTarget; + + var allComponents = go.GetComponents(typeof(Component)); + var keyWord = "VRMMeta"; + + foreach (var component in allComponents) + { + if (component == null) continue; + var sourceString = component.ToString(); + if (sourceString.Contains(keyWord)) + { + EditorUtility.DisplayDialog("Failed", MeshProcessingMessages.VRM_DETECTED.Msg(), "ok"); + return false; + } + } + + if (go.GetComponentsInChildren().Length > 0 || go.GetComponentsInChildren().Length > 0) + { + MeshUtility.MeshIntegrator(go); + return true; + } + else + { + EditorUtility.DisplayDialog("Failed", MeshProcessingMessages.NO_MESH.Msg(), "ok"); + return false; + } + } + } +} diff --git a/Assets/UniGLTF/Editor/MeshUtility/TabMeshIntegrator.cs.meta b/Assets/UniGLTF/Editor/MeshUtility/TabMeshIntegrator.cs.meta new file mode 100644 index 000000000..5c60a51fe --- /dev/null +++ b/Assets/UniGLTF/Editor/MeshUtility/TabMeshIntegrator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 65a227dcf3cb5f34085bd6829894fb64 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UniGLTF/Editor/MeshUtility/TabMeshSeparator.cs b/Assets/UniGLTF/Editor/MeshUtility/TabMeshSeparator.cs new file mode 100644 index 000000000..0966be00e --- /dev/null +++ b/Assets/UniGLTF/Editor/MeshUtility/TabMeshSeparator.cs @@ -0,0 +1,57 @@ +using UniGLTF.M17N; +using UnityEditor; +using UnityEngine; + +namespace UniGLTF.MeshUtility +{ + public static class TabMeshSeparator + { + public static bool OnGUI(GameObject _exportTarget) + { + var _isInvokeSuccess = false; + GUILayout.BeginVertical(); + { + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + if (GUILayout.Button("Process", GUILayout.MinWidth(100))) + { + _isInvokeSuccess = TabMeshSeparator.Execute(_exportTarget); + } + GUILayout.EndHorizontal(); + } + GUILayout.EndVertical(); + return _isInvokeSuccess; + } + + static bool Execute(GameObject _exportTarget) + { + if (_exportTarget == null) + { + EditorUtility.DisplayDialog("Failed", MeshProcessingMessages.NO_GAMEOBJECT_SELECTED.Msg(), "ok"); + return false; + } + + var go = _exportTarget; + if (go.GetComponentsInChildren().Length > 0) + { + // copy + var outputObject = GameObject.Instantiate(go); + outputObject.name = outputObject.name + "_mesh_separation"; + // 改変と asset の作成 + var list = MeshUtility.SeparationProcessing(outputObject); + foreach (var (src, with, without) in list) + { + // asset の永続化 + MeshUtility.SaveMesh(src, with, MeshUtility.BlendShapeLogic.WithBlendShape); + MeshUtility.SaveMesh(src, without, MeshUtility.BlendShapeLogic.WithoutBlendShape); + } + return true; + } + else + { + EditorUtility.DisplayDialog("Failed", MeshProcessingMessages.NO_SKINNED_MESH.Msg(), "ok"); + return false; + } + } + } +} diff --git a/Assets/UniGLTF/Editor/MeshUtility/TabMeshSeparator.cs.meta b/Assets/UniGLTF/Editor/MeshUtility/TabMeshSeparator.cs.meta new file mode 100644 index 000000000..8fb9a175b --- /dev/null +++ b/Assets/UniGLTF/Editor/MeshUtility/TabMeshSeparator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8921d732b66ae134db97faa11eaa9b17 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UniGLTF/Editor/MeshUtility/TabStaticMeshIntegrator.cs b/Assets/UniGLTF/Editor/MeshUtility/TabStaticMeshIntegrator.cs new file mode 100644 index 000000000..4d837d2e7 --- /dev/null +++ b/Assets/UniGLTF/Editor/MeshUtility/TabStaticMeshIntegrator.cs @@ -0,0 +1,47 @@ +using UniGLTF.M17N; +using UnityEditor; +using UnityEngine; + +namespace UniGLTF.MeshUtility +{ + public static class TabStaticMeshIntegrator + { + public static bool OnGUI(GameObject _exportTarget) + { + var _isInvokeSuccess = false; + GUILayout.BeginVertical(); + { + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + if (GUILayout.Button("Process", GUILayout.MinWidth(100))) + { + _isInvokeSuccess = TabStaticMeshIntegrator.Execute(_exportTarget); + } + GUILayout.EndHorizontal(); + } + GUILayout.EndVertical(); + return _isInvokeSuccess; + } + + static bool Execute(GameObject _exportTarget) + { + if (_exportTarget == null) + { + EditorUtility.DisplayDialog("Failed", MeshProcessingMessages.NO_GAMEOBJECT_SELECTED.Msg(), "ok"); + return false; + } + var go = _exportTarget; + + if (go.GetComponentsInChildren().Length > 0) + { + MeshUtility.IntegrateSelected(go); + return true; + } + else + { + EditorUtility.DisplayDialog("Failed", MeshProcessingMessages.NO_STATIC_MESH.Msg(), "ok"); + return false; + } + } + } +} diff --git a/Assets/UniGLTF/Editor/MeshUtility/TabStaticMeshIntegrator.cs.meta b/Assets/UniGLTF/Editor/MeshUtility/TabStaticMeshIntegrator.cs.meta new file mode 100644 index 000000000..4c0e30384 --- /dev/null +++ b/Assets/UniGLTF/Editor/MeshUtility/TabStaticMeshIntegrator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9701e1f6aaed8d14283243a7a50be2df +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: