Skip to content

Commit

Permalink
Merge pull request #693 from PoChang007/update_meshutility_editor
Browse files Browse the repository at this point in the history
updated MeshUtility editor
  • Loading branch information
ousttrue authored Jan 25, 2021
2 parents e39a94c + 81055e8 commit 4e4cc11
Show file tree
Hide file tree
Showing 8 changed files with 194 additions and 50 deletions.
Binary file modified Assets/UniGLTF/MeshUtility/Documentation/images/interface_2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,22 @@ MeshSeparator provides a functionality of separating meshes contained BlendShape

## How to use

Select a GameObject contained skinned mesh and BlendShape:
Select a GameObject contained skinned mesh and BlendShape (or drag and drop a GameObject to TargetObject field shown below):

<img src="../images/interface_1.jpg" width="200">

From menu go to `UniGLTF` -> `Mesh Utility` -> `MeshProcessing Wizard`, select `MeshSeparator` and click `process`:

<img src="../images/interface_2.jpg" width="300">

The separate meshes are saved in the Assets folder. GameObjects with separate meshes are also available in the Hierarchy Window:
The separate meshes are saved in the Assets folder.

<img src="../images/interface_3.jpg" width="200">

In the Hierarchy Window, click the generated GameObject and export.

<img src="../images/interface_4.jpg" width="250">

In this example, the model's mesh are split into two parts: face and body:

Face: with BlendShape | Body: without BlendShape
Expand Down
68 changes: 54 additions & 14 deletions Assets/UniGLTF/MeshUtility/Editor/MeshProcessDialog.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
using System;
using System.Reflection;
using UnityEngine;
using UnityEditor;
using System.Reflection;
using MeshUtility;
using System.IO;
using System;
using System.Linq;
using MeshUtility.M17N;

namespace MeshUtility
{
Expand Down Expand Up @@ -34,25 +32,67 @@ enum Tabs
GUIStyle _tabButtonStyle => "LargeButton";
GUI.ToolbarButtonSize _tabButtonSize => GUI.ToolbarButtonSize.Fixed;

private enum MeshProcessingMessages
{
[LangMsg(Languages.ja, "ターゲットオブジェクト")]
[LangMsg(Languages.en, "TargetObject")]
TARGET_OBJECT,

[LangMsg(Languages.ja, "BlendShapeを含むメッシュは分割されます")]
[LangMsg(Languages.en, "Meshes containing BlendShape will be split")]
MESH_SEPARATOR,

[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.en, "Integrate static meshes into one")]
STATIC_MESH_INTEGRATOR,

[LangMsg(Languages.ja, "GameObjectを選んでください")]
[LangMsg(Languages.en, "Select a GameObject first")]
NO_GAMEOBJECT_SELECTED,

[LangMsg(Languages.ja, "GameObjectにスキンメッシュが含まれていません")]
[LangMsg(Languages.en, "No skinned mesh is contained")]
NO_SKINNED_MESH,

[LangMsg(Languages.ja, "GameObjectに静的メッシュが含まれていません")]
[LangMsg(Languages.en, "No static mesh is contained")]
NO_STATIC_MESH,

[LangMsg(Languages.ja, "GameObjectにスキンメッシュ・静的メッシュが含まれていません")]
[LangMsg(Languages.en, "Skinned/Static mesh is not contained")]
NO_MESH,

[LangMsg(Languages.ja, "ターゲットオブジェクトはVRMモデルです。`VRM0-> MeshIntegrator`を使ってください")]
[LangMsg(Languages.en, "Target object is VRM model, use `VRM0 -> MeshIntegrator` instead")]
VRM_DETECTED,
}

private void OnGUI()
{
EditorGUIUtility.labelWidth = 150;
// lang
Getter.OnGuiSelectLang();

_tab = TabBar.OnGUI(_tab, _tabButtonStyle, _tabButtonSize);

switch (_tab)
{
case Tabs.MeshSeparator:
EditorGUILayout.TextField("Meshes containing BlendShape data will be split");
EditorGUILayout.TextField(MeshProcessingMessages.MESH_SEPARATOR.Msg());
break;
case Tabs.MeshIntegrator:
EditorGUILayout.TextField("Generate a single mesh. Meshes w/ BlendShape will be grouped into another one");
EditorGUILayout.TextField(MeshProcessingMessages.MESH_INTEGRATOR.Msg());
break;
case Tabs.StaticMeshIntegrator:
EditorGUILayout.TextField("Integrate static meshes into one");
EditorGUILayout.TextField(MeshProcessingMessages.STATIC_MESH_INTEGRATOR.Msg());
break;
}

EditorGUILayout.LabelField("ExportTarget");
EditorGUILayout.LabelField(MeshProcessingMessages.TARGET_OBJECT.Msg());
_exportTarget = (GameObject)EditorGUILayout.ObjectField(_exportTarget, typeof(GameObject), true);
if (_exportTarget == null && MeshUtility.IsGameObjectSelected())
{
Expand Down Expand Up @@ -111,7 +151,7 @@ private bool InvokeWizardUpdate(string processFuntion)

private bool GameObjectNull()
{
EditorUtility.DisplayDialog("Failed", "No GameObject Selected", "ok");
EditorUtility.DisplayDialog("Failed", MeshProcessingMessages.NO_GAMEOBJECT_SELECTED.Msg(), "ok");
return false;
}

Expand All @@ -127,7 +167,7 @@ private bool MeshSeparator()
}
else
{
EditorUtility.DisplayDialog("Failed", "No skinned mesh contained", "ok");
EditorUtility.DisplayDialog("Failed", MeshProcessingMessages.NO_SKINNED_MESH.Msg(), "ok");
return false;
}
}
Expand All @@ -146,7 +186,7 @@ private bool MeshIntegrator()
var sourceString = component.ToString();
if (sourceString.Contains(keyWord))
{
EditorUtility.DisplayDialog("Failed", "Target object is VRM file, use `VRM0 -> MeshIntegrator` instead", "ok");
EditorUtility.DisplayDialog("Failed", MeshProcessingMessages.VRM_DETECTED.Msg(), "ok");
return false;
}
}
Expand All @@ -158,7 +198,7 @@ private bool MeshIntegrator()
}
else
{
EditorUtility.DisplayDialog("Failed", "Neither skinned mesh nor static mesh contained", "ok");
EditorUtility.DisplayDialog("Failed", MeshProcessingMessages.NO_MESH.Msg(), "ok");
return false;
}
}
Expand All @@ -174,7 +214,7 @@ private bool StaticMeshIntegrator()
}
else
{
EditorUtility.DisplayDialog("Failed", "No static mesh contained", "ok");
EditorUtility.DisplayDialog("Failed", MeshProcessingMessages.NO_STATIC_MESH.Msg(), "ok");
return false;
}
}
Expand Down
70 changes: 38 additions & 32 deletions Assets/UniGLTF/MeshUtility/Editor/MeshUtility.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
Expand All @@ -9,14 +9,9 @@ namespace MeshUtility
public class MeshUtility
{
public const string MENU_PARENT = "UniGLTF/Mesh Utility/";

private const string ASSET_SUFFIX = ".mesh.asset";
private const string MENU_NAME = MENU_PARENT + "MeshSeparator";
private static readonly Vector3 ZERO_MOVEMENT = Vector3.zero;

private const string INTEGRATED_MESH_NAME = "MeshesIntegrated";
private const string INTEGRATED_MESH_BLENDSHAPE_NAME = "MeshesBlendShapeIntegrated";

public static Object GetPrefab(GameObject instance)
{
#if UNITY_2018_2_OR_NEWER
Expand All @@ -32,15 +27,6 @@ private enum BlendShapeLogic
WithoutBlendShape,
}

[MenuItem(MENU_NAME, validate = true)]
private static bool ShowLogValidation()
{
if (Selection.activeTransform == null)
return false;
else
return true;
}

[MenuItem(MENU_PARENT + "MeshUtility Docs", priority = 32)]
public static void LinkToMeshSeparatorDocs()
{
Expand Down Expand Up @@ -344,32 +330,35 @@ public static void MeshIntegrator(GameObject go)
// destroy integrated meshes in the source
foreach (var skinnedMesh in go.GetComponentsInChildren<SkinnedMeshRenderer>())
{
if (skinnedMesh.sharedMesh.name == INTEGRATED_MESH_NAME)
if (skinnedMesh.sharedMesh.name == MeshIntegratorUtility.INTEGRATED_MESH_NAME ||
skinnedMesh.sharedMesh.name == MeshIntegratorUtility.INTEGRATED_MESH_BLENDSHAPE_NAME)
{
GameObject.DestroyImmediate(skinnedMesh.gameObject);
}
}
// destroy original meshes in the copied GameObject
foreach (var skinnedMesh in skinnedMeshes)
{
if (skinnedMesh.sharedMesh.name != INTEGRATED_MESH_NAME)
{
GameObject.DestroyImmediate(skinnedMesh);
}
// avoid repeated name
else if (skinnedMesh.sharedMesh.blendShapeCount > 0)
{
skinnedMesh.sharedMesh.name = INTEGRATED_MESH_BLENDSHAPE_NAME;
}
// check if the integrated mesh is empty
else if (skinnedMesh.sharedMesh.subMeshCount == 0)
{
GameObject.DestroyImmediate(skinnedMesh.gameObject);
}
// destroy original meshes in the copied GameObject
if (!(skinnedMesh.sharedMesh.name == MeshIntegratorUtility.INTEGRATED_MESH_NAME ||
skinnedMesh.sharedMesh.name == MeshIntegratorUtility.INTEGRATED_MESH_BLENDSHAPE_NAME))
{
GameObject.DestroyImmediate(skinnedMesh);
}
// check if the integrated mesh is empty
else if (skinnedMesh.sharedMesh.subMeshCount == 0)
{
GameObject.DestroyImmediate(skinnedMesh.gameObject);
}
// save mesh data
else if (skinnedMesh.sharedMesh.name == MeshIntegratorUtility.INTEGRATED_MESH_NAME ||
skinnedMesh.sharedMesh.name == MeshIntegratorUtility.INTEGRATED_MESH_BLENDSHAPE_NAME)
{
// SaveMeshData(skinnedMesh.sharedMesh);
}
}
foreach (var normalMesh in normalMeshes)
{
if (normalMesh.sharedMesh.name != INTEGRATED_MESH_NAME)
if (normalMesh.sharedMesh.name != MeshIntegratorUtility.INTEGRATED_MESH_NAME)
{
if (normalMesh.gameObject.GetComponent<MeshRenderer>())
{
Expand All @@ -379,5 +368,22 @@ public static void MeshIntegrator(GameObject go)
}
}
}

private static void SaveMeshData(Mesh mesh)
{
var assetPath = string.Format("{0}{1}", Path.GetFileNameWithoutExtension(mesh.name), ASSET_SUFFIX);
Debug.Log(assetPath);
if (!string.IsNullOrEmpty((AssetDatabase.GetAssetPath(mesh))))
{
var directory = Path.GetDirectoryName(AssetDatabase.GetAssetPath(mesh)).Replace("\\", "/");
assetPath = string.Format("{0}/{1}{2}", directory, Path.GetFileNameWithoutExtension(mesh.name), ASSET_SUFFIX);
}
else
{
assetPath = string.Format("Assets/{0}{1}", Path.GetFileNameWithoutExtension(mesh.name), ASSET_SUFFIX);
}
Debug.LogFormat("CreateAsset: {0}", assetPath);
AssetDatabase.CreateAsset(mesh, assetPath);
}
}
}
8 changes: 7 additions & 1 deletion Assets/UniGLTF/MeshUtility/Runtime/MeshIntegratorUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ namespace MeshUtility
{
public static class MeshIntegratorUtility
{
public const string INTEGRATED_MESH_NAME = "MeshesIntegrated";
public const string INTEGRATED_MESH_BLENDSHAPE_NAME = "MeshesBlendShapeIntegrated";
/// <summary>
/// go を root としたヒエラルキーから Renderer を集めて、統合された Mesh 作成する
/// </summary>
Expand Down Expand Up @@ -54,7 +56,6 @@ public static MeshIntegrationResult Integrate(GameObject go, bool onlyBlendShape
}

var mesh = new Mesh();
mesh.name = "MeshesIntegrated";

if (integrator.Positions.Count > ushort.MaxValue)
{
Expand All @@ -77,6 +78,11 @@ public static MeshIntegrationResult Integrate(GameObject go, bool onlyBlendShape
if (onlyBlendShapeRenderers)
{
integrator.AddBlendShapesToMesh(mesh);
mesh.name = INTEGRATED_MESH_BLENDSHAPE_NAME;
}
else
{
mesh.name = INTEGRATED_MESH_NAME;
}

var integrated = meshNode.AddComponent<SkinnedMeshRenderer>();
Expand Down
2 changes: 1 addition & 1 deletion Assets/UniGLTF/MeshUtility/Runtime/StaticMeshIntegrator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public void Push(Matrix4x4 localToRoot, Mesh mesh, Material[] materials)
public Mesh ToMesh()
{
var mesh = new Mesh();
mesh.name = "MeshesIntegrated";
mesh.name = MeshIntegratorUtility.INTEGRATED_MESH_NAME;

mesh.vertices = m_positions.ToArray();
if (m_normals.Count > 0)
Expand Down

0 comments on commit 4e4cc11

Please sign in to comment.