Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

moved BoneMeshEraser to MeshUtility editor #718

Merged
merged 1 commit into from
Feb 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Assets/UniGLTF/MeshUtility/Editor/BoneMeshEraserWizard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public override float GetPropertyHeight(SerializedProperty property, GUIContent

public class BoneMeshEraserWizard : ScriptableWizard
{
public const string BONE_MESH_ERASER_NAME = "BoneMeshEraser";
const string ASSET_SUFFIX = ".asset";

[SerializeField]
Expand Down Expand Up @@ -132,7 +133,7 @@ SkinnedMeshRenderer _Erase(GameObject go)
.Select(x => Array.IndexOf(bones, x.Bone))
.ToArray();

var meshNode = new GameObject("BoneMeshEraser");
var meshNode = new GameObject(BONE_MESH_ERASER_NAME);
meshNode.transform.SetParent(go.transform, false);

var erased = meshNode.AddComponent<SkinnedMeshRenderer>();
Expand Down
221 changes: 213 additions & 8 deletions Assets/UniGLTF/MeshUtility/Editor/MeshProcessDialog.cs
Original file line number Diff line number Diff line change
@@ -1,31 +1,68 @@
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEditor;
using MeshUtility.M17N;

namespace MeshUtility
{
[CustomEditor(typeof(MeshProcessDialog), true)]
public class BoneMeshEraserGUI : Editor
{
public override void OnInspectorGUI()
{
serializedObject.Update();
var skinnedMesh = serializedObject.FindProperty("_cSkinnedMesh");
EditorGUILayout.PropertyField(skinnedMesh, new GUIContent("Skinned Mesh"), true);
var animator = serializedObject.FindProperty("_cAnimator");
EditorGUILayout.PropertyField(animator, new GUIContent("Animator"), false);
var eraseRoot = serializedObject.FindProperty("_cEraseRoot");
EditorGUILayout.PropertyField(eraseRoot, new GUIContent("Erase Root"), false);
var list = serializedObject.FindProperty("_eraseBones");
EditorGUILayout.PropertyField(list, new GUIContent("Erase Bones"), true);
serializedObject.ApplyModifiedProperties();
}
}

public class MeshProcessDialog : EditorWindow
{
const string MESH_UTILITY_DICT = "UniGLTF/Mesh Utility/";

[MenuItem(MESH_UTILITY_DICT + "MeshProcessing Wizard", priority = 30)]
static void MeshProcessFromMenu()
{
var window = (MeshProcessDialog)EditorWindow.GetWindowWithRect(typeof(MeshProcessDialog), new Rect(0, 0, 500, 250));
window.titleContent = new GUIContent ("Mesh Processing Window");
var window = (MeshProcessDialog)EditorWindow.GetWindowWithRect(typeof(MeshProcessDialog), new Rect(0, 0, 650, 500));
window.titleContent = new GUIContent("Mesh Processing Window");
window.Show();
}

enum Tabs
{
MeshSeparator,
MeshIntegrator,
StaticMeshIntegrator,
BoneMeshEraser,
}
private Tabs _tab;

private GameObject _exportTarget;
private Editor _boneMeshEraserEditor;
private SkinnedMeshRenderer _pSkinnedMesh;
private Animator _pAnimator;
private Transform _pEraseRoot;
private Vector2 _scrollPos = new Vector2(0, 0);

[SerializeField]
private SkinnedMeshRenderer _cSkinnedMesh = null;
[SerializeField]
private Animator _cAnimator;
[SerializeField]
private Transform _cEraseRoot;
[SerializeField]
private BoneMeshEraser.EraseBone[] _eraseBones;

private MethodInfo _processFunction;
private bool _isInvokeSuccess = false;

Expand All @@ -42,14 +79,26 @@ private enum MeshProcessingMessages
[LangMsg(Languages.en, "Meshes containing BlendShape will be split")]
MESH_SEPARATOR,

[LangMsg(Languages.ja, "メッシュを統合する。BlendShapeを含むメッシュは独立して統合されます")]
[LangMsg(Languages.ja, "メッシュを統合します。BlendShapeを含むメッシュは独立して統合されます")]
[LangMsg(Languages.en, "Generate a single mesh. Meshes w/ BlendShape will be grouped into another one")]
MESH_INTEGRATOR,

[LangMsg(Languages.ja, "静的メッシュを一つに統合する")]
[LangMsg(Languages.ja, "静的メッシュを一つに統合します")]
[LangMsg(Languages.en, "Integrate static meshes into one")]
STATIC_MESH_INTEGRATOR,

[LangMsg(Languages.ja, "ボーン(Erase Rootのヒエラルキー)に関連するメッシュを削除します")]
[LangMsg(Languages.en, "Eliminate meshes associated with the bones in EraseRoot hierarchy")]
BONE_MESH_ERASER,

[LangMsg(Languages.ja, "Skinned Meshを選んでください")]
[LangMsg(Languages.en, "Select a skinned mesh")]
SELECT_SKINNED_MESH,

[LangMsg(Languages.ja, "Erase Rootを選んでください")]
[LangMsg(Languages.en, "Select a erase root")]
SELECT_ERASE_ROOT,

[LangMsg(Languages.ja, "GameObjectを選んでください")]
[LangMsg(Languages.en, "Select a GameObject first")]
NO_GAMEOBJECT_SELECTED,
Expand All @@ -71,8 +120,17 @@ private enum MeshProcessingMessages
VRM_DETECTED,
}

private void OnEnable()
{
if (!_boneMeshEraserEditor)
{
_boneMeshEraserEditor = Editor.CreateEditor(this);
}
}

private void OnGUI()
{
_scrollPos = EditorGUILayout.BeginScrollView(_scrollPos);
EditorGUIUtility.labelWidth = 150;
// lang
Getter.OnGuiSelectLang();
Expand All @@ -82,23 +140,44 @@ private void OnGUI()
switch (_tab)
{
case Tabs.MeshSeparator:
EditorGUILayout.TextField(MeshProcessingMessages.MESH_SEPARATOR.Msg());
EditorGUILayout.LabelField(MeshProcessingMessages.MESH_SEPARATOR.Msg());
break;
case Tabs.MeshIntegrator:
EditorGUILayout.TextField(MeshProcessingMessages.MESH_INTEGRATOR.Msg());
EditorGUILayout.LabelField(MeshProcessingMessages.MESH_INTEGRATOR.Msg());
break;
case Tabs.StaticMeshIntegrator:
EditorGUILayout.TextField(MeshProcessingMessages.STATIC_MESH_INTEGRATOR.Msg());
EditorGUILayout.LabelField(MeshProcessingMessages.STATIC_MESH_INTEGRATOR.Msg());
break;
case Tabs.BoneMeshEraser:
EditorGUILayout.LabelField(MeshProcessingMessages.BONE_MESH_ERASER.Msg());
break;
}

EditorGUILayout.LabelField(MeshProcessingMessages.TARGET_OBJECT.Msg());
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField(MeshProcessingMessages.TARGET_OBJECT.Msg(), GUILayout.MaxWidth(146.0f));
_exportTarget = (GameObject)EditorGUILayout.ObjectField(_exportTarget, typeof(GameObject), true);
EditorGUILayout.EndHorizontal();
if (_exportTarget == null && MeshUtility.IsGameObjectSelected())
{
_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();
Expand All @@ -119,6 +198,9 @@ private void OnGUI()
case Tabs.StaticMeshIntegrator:
_isInvokeSuccess = InvokeWizardUpdate("StaticMeshIntegrator");
break;
case Tabs.BoneMeshEraser:
_isInvokeSuccess = InvokeWizardUpdate("BoneMeshRemover");
break;
}
if (_isInvokeSuccess)
{
Expand All @@ -132,6 +214,7 @@ private void OnGUI()
}
GUILayout.EndVertical();
}
EditorGUILayout.EndScrollView();
}

private bool InvokeWizardUpdate(string processFuntion)
Expand Down Expand Up @@ -218,5 +301,127 @@ private bool StaticMeshIntegrator()
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()
{
if (_cSkinnedMesh == null)
{
_eraseBones = new BoneMeshEraser.EraseBone[] { };
return;
}

if (_cEraseRoot == null)
{
if (_cAnimator != null)
{
_cEraseRoot = _cAnimator.GetBoneTransform(HumanBodyBones.Head);
//Debug.LogFormat("head: {0}", EraseRoot);
}
}

_eraseBones = _cSkinnedMesh.bones.Select(x =>
{
var eb = new BoneMeshEraser.EraseBone
{
Bone = x,
};

if (_cEraseRoot != null)
{
// 首の子孫を消去
if (eb.Bone.Ancestor().Any(y => y == _cEraseRoot))
{
//Debug.LogFormat("erase {0}", x);
eb.Erase = true;
}
}

return eb;
})
.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<SkinnedMeshRenderer>())
{
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<SkinnedMeshRenderer>())
{
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<SkinnedMeshRenderer>();
erased.sharedMesh = BoneMeshEraser.CreateErasedMesh(_cSkinnedMesh.sharedMesh, eraseBones);
erased.sharedMaterials = _cSkinnedMesh.sharedMaterials;
erased.bones = _cSkinnedMesh.bones;

return erased;
}
}
}
6 changes: 3 additions & 3 deletions Assets/UniGLTF/MeshUtility/Editor/MeshUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace MeshUtility
public class MeshUtility
{
public const string MENU_PARENT = "UniGLTF/Mesh Utility/";
private const string ASSET_SUFFIX = ".mesh.asset";
public const string ASSET_SUFFIX = ".mesh.asset";
private static readonly Vector3 ZERO_MOVEMENT = Vector3.zero;

public static Object GetPrefab(GameObject instance)
Expand Down Expand Up @@ -302,7 +302,7 @@ public static void IntegrateSelected(GameObject go)
AssetDatabase.CreateAsset(meshWithMaterials.Mesh, assetPath);

// add component
var meshObject = new GameObject(go.name + ".integrated");
var meshObject = new GameObject(go.name + ".static_meshes_integrated");
if (go.transform.parent != null)
{
meshObject.transform.SetParent(go.transform.parent, false);
Expand Down Expand Up @@ -353,7 +353,7 @@ public static void MeshIntegrator(GameObject go)
else if (skinnedMesh.sharedMesh.name == MeshIntegratorUtility.INTEGRATED_MESH_NAME ||
skinnedMesh.sharedMesh.name == MeshIntegratorUtility.INTEGRATED_MESH_BLENDSHAPE_NAME)
{
// SaveMeshData(skinnedMesh.sharedMesh);
SaveMeshData(skinnedMesh.sharedMesh);
}
}
foreach (var normalMesh in normalMeshes)
Expand Down