統合Meshをヒエラルキーに追加するタイミングをコピー後に変更

This commit is contained in:
ousttrue
2022-05-16 16:44:01 +09:00
parent 1b01d6d8d7
commit 5fd2a743a1
5 changed files with 123 additions and 125 deletions

View File

@@ -1,4 +1,4 @@
using System.IO;
using System.Collections.Generic;
using UniGLTF.M17N;
using UnityEditor;
using UnityEngine;
@@ -7,8 +7,6 @@ namespace UniGLTF.MeshUtility
{
public static class TabMeshIntegrator
{
const string ASSET_SUFFIX = ".mesh.asset";
public static bool OnGUI(GameObject root, bool onlyBlendShapeRenderers)
{
var _isInvokeSuccess = false;
@@ -44,6 +42,7 @@ namespace UniGLTF.MeshUtility
static bool Execute(GameObject root, bool onlyBlendShapeRenderers)
{
// check
if (root == null)
{
EditorUtility.DisplayDialog("Failed", MeshProcessingMessages.NO_GAMEOBJECT_SELECTED.Msg(), "ok");
@@ -62,87 +61,22 @@ namespace UniGLTF.MeshUtility
return false;
}
// execute
var results = new List<MeshIntegrationResult>();
if (onlyBlendShapeRenderers)
{
MeshIntegratorUtility.Integrate(root, onlyBlendShapeRenderers: MeshEnumerateOption.OnlyWithBlendShape);
MeshIntegratorUtility.Integrate(root, onlyBlendShapeRenderers: MeshEnumerateOption.OnlyWithoutBlendShape);
results.Add(MeshIntegratorUtility.Integrate(root, onlyBlendShapeRenderers: MeshEnumerateOption.OnlyWithBlendShape));
results.Add(MeshIntegratorUtility.Integrate(root, onlyBlendShapeRenderers: MeshEnumerateOption.OnlyWithoutBlendShape));
}
else
{
MeshIntegratorUtility.Integrate(root, onlyBlendShapeRenderers: MeshEnumerateOption.All);
results.Add(MeshIntegratorUtility.Integrate(root, onlyBlendShapeRenderers: MeshEnumerateOption.All));
}
CopyAndSaveAssetEtc(root);
// 統合結果を適用した新しいヒエラルキーをコピーから作成する
MeshIntegratorUtility.CopyAndReplaceWithResults(root, results);
return true;
}
static void CopyAndSaveAssetEtc(GameObject root)
{
// copy hierarchy
var outputObject = GameObject.Instantiate(root);
outputObject.name = outputObject.name + "_mesh_integration";
var skinnedMeshes = outputObject.GetComponentsInChildren<SkinnedMeshRenderer>();
// destroy integrated meshes in the source
foreach (var skinnedMesh in root.GetComponentsInChildren<SkinnedMeshRenderer>())
{
if (skinnedMesh.sharedMesh.name == MeshIntegratorUtility.INTEGRATED_MESH_NAME ||
skinnedMesh.sharedMesh.name == MeshIntegratorUtility.INTEGRATED_MESH_BLENDSHAPE_NAME)
{
GameObject.DestroyImmediate(skinnedMesh.gameObject);
}
}
foreach (var skinnedMesh in skinnedMeshes)
{
// 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);
}
}
var normalMeshes = outputObject.GetComponentsInChildren<MeshFilter>();
foreach (var normalMesh in normalMeshes)
{
if (normalMesh.sharedMesh.name != MeshIntegratorUtility.INTEGRATED_MESH_NAME)
{
if (normalMesh.gameObject.GetComponent<MeshRenderer>())
{
GameObject.DestroyImmediate(normalMesh.gameObject.GetComponent<MeshRenderer>());
}
GameObject.DestroyImmediate(normalMesh);
}
}
}
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);
}
}
}

View File

@@ -25,7 +25,7 @@ namespace UniGLTF.MeshUtility
public Vector3[] Tangents;
}
public MeshIntegrationResult Result { get; } = new MeshIntegrationResult();
MeshIntegrationResult Result { get; } = new MeshIntegrationResult();
List<Vector3> Positions { get; } = new List<Vector3>();
List<Vector3> Normals { get; } = new List<Vector3>();
List<Vector2> UV { get; } = new List<Vector2>();
@@ -230,7 +230,7 @@ namespace UniGLTF.MeshUtility
}
}
public void Integrate(MeshEnumerateOption onlyBlendShapeRenderers)
public MeshIntegrationResult Integrate(MeshEnumerateOption onlyBlendShapeRenderers)
{
var mesh = new Mesh();
@@ -290,6 +290,7 @@ namespace UniGLTF.MeshUtility
integrated.bones = Bones.ToArray();
Result.IntegratedRenderer = integrated;
Result.MeshMap.Integrated = mesh;
return Result;
}
}
}

View File

@@ -1,10 +1,14 @@
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
namespace UniGLTF.MeshUtility
{
public static class MeshIntegratorUtility
{
const string ASSET_SUFFIX = ".mesh.asset";
public static string INTEGRATED_MESH_NAME => MeshIntegrator.INTEGRATED_MESH_NAME;
public static string INTEGRATED_MESH_BLENDSHAPE_NAME => MeshIntegrator.INTEGRATED_MESH_BLENDSHAPE_NAME;
@@ -19,7 +23,9 @@ namespace UniGLTF.MeshUtility
/// null: すべてのSkinnedMeshRenderer + MeshRenderer
/// </param>
/// <returns></returns>
public static MeshIntegrationResult Integrate(GameObject go, MeshEnumerateOption onlyBlendShapeRenderers, IEnumerable<Mesh> excludes = null)
public static MeshIntegrationResult Integrate(GameObject go, MeshEnumerateOption onlyBlendShapeRenderers,
IEnumerable<Mesh> excludes = null,
bool destroyIntegratedRenderer = false)
{
var exclude = new MeshExclude(excludes);
@@ -87,9 +93,7 @@ namespace UniGLTF.MeshUtility
}
}
integrator.Integrate(onlyBlendShapeRenderers);
integrator.Result.IntegratedRenderer.transform.SetParent(go.transform, false);
return integrator.Result;
return integrator.Integrate(onlyBlendShapeRenderers);
}
public static IEnumerable<SkinnedMeshRenderer> EnumerateSkinnedMeshRenderer(Transform root, MeshEnumerateOption hasBlendShape)
@@ -160,5 +164,54 @@ namespace UniGLTF.MeshUtility
}
}
}
public static void CopyAndReplaceWithResults(GameObject root, List<MeshIntegrationResult> results)
{
// copy hierarchy
var outputObject = GameObject.Instantiate(root);
outputObject.name = outputObject.name + "_mesh_integration";
// destroy original meshes in the copied GameObject
foreach (var skinnedMesh in outputObject.GetComponentsInChildren<SkinnedMeshRenderer>())
{
GameObject.DestroyImmediate(skinnedMesh);
}
foreach (var normalMesh in outputObject.GetComponentsInChildren<MeshFilter>())
{
if (normalMesh.sharedMesh.name != MeshIntegratorUtility.INTEGRATED_MESH_NAME)
{
if (normalMesh.gameObject.GetComponent<MeshRenderer>())
{
GameObject.DestroyImmediate(normalMesh.gameObject.GetComponent<MeshRenderer>());
}
GameObject.DestroyImmediate(normalMesh);
}
}
foreach (var result in results)
{
// Add integrated
result.IntegratedRenderer.transform.SetParent(outputObject.transform, false);
// save mesh data
SaveMeshData(result.IntegratedRenderer.sharedMesh);
}
}
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);
}
}
}

View File

@@ -217,6 +217,9 @@ namespace VRM
// helpString = "Set target gameobject `in scene`. Prefab not supported.";
}
/// <summary>
/// Prefab に対する操作として実装されている
/// </summary>
void Integrate()
{
var prefabPath = AssetDatabase.GetAssetPath(m_root);
@@ -241,33 +244,70 @@ namespace VRM
Undo.RecordObject(m_root, "Mesh Integration");
var instance = VrmPrefabUtility.InstantiatePrefab(m_root);
var clips = new List<BlendShapeClip>();
var proxy = instance.GetComponent<VRMBlendShapeProxy>();
if (proxy != null && proxy.BlendShapeAvatar != null)
{
clips = proxy.BlendShapeAvatar.Clips;
clips.AddRange(proxy.BlendShapeAvatar.Clips);
}
foreach (var clip in clips)
{
Undo.RecordObject(clip, "Mesh Integration");
}
_Integrate(instance, excludes, assetPath, clips);
// destroy source renderers
UnityEngine.Object.DestroyImmediate(instance);
}
void _Integrate(GameObject instance, IEnumerable<Mesh> excludes, UniGLTF.UnityPath assetPath, List<BlendShapeClip> clips)
{
// Execute
var results = VRMMeshIntegratorUtility.Integrate(instance, clips, excludes, m_separateByBlendShape);
// integrationResults = MeshIntegratorEditor.Integrate(m_root, assetPath, excludes, m_separateByBlendShape).Select(x => x.MeshMap).ToArray();
// public static List<MeshIntegrationResult> Integrate(GameObject prefab, UniGLTF.UnityPath writeAssetPath, IEnumerable<Mesh> excludes, bool separateByBlendShape)
var results = new List<UniGLTF.MeshUtility.MeshIntegrationResult>();
if (m_separateByBlendShape)
{
var withoutBlendShape = MeshIntegratorUtility.Integrate(instance, onlyBlendShapeRenderers: MeshEnumerateOption.OnlyWithoutBlendShape, excludes: excludes);
if (withoutBlendShape.IntegratedRenderer != null)
{
results.Add(withoutBlendShape);
}
var onlyBlendShape = MeshIntegratorUtility.Integrate(instance, onlyBlendShapeRenderers: MeshEnumerateOption.OnlyWithBlendShape, excludes: excludes);
if (onlyBlendShape.IntegratedRenderer != null)
{
results.Add(onlyBlendShape);
VRMMeshIntegratorUtility.FollowBlendshapeRendererChange(clips, onlyBlendShape, instance);
}
}
else
{
var integrated = MeshIntegratorUtility.Integrate(instance, onlyBlendShapeRenderers: MeshEnumerateOption.All, excludes: excludes);
if (integrated.IntegratedRenderer != null)
{
results.Add(integrated);
}
}
DeactivateOldRendererAndAddIntegrated(instance, results, assetPath,
UniGLTF.UnityPath.FromUnityPath(AssetDatabase.GetAssetPath(m_root)).Equals(assetPath));
}
static void DeactivateOldRendererAndAddIntegrated(GameObject instance, List<MeshIntegrationResult> results, UniGLTF.UnityPath assetPath,
bool applyToPrefab)
{
// TODO: add integrated
// disable source renderer
foreach (var res in results)
foreach (var result in results)
{
foreach (var renderer in res.SourceSkinnedMeshRenderers)
foreach (var renderer in result.SourceSkinnedMeshRenderers)
{
Undo.RecordObject(renderer.gameObject, "Deactivate old renderer");
renderer.gameObject.SetActive(false);
}
foreach (var renderer in res.SourceMeshRenderers)
foreach (var renderer in result.SourceMeshRenderers)
{
Undo.RecordObject(renderer.gameObject, "Deactivate old renderer");
renderer.gameObject.SetActive(false);
@@ -278,6 +318,10 @@ namespace VRM
{
if (result.IntegratedRenderer == null) continue;
// Add integrated
result.IntegratedRenderer.transform.SetParent(instance.transform, false);
// save as asset mesh
var childAssetPath = assetPath.Parent.Child($"{result.IntegratedRenderer.gameObject.name}{ASSET_SUFFIX}");
Debug.LogFormat("CreateAsset: {0}", childAssetPath);
childAssetPath.CreateAsset(result.IntegratedRenderer.sharedMesh);
@@ -285,7 +329,7 @@ namespace VRM
}
// Apply to Prefab
if (UniGLTF.UnityPath.FromUnityPath(AssetDatabase.GetAssetPath(m_root)).Equals(assetPath))
if (applyToPrefab)
{
VrmPrefabUtility.ApplyChangesToPrefab(instance);
}
@@ -297,9 +341,6 @@ namespace VRM
throw new System.Exception($"PrefabUtility.SaveAsPrefabAsset: {assetPath}");
}
}
// destroy source renderers
UnityEngine.Object.DestroyImmediate(instance);
}
void OnWizardCreate()

View File

@@ -11,38 +11,7 @@ namespace VRM
/// </summary>
public static class VRMMeshIntegratorUtility
{
public static List<UniGLTF.MeshUtility.MeshIntegrationResult> Integrate(GameObject root, List<BlendShapeClip> blendshapeClips, IEnumerable<Mesh> excludes, bool separateByBlendShape)
{
var result = new List<UniGLTF.MeshUtility.MeshIntegrationResult>();
if (separateByBlendShape)
{
var withoutBlendShape = MeshIntegratorUtility.Integrate(root, onlyBlendShapeRenderers: MeshEnumerateOption.OnlyWithoutBlendShape, excludes: excludes);
if (withoutBlendShape.IntegratedRenderer != null)
{
result.Add(withoutBlendShape);
}
var onlyBlendShape = MeshIntegratorUtility.Integrate(root, onlyBlendShapeRenderers: MeshEnumerateOption.OnlyWithBlendShape, excludes: excludes);
if (onlyBlendShape.IntegratedRenderer != null)
{
result.Add(onlyBlendShape);
FollowBlendshapeRendererChange(blendshapeClips, onlyBlendShape, root);
}
}
else
{
var integrated = MeshIntegratorUtility.Integrate(root, onlyBlendShapeRenderers: MeshEnumerateOption.All, excludes: excludes);
if (integrated.IntegratedRenderer != null)
{
result.Add(integrated);
}
}
return result;
}
private static void FollowBlendshapeRendererChange(List<BlendShapeClip> clips, MeshIntegrationResult result, GameObject root)
public static void FollowBlendshapeRendererChange(List<BlendShapeClip> clips, MeshIntegrationResult result, GameObject root)
{
if (clips == null || result == null || result.IntegratedRenderer == null || root == null) return;