mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-07-15 07:34:25 -05:00
Merge pull request #693 from PoChang007/update_meshutility_editor
updated MeshUtility editor
This commit is contained in:
commit
4e4cc1150c
Binary file not shown.
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 24 KiB |
BIN
Assets/UniGLTF/MeshUtility/Documentation/images/interface_4.jpg
Normal file
BIN
Assets/UniGLTF/MeshUtility/Documentation/images/interface_4.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
|
|
@ -0,0 +1,88 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 669e2a7e945cb8f468940a05224a8efb
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 9
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -100
|
||||
wrapU: -1
|
||||
wrapV: -1
|
||||
wrapW: -1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 2
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -4,7 +4,7 @@ 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">
|
||||
|
||||
|
|
@ -12,10 +12,14 @@ From menu go to `UniGLTF` -> `Mesh Utility` -> `MeshProcessing Wizard`, select `
|
|||
|
||||
<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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -34,25 +32,67 @@ namespace MeshUtility
|
|||
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())
|
||||
{
|
||||
|
|
@ -111,7 +151,7 @@ namespace MeshUtility
|
|||
|
||||
private bool GameObjectNull()
|
||||
{
|
||||
EditorUtility.DisplayDialog("Failed", "No GameObject Selected", "ok");
|
||||
EditorUtility.DisplayDialog("Failed", MeshProcessingMessages.NO_GAMEOBJECT_SELECTED.Msg(), "ok");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -127,7 +167,7 @@ namespace MeshUtility
|
|||
}
|
||||
else
|
||||
{
|
||||
EditorUtility.DisplayDialog("Failed", "No skinned mesh contained", "ok");
|
||||
EditorUtility.DisplayDialog("Failed", MeshProcessingMessages.NO_SKINNED_MESH.Msg(), "ok");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -146,7 +186,7 @@ namespace MeshUtility
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -158,7 +198,7 @@ namespace MeshUtility
|
|||
}
|
||||
else
|
||||
{
|
||||
EditorUtility.DisplayDialog("Failed", "Neither skinned mesh nor static mesh contained", "ok");
|
||||
EditorUtility.DisplayDialog("Failed", MeshProcessingMessages.NO_MESH.Msg(), "ok");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -174,7 +214,7 @@ namespace MeshUtility
|
|||
}
|
||||
else
|
||||
{
|
||||
EditorUtility.DisplayDialog("Failed", "No static mesh contained", "ok");
|
||||
EditorUtility.DisplayDialog("Failed", MeshProcessingMessages.NO_STATIC_MESH.Msg(), "ok");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
|
@ -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
|
||||
|
|
@ -32,15 +27,6 @@ namespace MeshUtility
|
|||
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()
|
||||
{
|
||||
|
|
@ -344,32 +330,35 @@ namespace MeshUtility
|
|||
// 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>())
|
||||
{
|
||||
|
|
@ -379,5 +368,22 @@ namespace MeshUtility
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -54,7 +56,6 @@ namespace MeshUtility
|
|||
}
|
||||
|
||||
var mesh = new Mesh();
|
||||
mesh.name = "MeshesIntegrated";
|
||||
|
||||
if (integrator.Positions.Count > ushort.MaxValue)
|
||||
{
|
||||
|
|
@ -77,6 +78,11 @@ namespace MeshUtility
|
|||
if (onlyBlendShapeRenderers)
|
||||
{
|
||||
integrator.AddBlendShapesToMesh(mesh);
|
||||
mesh.name = INTEGRATED_MESH_BLENDSHAPE_NAME;
|
||||
}
|
||||
else
|
||||
{
|
||||
mesh.name = INTEGRATED_MESH_NAME;
|
||||
}
|
||||
|
||||
var integrated = meshNode.AddComponent<SkinnedMeshRenderer>();
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ namespace MeshUtility
|
|||
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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user