prefab と runtime で整合性。

- prefab 時は instance 化する。統合グループをの内容をインスタンス後のもので置き換える
- 未使用削除
This commit is contained in:
ousttrue 2023-11-29 20:02:46 +09:00
parent ddfe692164
commit f8f27d0619
9 changed files with 50 additions and 431 deletions

View File

@ -71,90 +71,8 @@ namespace UniGLTF.MeshUtility
void OnEnable()
{
// Clear(HelpMessage.Ready, ValidationError.None);
// OnValidate();
}
// void Clear(HelpMessage help, ValidationError error)
// {
// helpString = help.Msg();
// errorString = error != ValidationError.None ? error.Msg() : null;
// m_uniqueMaterials = new Material[] { };
// m_duplicateMaterials = new MaterialList[] { };
// m_excludes.Clear();
// isValid = false;
// }
// void OnValidate()
// {
// isValid = false;
// if (m_root == null)
// {
// Clear(HelpMessage.SetTarget, ValidationError.NoTarget);
// return;
// }
// if (m_root.GetGameObjectType() != GameObjectType.AssetPrefab)
// {
// Clear(HelpMessage.SetTarget, ValidationError.NotPrefab);
// return;
// }
// if (m_root.transform.parent != null)
// {
// Clear(HelpMessage.InvalidTarget, ValidationError.HasParent);
// return;
// }
// var backup = m_excludes.ToArray();
// Clear(HelpMessage.Ready, ValidationError.None);
// isValid = true;
// m_uniqueMaterials = MeshIntegratorUtility.EnumerateSkinnedMeshRenderer(m_root.transform, MeshEnumerateOption.OnlyWithoutBlendShape)
// .SelectMany(x => x.sharedMaterials)
// .Distinct()
// .ToArray();
// m_duplicateMaterials = m_uniqueMaterials
// .GroupBy(x => GetMaterialKey(x), x => x)
// .Select(x => new MaterialList(x.ToArray()))
// .Where(x => x.Materials.Length > 1)
// .ToArray()
// ;
// UpdateExcludes(backup);
// }
// void UpdateExcludes(ExcludeItem[] backup)
// {
// var exclude_map = new Dictionary<Mesh, ExcludeItem>();
// var excludes = new List<ExcludeItem>();
// foreach (var x in m_root.GetComponentsInChildren<Renderer>())
// {
// var mesh = x.GetMesh();
// if (mesh == null)
// {
// continue;
// }
// if (exclude_map.ContainsKey(mesh))
// {
// continue;
// }
// var item = new ExcludeItem
// {
// Mesh = mesh,
// };
// var found = backup.FirstOrDefault(y => y.Mesh == mesh);
// if (found != null)
// {
// item.Exclude = found.Exclude;
// }
// excludes.Add(item);
// exclude_map[mesh] = item;
// }
// m_excludes.AddRange(excludes);
// }
protected virtual void DialogMessage()
{
EditorGUILayout.HelpBox(MeshUtilityMessages.MESH_UTILITY.Msg(), MessageType.Info);
@ -290,7 +208,7 @@ namespace UniGLTF.MeshUtility
PrefabUtility.UnpackPrefabInstance(copy, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction);
}
var (results, created) = MeshUtility.Process(copy);
var (results, created) = MeshUtility.Process(_exportTarget, copy);
WriteAssets(copy, assetFolder, results);
@ -305,7 +223,7 @@ namespace UniGLTF.MeshUtility
{
PrefabUtility.UnpackPrefabInstance(_exportTarget, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction);
}
var (results, created) = MeshUtility.Process(_exportTarget);
var (results, created) = MeshUtility.Process(_exportTarget, null);
foreach (var go in created)
{
Undo.RegisterCreatedObjectUndo(go, "MeshUtility");

View File

@ -1,120 +0,0 @@
using System.Collections.Generic;
using System.IO;
using UniGLTF.M17N;
using UnityEditor;
using UnityEngine;
namespace UniGLTF.MeshUtility
{
public static class TabMeshIntegrator
{
public static bool TryExecutable(GameObject root, out string msg)
{
// check
if (root == null)
{
msg = MeshUtilityMessages.NO_GAMEOBJECT_SELECTED.Msg();
return false;
}
if (HasVrm(root))
{
msg = MeshUtilityMessages.VRM_DETECTED.Msg();
return false;
}
if (root.GetComponentsInChildren<SkinnedMeshRenderer>().Length == 0 && root.GetComponentsInChildren<MeshFilter>().Length == 0)
{
msg = MeshUtilityMessages.NO_MESH.Msg();
return false;
}
msg = "";
return true;
}
const string VRM_META = "VRMMeta";
static bool HasVrm(GameObject root)
{
var allComponents = root.GetComponents(typeof(Component));
foreach (var component in allComponents)
{
if (component == null) continue;
var sourceString = component.ToString();
if (sourceString.Contains(VRM_META))
{
return true;
}
}
return false;
}
const string ASSET_SUFFIX = ".mesh.asset";
static string GetMeshWritePath(Mesh mesh)
{
if (!string.IsNullOrEmpty((AssetDatabase.GetAssetPath(mesh))))
{
var directory = Path.GetDirectoryName(AssetDatabase.GetAssetPath(mesh)).Replace("\\", "/");
return $"{directory}/{Path.GetFileNameWithoutExtension(mesh.name)}{ASSET_SUFFIX}";
}
else
{
return $"Assets/{Path.GetFileNameWithoutExtension(mesh.name)}{ASSET_SUFFIX}";
}
}
/// <param name="src">GameObject instance in scene or prefab</param>
public static bool Execute(GameObject src, bool onlyBlendShapeRenderers)
{
var results = new List<MeshIntegrationResult>();
// instance or prefab => copy
var copy = GameObject.Instantiate(src);
copy.name = copy.name + "_mesh_integration";
// integrate
if (onlyBlendShapeRenderers)
{
results.Add(MeshIntegratorUtility.Integrate(copy, onlyBlendShapeRenderers: MeshEnumerateOption.OnlyWithBlendShape));
results.Add(MeshIntegratorUtility.Integrate(copy, onlyBlendShapeRenderers: MeshEnumerateOption.OnlyWithoutBlendShape));
}
else
{
results.Add(MeshIntegratorUtility.Integrate(copy, onlyBlendShapeRenderers: MeshEnumerateOption.All));
}
// replace
MeshIntegratorUtility.ReplaceMeshWithResults(copy, results);
// write mesh asset.
foreach (var result in results)
{
var mesh = result.Integrated.Mesh;
var assetPath = GetMeshWritePath(mesh);
Debug.LogFormat("CreateAsset: {0}", assetPath);
AssetDatabase.CreateAsset(mesh, assetPath);
}
if (src.GetGameObjectType() == GameObjectType.AssetPrefab)
{
// write prefab.
{
var prefabPath = UnityPath.FromAsset(src);
prefabPath = prefabPath.Parent.Child($"{prefabPath.FileNameWithoutExtension}_integrated.prefab");
Debug.LogFormat("WritePrefab: {0}", prefabPath);
PrefabUtility.SaveAsPrefabAsset(copy, prefabPath.Value);
}
// destroy copy in scene.
GameObject.DestroyImmediate(copy);
}
else
{
// do nothing. keep copy.
}
return true;
}
}
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 65a227dcf3cb5f34085bd6829894fb64
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -150,12 +150,31 @@ namespace UniGLTF.MeshUtility
return empty;
}
protected virtual List<MeshIntegrationGroup> CopyMeshIntegrationGroups()
/// <summary>
///
/// </summary>
/// <param name="go">MeshIntegrationGroup を作ったとき root</param>
/// <param name="instance">go が prefab だった場合に instance されたもの</param>
/// <returns></returns>
protected virtual IEnumerable<MeshIntegrationGroup> CopyInstantiate(GameObject go, GameObject instance)
{
return MeshIntegrationGroups.ToList();
if (instance == null)
{
foreach (var g in MeshIntegrationGroups)
{
yield return g;
}
}
else
{
foreach (var g in MeshIntegrationGroups)
{
yield return g.CopyInstantiate(go, instance);
}
}
}
public virtual (List<MeshIntegrationResult>, List<GameObject>) Process(GameObject go)
public virtual (List<MeshIntegrationResult>, List<GameObject>) Process(GameObject go, GameObject instance)
{
if (FreezeBlendShape || FreezeRotation || FreezeScaling)
{
@ -168,11 +187,11 @@ namespace UniGLTF.MeshUtility
BoneNormalizer.Replace(go, newMesh, FreezeRotation, FreezeScaling);
}
var copy = CopyMeshIntegrationGroups();
var copy = CopyInstantiate(go, instance);
var newList = new List<GameObject>();
var empty = GetOrCreateEmpty(go, "mesh");
var empty = GetOrCreateEmpty(instance ?? go, "mesh");
var results = new List<MeshIntegrationResult>();
foreach (var group in copy)

View File

@ -1,4 +1,3 @@
using System;
using System.Collections.Generic;
using UnityEngine;
@ -9,9 +8,25 @@ namespace UniGLTF.MeshUtility
public string Name;
public List<Renderer> Renderers = new List<Renderer>();
public static List<MeshIntegrationGroup> ToList()
public MeshIntegrationGroup CopyInstantiate(GameObject go, GameObject instance)
{
throw new NotImplementedException();
var copy = new MeshIntegrationGroup
{
Name = Name
};
foreach (var r in Renderers)
{
var relative = r.transform.RelativePathFrom(go.transform);
if (r is SkinnedMeshRenderer smr)
{
copy.Renderers.Add(instance.transform.GetFromPath(relative).GetComponent<SkinnedMeshRenderer>());
}
else if (r is MeshRenderer mr)
{
copy.Renderers.Add(instance.transform.GetFromPath(relative).GetComponent<MeshRenderer>());
}
}
return copy;
}
}
}

View File

@ -1,199 +0,0 @@
using System.Collections.Generic;
using UnityEngine;
namespace UniGLTF.MeshUtility
{
public static class MeshIntegratorUtility
{
public const string INTEGRATED_MESH_WITHOUT_BLENDSHAPE_NAME = "Integrated(WithoutBlendShape)";
public const string INTEGRATED_MESH_WITH_BLENDSHAPE_NAME = "Integrated(WithBlendShape)";
public const string INTEGRATED_MESH_ALL_NAME = "Integrated(All)";
/// <summary>
/// go を root としたヒエラルキーから Renderer を集めて、統合された Mesh 作成する
/// </summary>
/// <param name="go"></param>
/// <param name="onlyBlendShapeRenderers">
/// true: BlendShapeを保持するSkinnedMeshRendererのみ
/// false: BlendShapeを保持しないSkinnedMeshRenderer + MeshRenderer
/// null: すべてのSkinnedMeshRenderer + MeshRenderer
/// </param>
/// <returns></returns>
public static MeshIntegrationResult Integrate(GameObject go, MeshEnumerateOption onlyBlendShapeRenderers,
IEnumerable<Mesh> excludes = null,
bool destroyIntegratedRenderer = false)
{
var exclude = new MeshExclude(excludes);
var group = new MeshIntegrationGroup();
bool useBlendShape = false;
switch (onlyBlendShapeRenderers)
{
case MeshEnumerateOption.OnlyWithBlendShape:
{
group.Name = INTEGRATED_MESH_WITH_BLENDSHAPE_NAME;
useBlendShape = true;
foreach (var x in EnumerateSkinnedMeshRenderer(go.transform, onlyBlendShapeRenderers))
{
if (exclude.IsExcluded(x))
{
continue;
}
group.Renderers.Add(x);
}
break;
}
case MeshEnumerateOption.OnlyWithoutBlendShape:
{
group.Name = INTEGRATED_MESH_WITHOUT_BLENDSHAPE_NAME;
useBlendShape = false;
foreach (var x in EnumerateSkinnedMeshRenderer(go.transform, onlyBlendShapeRenderers))
{
if (exclude.IsExcluded(x))
{
continue;
}
group.Renderers.Add(x);
}
foreach (var x in EnumerateMeshRenderer(go.transform))
{
if (exclude.IsExcluded(x))
{
continue;
}
group.Renderers.Add(x);
}
break;
}
case MeshEnumerateOption.All:
{
group.Name = INTEGRATED_MESH_ALL_NAME;
useBlendShape = true;
foreach (var x in EnumerateSkinnedMeshRenderer(go.transform, onlyBlendShapeRenderers))
{
if (exclude.IsExcluded(x))
{
continue;
}
group.Renderers.Add(x);
}
foreach (var x in EnumerateMeshRenderer(go.transform))
{
if (exclude.IsExcluded(x))
{
continue;
}
group.Renderers.Add(x);
}
break;
}
}
return MeshIntegrator.Integrate(group, useBlendShape
? MeshIntegrator.BlendShapeOperation.Use
: MeshIntegrator.BlendShapeOperation.None);
}
public static IEnumerable<SkinnedMeshRenderer> EnumerateSkinnedMeshRenderer(Transform root, MeshEnumerateOption hasBlendShape)
{
foreach (var x in Traverse(root))
{
var renderer = x.GetComponent<SkinnedMeshRenderer>();
if (renderer != null &&
renderer.gameObject.activeInHierarchy &&
renderer.sharedMesh != null &&
renderer.enabled)
{
switch (hasBlendShape)
{
case MeshEnumerateOption.OnlyWithBlendShape:
if (renderer.sharedMesh.blendShapeCount > 0)
{
yield return renderer;
}
break;
case MeshEnumerateOption.OnlyWithoutBlendShape:
if (renderer.sharedMesh.blendShapeCount == 0)
{
yield return renderer;
}
break;
case MeshEnumerateOption.All:
{
yield return renderer;
break;
}
}
}
}
}
public static IEnumerable<MeshRenderer> EnumerateMeshRenderer(Transform root)
{
foreach (var x in Traverse(root))
{
var renderer = x.GetComponent<MeshRenderer>();
var filter = x.GetComponent<MeshFilter>();
if (renderer != null &&
filter != null &&
renderer.gameObject.activeInHierarchy &&
filter.sharedMesh != null)
{
yield return renderer;
}
}
}
private static IEnumerable<Transform> Traverse(Transform parent)
{
if (parent.gameObject.activeSelf)
{
yield return parent;
foreach (Transform child in parent)
{
foreach (var x in Traverse(child))
{
yield return x;
}
}
}
}
public static void ReplaceMeshWithResults(GameObject copy, List<MeshIntegrationResult> results)
{
// destroy original meshes
foreach (var skinnedMesh in copy.GetComponentsInChildren<SkinnedMeshRenderer>())
{
GameObject.DestroyImmediate(skinnedMesh);
}
foreach (var normalMesh in copy.GetComponentsInChildren<MeshFilter>())
{
if (normalMesh.gameObject.GetComponent<MeshRenderer>())
{
GameObject.DestroyImmediate(normalMesh.gameObject.GetComponent<MeshRenderer>());
}
GameObject.DestroyImmediate(normalMesh);
}
// Add integrated
foreach (var result in results)
{
result.AddIntegratedRendererTo(copy);
}
}
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: a982d9d30c0145038245b0214dc2f2e4
timeCreated: 1560190306

View File

@ -10,7 +10,7 @@ namespace VRM
public class VrmMeshUtility : UniGLTF.MeshUtility.GltfMeshUtility
{
bool _generateFirstPerson = false;
protected override List<UniGLTF.MeshUtility.MeshIntegrationGroup> CopyMeshIntegrationGroups()
protected override IEnumerable<UniGLTF.MeshUtility.MeshIntegrationGroup> CopyInstantiate(GameObject go, GameObject instance)
{
var copy = new List<UniGLTF.MeshUtility.MeshIntegrationGroup>();
_generateFirstPerson = false;
@ -84,7 +84,7 @@ namespace VRM
/// <summary>
/// glTF に比べて Humanoid や FirstPerson の処理が追加される
/// </summary>
public override (List<UniGLTF.MeshUtility.MeshIntegrationResult>, List<GameObject>) Process(GameObject go)
public override (List<UniGLTF.MeshUtility.MeshIntegrationResult>, List<GameObject>) Process(GameObject go, GameObject instance)
{
_vrmInstance = go.GetComponent<VRMFirstPerson>();
if (_vrmInstance == null)
@ -105,7 +105,7 @@ namespace VRM
// TODO: update: spring
// TODO: update: constraint
// TODO: update: firstPerson offset
var (list, newList) = base.Process(go);
var (list, newList) = base.Process(go, instance);
if (FreezeBlendShape || FreezeRotation || FreezeScaling)
{

View File

@ -10,7 +10,7 @@ namespace UniVRM10
public class Vrm10MeshUtility : UniGLTF.MeshUtility.GltfMeshUtility
{
bool _generateFirstPerson = false;
protected override List<UniGLTF.MeshUtility.MeshIntegrationGroup> CopyMeshIntegrationGroups()
protected override IEnumerable<UniGLTF.MeshUtility.MeshIntegrationGroup> CopyInstantiate(GameObject go, GameObject instance)
{
var copy = new List<UniGLTF.MeshUtility.MeshIntegrationGroup>();
_generateFirstPerson = false;
@ -89,7 +89,7 @@ namespace UniVRM10
/// <summary>
/// glTF に比べて Humanoid や FirstPerson の処理が追加される
/// </summary>
public override (List<UniGLTF.MeshUtility.MeshIntegrationResult>, List<GameObject>) Process(GameObject go)
public override (List<UniGLTF.MeshUtility.MeshIntegrationResult>, List<GameObject>) Process(GameObject go, GameObject instance)
{
_vrmInstance = go.GetComponent<Vrm10Instance>();
if (_vrmInstance == null)
@ -110,7 +110,7 @@ namespace UniVRM10
// TODO: update: spring
// TODO: update: constraint
// TODO: update: firstPerson offset
var (list, newList) = base.Process(go);
var (list, newList) = base.Process(go, instance);
if (FreezeBlendShape || FreezeRotation || FreezeScaling)
{