diff --git a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs
new file mode 100644
index 000000000..4a4af9177
--- /dev/null
+++ b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs
@@ -0,0 +1,201 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+
+
+namespace UniGLTF.MeshUtility
+{
+ ///
+ /// - Freeze
+ /// - Integration
+ /// - Split
+ ///
+ /// - Implement runtime logic => Process a hierarchy in scene. Do not process prefab.
+ /// - Implement undo
+ ///
+ ///
+ public class GltfMeshUtility
+ {
+ ///
+ /// GameObject 名が重複している場合にリネームする。
+ /// 最初に実行(Avatar生成時のエラーを回避?)
+ ///
+ public bool ForceUniqueName = false;
+
+ ///
+ /// Same as VRM-0 normalization
+ /// - Mesh
+ /// - Node
+ /// - InverseBindMatrices
+ ///
+ public bool FreezeBlendShape = false;
+
+ ///
+ /// Same as VRM-0 normalization
+ /// - Mesh
+ /// - Node
+ /// - InverseBindMatrices
+ ///
+ public bool FreezeScaling = true;
+
+ ///
+ /// Same as VRM-0 normalization
+ /// - Mesh
+ /// - Node
+ /// - InverseBindMatrices
+ ///
+ public bool FreezeRotation = false;
+
+ public List MeshIntegrationGroups = new List();
+
+ ///
+ /// Create a headless model and solve VRM.FirstPersonFlag.Auto
+ ///
+ public bool GenerateMeshForFirstPersonAuto = false;
+
+ ///
+ /// Split into having and not having BlendShape
+ ///
+ public bool SplitByBlendShape = false;
+
+ public void IntegrateAll(GameObject root)
+ {
+ if (root == null)
+ {
+ return;
+ }
+ MeshIntegrationGroups.Add(new MeshIntegrationGroup
+ {
+ Name = "ALL",
+ Renderers = root.GetComponentsInChildren().ToList(),
+ });
+ }
+
+ void RemoveComponent(T c) where T : Component
+ {
+ if (c == null)
+ {
+ return;
+ }
+ var t = c.transform;
+ if (Application.isPlaying)
+ {
+ GameObject.Destroy(c);
+ }
+ else
+ {
+ GameObject.DestroyImmediate(c);
+ }
+
+ if (t.childCount == 0)
+ {
+ var list = t.GetComponents();
+ // Debug.Log($"{list[0].GetType().Name}");
+ if (list.Length == 1 && list[0] == t)
+ {
+ if (Application.isPlaying)
+ {
+ GameObject.Destroy(t.gameObject);
+ }
+ else
+ {
+ GameObject.DestroyImmediate(t.gameObject);
+ }
+ }
+ }
+ }
+
+ static GameObject GetOrCreateEmpty(GameObject go, string name)
+ {
+ foreach (var child in go.transform.GetChildren())
+ {
+ if (child.name == name
+ && child.localPosition == Vector3.zero
+ && child.localScale == Vector3.one
+ && child.localRotation == Quaternion.identity)
+ {
+ return child.gameObject;
+ }
+ }
+ var empty = new GameObject(name);
+ empty.transform.SetParent(go.transform, false);
+ return empty;
+ }
+
+ protected virtual List CopyMeshIntegrationGroups()
+ {
+ return MeshIntegrationGroups.ToList();
+ }
+
+ public virtual List Process(GameObject go)
+ {
+ // TODO unpack prefab
+
+ // 正規化されたヒエラルキーを作る
+ if (FreezeBlendShape || FreezeRotation || FreezeScaling)
+ {
+ var (normalized, boneMap) = BoneNormalizer.NormalizeHierarchyFreezeMesh(go,
+ removeScaling: FreezeScaling,
+ removeRotation: FreezeRotation,
+ freezeBlendShape: FreezeBlendShape);
+
+ // write back normalized transform to boneMap
+ BoneNormalizer.WriteBackResult(go, normalized, boneMap);
+ if (Application.isPlaying)
+ {
+ GameObject.Destroy(normalized);
+ }
+ else
+ {
+ GameObject.DestroyImmediate(normalized);
+ }
+ }
+
+ var copy = CopyMeshIntegrationGroups();
+
+ var newGo = new List();
+ {
+ var empty = GetOrCreateEmpty(go, "mesh");
+
+ var results = new List();
+ foreach (var group in copy)
+ {
+ Integrate(newGo, empty, results, group);
+ }
+
+ foreach (var result in results)
+ {
+ foreach (var r in result.SourceMeshRenderers)
+ {
+ RemoveComponent(r);
+ }
+ foreach (var r in result.SourceSkinnedMeshRenderers)
+ {
+ RemoveComponent(r);
+ }
+ }
+ }
+
+ MeshIntegrationGroups.Clear();
+
+ return newGo;
+ }
+
+ protected virtual MeshIntegrationResult Integrate(List newGo,
+ GameObject empty, List results, MeshIntegrationGroup group)
+ {
+ var result = MeshIntegrator.Integrate(group, SplitByBlendShape
+ ? MeshIntegrator.BlendShapeOperation.Split
+ : MeshIntegrator.BlendShapeOperation.Use);
+ results.Add(result);
+
+ foreach (var created in result.AddIntegratedRendererTo(empty))
+ {
+ newGo.Add(created);
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs.meta b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs.meta
new file mode 100644
index 000000000..0ad3bff31
--- /dev/null
+++ b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e2425cf6ac1f2434986968ff0d4a4755
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationGroup.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationGroup.cs
index 64a49c3e3..7d7158691 100644
--- a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationGroup.cs
+++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationGroup.cs
@@ -1,5 +1,5 @@
+using System;
using System.Collections.Generic;
-using System.Linq;
using UnityEngine;
namespace UniGLTF.MeshUtility
@@ -8,5 +8,10 @@ namespace UniGLTF.MeshUtility
{
public string Name;
public List Renderers = new List();
+
+ public static List ToList()
+ {
+ throw new NotImplementedException();
+ }
}
}
\ No newline at end of file
diff --git a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs
index e66253d80..48b79d617 100644
--- a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs
+++ b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs
@@ -1,93 +1,120 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using UniGLTF.MeshUtility;
using UniHumanoid;
using UnityEngine;
-using VRMShaders;
namespace UniVRM10
{
- ///
- /// - Freeze
- /// - Integration
- /// - Split
- ///
- /// - Implement runtime logic => Process a hierarchy in scene. Do not process prefab.
- /// - Implement undo
- ///
- ///
- public class Vrm10MeshUtility
+ public class Vrm10MeshUtility : UniGLTF.MeshUtility.GltfMeshUtility
{
- ///
- /// GameObject 名が重複している場合にリネームする。
- /// 最初に実行(Avatar生成時のエラーを回避?)
- ///
- public bool ForceUniqueName = false;
-
- ///
- /// Same as VRM-0 normalization
- /// - Mesh
- /// - Node
- /// - InverseBindMatrices
- ///
- public bool FreezeBlendShape = false;
-
- ///
- /// Same as VRM-0 normalization
- /// - Mesh
- /// - Node
- /// - InverseBindMatrices
- ///
- public bool FreezeScaling = true;
-
- ///
- /// Same as VRM-0 normalization
- /// - Mesh
- /// - Node
- /// - InverseBindMatrices
- ///
- public bool FreezeRotation = false;
-
- public List MeshIntegrationGroups = new List();
-
- ///
- /// Create a headless model and solve VRM.FirstPersonFlag.Auto
- ///
- public bool GenerateMeshForFirstPersonAuto = false;
-
- ///
- /// Split into having and not having BlendShape
- ///
- public bool SplitByBlendShape = false;
-
- public void IntegrateAll(GameObject root)
+ bool _generateFirstPerson = false;
+ protected override List CopyMeshIntegrationGroups()
{
- if (root == null)
+ var copy = new List();
+ _generateFirstPerson = false;
+ if (GenerateMeshForFirstPersonAuto)
{
- return;
- }
- MeshIntegrationGroups.Add(new MeshIntegrationGroup
- {
- Name = "ALL",
- Renderers = root.GetComponentsInChildren().ToList(),
- });
- }
-
- MeshIntegrationGroup GetOrCreateGroup(string name)
- {
- foreach (var g in MeshIntegrationGroups)
- {
- if (g.Name == name)
+ foreach (var g in MeshIntegrationGroups)
{
- return g;
+ if (g.Name == "auto")
+ {
+ _generateFirstPerson = true;
+ // 元のメッシュを三人称に変更
+ copy.Add(new UniGLTF.MeshUtility.MeshIntegrationGroup
+ {
+ Name = UniGLTF.Extensions.VRMC_vrm.FirstPersonType.thirdPersonOnly.ToString(),
+ Renderers = g.Renderers.ToList(),
+ });
+ }
+ copy.Add(g);
}
}
- MeshIntegrationGroups.Add(new MeshIntegrationGroup
+ else
{
- Name = name,
- });
- return MeshIntegrationGroups.Last();
+ copy.AddRange(MeshIntegrationGroups);
+ }
+ return copy;
+ }
+
+ protected override UniGLTF.MeshUtility.MeshIntegrationResult Integrate(List newGo,
+ GameObject empty,
+ List results,
+ UniGLTF.MeshUtility.MeshIntegrationGroup group)
+ {
+ var result = base.Integrate(newGo, empty, results, group);
+
+ if (_generateFirstPerson && group.Name == "auto")
+ {
+ Debug.Log("generateFirstPerson");
+ if (result.Integrated.Mesh != null)
+ {
+ _ProcessFirstPerson(_vrmInstance, result.Integrated);
+ }
+ if (result.IntegratedNoBlendShape.Mesh != null)
+ {
+ _ProcessFirstPerson(_vrmInstance, result.IntegratedNoBlendShape);
+ }
+ }
+
+ return result;
+ }
+
+ Vrm10Instance _vrmInstance = null;
+ ///
+ /// glTF に比べて Humanoid や FirstPerson の処理が追加される
+ ///
+ public override List Process(GameObject go)
+ {
+ _vrmInstance = go.GetComponent();
+ if (_vrmInstance == null)
+ {
+ throw new ArgumentException();
+ }
+
+ if (ForceUniqueName)
+ {
+ throw new NotImplementedException();
+
+ // 必用?
+ var animator = go.GetComponent();
+ var newAvatar = AvatarDescription.RecreateAvatar(animator);
+ animator.avatar = newAvatar;
+ }
+
+ // TODO: update: spring
+ // TODO: update: constraint
+ // TODO: update: firstPerson offset
+ var list = base.Process(go);
+
+ if (FreezeBlendShape || FreezeRotation || FreezeScaling)
+ {
+ var animator = go.GetComponent();
+ var newAvatar = AvatarDescription.RecreateAvatar(animator);
+ animator.avatar = newAvatar;
+ }
+
+ return list;
+ }
+
+ void _ProcessFirstPerson(Vrm10Instance vrmInstance, UniGLTF.MeshUtility.MeshInfo info)
+ {
+ var firstPersonBone = vrmInstance.Humanoid.Head;
+ var task = VRM10ObjectFirstPerson.CreateErasedMeshAsync(
+ info.IntegratedRenderer,
+ firstPersonBone,
+ new VRMShaders.ImmediateCaller());
+ task.Wait();
+
+ if (task.Result != null)
+ {
+ info.IntegratedRenderer.sharedMesh = task.Result;
+ info.IntegratedRenderer.name = "auto.headless";
+ }
+ else
+ {
+ Debug.LogWarning("no result");
+ }
}
public void IntegrateFirstPerson(GameObject root)
@@ -113,202 +140,25 @@ namespace UniVRM10
}
foreach (var a in fp.Renderers)
{
- var g = GetOrCreateGroup(a.FirstPersonFlag.ToString());
+ var g = _GetOrCreateGroup(a.FirstPersonFlag.ToString());
g.Renderers.Add(a.GetRenderer(root.transform));
}
}
- void RemoveComponent(T c) where T : Component
+ UniGLTF.MeshUtility.MeshIntegrationGroup _GetOrCreateGroup(string name)
{
- if (c == null)
+ foreach (var g in MeshIntegrationGroups)
{
- return;
- }
- var t = c.transform;
- if (Application.isPlaying)
- {
- GameObject.Destroy(c);
- }
- else
- {
- GameObject.DestroyImmediate(c);
- }
-
- if (t.childCount == 0)
- {
- var list = t.GetComponents();
- // Debug.Log($"{list[0].GetType().Name}");
- if (list.Length == 1 && list[0] == t)
+ if (g.Name == name)
{
- if (Application.isPlaying)
- {
- GameObject.Destroy(t.gameObject);
- }
- else
- {
- GameObject.DestroyImmediate(t.gameObject);
- }
+ return g;
}
}
- }
-
- static GameObject GetOrCreateEmpty(GameObject go, string name)
- {
- foreach (var child in go.transform.GetChildren())
+ MeshIntegrationGroups.Add(new UniGLTF.MeshUtility.MeshIntegrationGroup
{
- if (child.name == name
- && child.localPosition == Vector3.zero
- && child.localScale == Vector3.one
- && child.localRotation == Quaternion.identity)
- {
- return child.gameObject;
- }
- }
- var empty = new GameObject(name);
- empty.transform.SetParent(go.transform, false);
- return empty;
- }
-
- public List Process(GameObject go)
- {
- var vrmInstance = go.GetComponent();
- if (vrmInstance == null)
- {
- throw new ArgumentException();
- }
-
- // TODO unpack prefab
-
- if (ForceUniqueName)
- {
- throw new NotImplementedException();
-
- // 必用?
- var animator = go.GetComponent();
- var newAvatar = AvatarDescription.RecreateAvatar(animator);
- animator.avatar = newAvatar;
- }
-
- // 正規化されたヒエラルキーを作る
- if (FreezeBlendShape || FreezeRotation || FreezeScaling)
- {
- // TODO: UNDO
- var (normalized, boneMap) = BoneNormalizer.NormalizeHierarchyFreezeMesh(go,
- removeScaling: FreezeScaling,
- removeRotation: FreezeRotation,
- freezeBlendShape: FreezeBlendShape);
-
- // TODO: update: spring
- // TODO: update: constraint
- // TODO: update: firstPerson offset
-
- // write back normalized transform to boneMap
- BoneNormalizer.WriteBackResult(go, normalized, boneMap);
- if (Application.isPlaying)
- {
- GameObject.Destroy(normalized);
- }
- else
- {
- GameObject.DestroyImmediate(normalized);
- }
-
- var animator = go.GetComponent();
- var newAvatar = AvatarDescription.RecreateAvatar(animator);
- animator.avatar = newAvatar;
- }
-
- var copy = new List();
- var generateFirstPerson = false;
- if (GenerateMeshForFirstPersonAuto)
- {
- foreach (var g in MeshIntegrationGroups)
- {
- if (g.Name == "auto")
- {
- generateFirstPerson = true;
- // 元のメッシュを三人称に変更
- copy.Add(new MeshIntegrationGroup
- {
- Name = UniGLTF.Extensions.VRMC_vrm.FirstPersonType.thirdPersonOnly.ToString(),
- Renderers = g.Renderers.ToList(),
- });
- }
- copy.Add(g);
- }
- }
- else
- {
- copy.AddRange(MeshIntegrationGroups);
- }
-
- var newGo = new List();
- {
- var empty = GetOrCreateEmpty(go, "mesh");
-
- var results = new List();
- foreach (var group in copy)
- {
- var result = MeshIntegrator.Integrate(group, SplitByBlendShape
- ? MeshIntegrator.BlendShapeOperation.Split
- : MeshIntegrator.BlendShapeOperation.Use);
- results.Add(result);
-
- foreach (var created in result.AddIntegratedRendererTo(empty))
- {
- newGo.Add(created);
- }
-
- if (generateFirstPerson && group.Name == "auto")
- {
- Debug.Log("generateFirstPerson");
- if (result.Integrated.Mesh != null)
- {
- ProcessFirstPerson(vrmInstance, result.Integrated);
- }
- if (result.IntegratedNoBlendShape.Mesh != null)
- {
- ProcessFirstPerson(vrmInstance, result.IntegratedNoBlendShape);
- }
- }
- }
-
- foreach (var result in results)
- {
- foreach (var r in result.SourceMeshRenderers)
- {
- RemoveComponent(r);
- }
- foreach (var r in result.SourceSkinnedMeshRenderers)
- {
- RemoveComponent(r);
- }
- }
- }
-
- MeshIntegrationGroups.Clear();
-
- return newGo;
- }
-
- void ProcessFirstPerson(Vrm10Instance vrmInstance, MeshInfo info)
- {
- var firstPersonBone = vrmInstance.Humanoid.Head;
- var task = VRM10ObjectFirstPerson.CreateErasedMeshAsync(
- info.IntegratedRenderer,
- firstPersonBone,
- new ImmediateCaller());
- task.Wait();
-
- if (task.Result != null)
- {
- info.IntegratedRenderer.sharedMesh = task.Result;
- info.IntegratedRenderer.name = "auto.headless";
- }
- else
- {
- Debug.LogWarning("no result");
- }
+ Name = name,
+ });
+ return MeshIntegrationGroups.Last();
}
}
-}
+}
\ No newline at end of file