mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-08-23 02:55:07 -05:00
統合Meshをヒエラルキーに追加するタイミングをコピー後に変更
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user