From 8e6c005600fbaadc0777b558bc344ea7f290cf22 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 17 Nov 2023 19:36:57 +0900 Subject: [PATCH 01/25] =?UTF-8?q?GltfMeshUtility=20=E3=82=92=E5=9F=BA?= =?UTF-8?q?=E5=BA=95=E3=82=AF=E3=83=A9=E3=82=B9=E3=81=A8=E3=81=97=E3=81=A6?= =?UTF-8?q?=E5=88=87=E3=82=8A=E5=87=BA=E3=81=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Runtime/MeshUtility/GltfMeshUtility.cs | 201 ++++++++++ .../MeshUtility/GltfMeshUtility.cs.meta | 11 + .../MeshUtility/MeshIntegrationGroup.cs | 7 +- .../Runtime/MeshUtility/Vrm10MeshUtility.cs | 374 ++++++------------ 4 files changed, 330 insertions(+), 263 deletions(-) create mode 100644 Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs create mode 100644 Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs.meta 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 From c0d29dd2e606edec79e445c25a1201767748cd63 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 17 Nov 2023 19:58:10 +0900 Subject: [PATCH 02/25] UniGLTF.MeshUtility.MeshIntegrationTab --- .../MeshUtility/BoneMeshEraserEditor.cs | 43 ---- .../Editor/MeshUtility/MeshIntegrationTab.cs | 16 +- .../MeshUtility/MeshIntegrationTab.cs.meta | 2 +- .../Editor/MeshUtility/MeshUtilityDialog.cs | 205 ++++++++++++------ .../Editor/MeshUtility/Splitter.cs | 2 +- .../Editor/MeshUtility/Splitter.cs.meta | 2 +- .../MeshUtility/Vrm10MeshIntegrationTab.cs | 23 ++ .../Vrm10MeshIntegrationTab.cs.meta} | 2 +- .../MeshUtility/Vrm10MeshUtilityDialog.cs | 160 +++----------- 9 files changed, 205 insertions(+), 250 deletions(-) delete mode 100644 Assets/UniGLTF/Editor/MeshUtility/BoneMeshEraserEditor.cs rename Assets/{VRM10 => UniGLTF}/Editor/MeshUtility/MeshIntegrationTab.cs (87%) rename Assets/{VRM10 => UniGLTF}/Editor/MeshUtility/MeshIntegrationTab.cs.meta (83%) rename Assets/{VRM10 => UniGLTF}/Editor/MeshUtility/Splitter.cs (99%) rename Assets/{VRM10 => UniGLTF}/Editor/MeshUtility/Splitter.cs.meta (83%) create mode 100644 Assets/VRM10/Editor/MeshUtility/Vrm10MeshIntegrationTab.cs rename Assets/{UniGLTF/Editor/MeshUtility/BoneMeshEraserEditor.cs.meta => VRM10/Editor/MeshUtility/Vrm10MeshIntegrationTab.cs.meta} (83%) diff --git a/Assets/UniGLTF/Editor/MeshUtility/BoneMeshEraserEditor.cs b/Assets/UniGLTF/Editor/MeshUtility/BoneMeshEraserEditor.cs deleted file mode 100644 index 212e77b9b..000000000 --- a/Assets/UniGLTF/Editor/MeshUtility/BoneMeshEraserEditor.cs +++ /dev/null @@ -1,43 +0,0 @@ -using UniGLTF.M17N; -using UnityEditor; -using UnityEngine; - -namespace UniGLTF.MeshUtility -{ - /// - /// BoneMeshRemover 向けのエディタ。 - /// - /// SerializedProperty 経由で ユーザー定義 struct のフィールド - /// public List _eraseBones; - /// を EditorGUILayout.PropertyField するための細工である。 - /// - /// SerializedObject は UnityEngine.Object から作成するので、 - /// UnityEngine.Object を継承したクラスのフィールドに ユーザー定義 struct を配置する。 - /// 持ち主の SerializedObject を経由して EditorGUILayout.PropertyField してる。 - /// - [CustomEditor(typeof(MeshUtilityDialog), true)] - class BoneMeshEraserEditor : Editor - { - MeshUtilityDialog _targetDialog; - SerializedProperty _skinnedMesh; - SerializedProperty _eraseBones; - - void OnEnable() - { - _targetDialog = target as MeshUtilityDialog; - if (_targetDialog) - { - _skinnedMesh = serializedObject.FindProperty(nameof(MeshUtilityDialog._skinnedMeshRenderer)); - _eraseBones = serializedObject.FindProperty(nameof(MeshUtilityDialog._eraseBones)); - } - } - - public override void OnInspectorGUI() - { - serializedObject.Update(); - EditorGUILayout.PropertyField(_skinnedMesh); - EditorGUILayout.PropertyField(_eraseBones); - serializedObject.ApplyModifiedProperties(); - } - } -} diff --git a/Assets/VRM10/Editor/MeshUtility/MeshIntegrationTab.cs b/Assets/UniGLTF/Editor/MeshUtility/MeshIntegrationTab.cs similarity index 87% rename from Assets/VRM10/Editor/MeshUtility/MeshIntegrationTab.cs rename to Assets/UniGLTF/Editor/MeshUtility/MeshIntegrationTab.cs index fb3d5c0fb..cf90961e5 100644 --- a/Assets/VRM10/Editor/MeshUtility/MeshIntegrationTab.cs +++ b/Assets/UniGLTF/Editor/MeshUtility/MeshIntegrationTab.cs @@ -1,22 +1,21 @@ using System.Collections.Generic; -using UniGLTF.MeshUtility; using UnityEditor; using UnityEditorInternal; using UnityEngine; -namespace UniVRM10 +namespace UniGLTF.MeshUtility { - class MeshIntegrationTab + public class MeshIntegrationTab { bool _modified = false; - Vrm10MeshUtility _meshUti; + protected GltfMeshUtility _meshUti; Splitter _splitter; ReorderableList _groupList; ReorderableList _rendererList; public List _renderers = new List(); - int _selected = -1; - int Selected + protected int _selected = -1; + protected int Selected { set { @@ -34,7 +33,7 @@ namespace UniVRM10 } } - public MeshIntegrationTab(EditorWindow editor, Vrm10MeshUtility meshUtility) + public MeshIntegrationTab(EditorWindow editor, GltfMeshUtility meshUtility) { _meshUti = meshUtility; _splitter = new VerticalSplitter(editor, 200, 50); @@ -66,11 +65,10 @@ namespace UniVRM10 }; } - public void UpdateMeshIntegrationList(GameObject root) + public virtual void UpdateMeshIntegrationList(GameObject root) { _selected = -1; _meshUti.MeshIntegrationGroups.Clear(); - _meshUti.IntegrateFirstPerson(root); Selected = 0; } diff --git a/Assets/VRM10/Editor/MeshUtility/MeshIntegrationTab.cs.meta b/Assets/UniGLTF/Editor/MeshUtility/MeshIntegrationTab.cs.meta similarity index 83% rename from Assets/VRM10/Editor/MeshUtility/MeshIntegrationTab.cs.meta rename to Assets/UniGLTF/Editor/MeshUtility/MeshIntegrationTab.cs.meta index 91a743257..3ed1e2492 100644 --- a/Assets/VRM10/Editor/MeshUtility/MeshIntegrationTab.cs.meta +++ b/Assets/UniGLTF/Editor/MeshUtility/MeshIntegrationTab.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 07d031dea01a55c43b1ec68cd10bf461 +guid: 27b74253f485b4b45a8d2847ec3c2b34 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs b/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs index 17eeca36a..ba7ff48e9 100644 --- a/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs +++ b/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs @@ -2,34 +2,13 @@ using UnityEngine; using UnityEditor; using UniGLTF.M17N; using System.Collections.Generic; +using System.Linq; namespace UniGLTF.MeshUtility { public class MeshUtilityDialog : EditorWindow { public const string MENU_NAME = "glTF MeshUtility"; - enum MeshProcessDialogTabs - { - MeshSeparator, - MeshIntegrator, - BoneMeshEraser, - } - MeshProcessDialogTabs _tab; - - private GameObject _exportTarget; - - [SerializeField] - public bool _separateByBlendShape = true; - - [SerializeField] - public SkinnedMeshRenderer _skinnedMeshRenderer = null; - - [SerializeField] - public List _eraseBones; - - private BoneMeshEraserEditor _boneMeshEraserEditor; - private Vector2 _scrollPos = new Vector2(0, 0); - public static void OpenWindow() { var window = @@ -38,82 +17,182 @@ namespace UniGLTF.MeshUtility window.Show(); } - private void OnEnable() + protected enum Tabs { - if (!_boneMeshEraserEditor) + Freeze, + IntegrateSplit, + BoneMeshEraser, + } + protected Tabs _tab; + protected GameObject _exportTarget; + + GltfMeshUtility _meshUtil; + protected virtual GltfMeshUtility MeshUtility + { + get { - _boneMeshEraserEditor = (BoneMeshEraserEditor)Editor.CreateEditor(this); + if (_meshUtil == null) + { + _meshUtil = new GltfMeshUtility(); + } + return _meshUtil; } } + MeshIntegrationTab _integrationTab; + protected virtual MeshIntegrationTab MeshIntegration + { + get + { + if (_integrationTab == null) + { + _integrationTab = new MeshIntegrationTab(this, MeshUtility); + } + return _integrationTab; + } + } + + protected List _validations = new List(); + protected virtual void Validate() + { + _validations.Clear(); + if (_exportTarget == null) + { + _validations.Add(Validation.Error("set target GameObject")); + return; + } + } + bool IsValid => !_validations.Any(v => !v.CanExport); + Vector2 _scrollPos; + + void OnEnable() + { + } private void OnGUI() { + var modified = false; _scrollPos = EditorGUILayout.BeginScrollView(_scrollPos); EditorGUIUtility.labelWidth = 200; LanguageGetter.OnGuiSelectLang(); - _exportTarget = (GameObject)EditorGUILayout.ObjectField(MeshUtilityMessages.TARGET_OBJECT.Msg(), _exportTarget, typeof(GameObject), true); + var exportTarget = (GameObject)EditorGUILayout.ObjectField( + MeshUtilityMessages.TARGET_OBJECT.Msg(), + _exportTarget, typeof(GameObject), true); + if (exportTarget != _exportTarget) + { + _exportTarget = exportTarget; + MeshIntegration.UpdateMeshIntegrationList(_exportTarget); + modified = true; + } _tab = TabBar.OnGUI(_tab, "LargeButton", GUI.ToolbarButtonSize.Fixed); - var processed = false; + foreach (var validation in _validations) + { + validation.DrawGUI(); + } + + EditorGUILayout.HelpBox(MeshUtilityMessages.MESH_SEPARATOR.Msg(), MessageType.Info); + EditorGUILayout.HelpBox(MeshUtilityMessages.MESH_INTEGRATOR.Msg(), MessageType.Info); + switch (_tab) { - case MeshProcessDialogTabs.MeshSeparator: + case Tabs.Freeze: { - EditorGUILayout.HelpBox(MeshUtilityMessages.MESH_SEPARATOR.Msg(), MessageType.Info); - if (TabMeshSeparator.TryExecutable(_exportTarget, out string msg)) + if (MeshFreezeGui()) { - processed = TabMeshSeparator.OnGUI(_exportTarget); - } - else - { - EditorGUILayout.HelpBox(msg, MessageType.Error); + modified = true; } break; } - case MeshProcessDialogTabs.MeshIntegrator: + case Tabs.IntegrateSplit: { - EditorGUILayout.HelpBox(MeshUtilityMessages.MESH_INTEGRATOR.Msg(), MessageType.Info); - _separateByBlendShape = EditorGUILayout.Toggle(MeshUtilityMessages.MESH_SEPARATOR_BY_BLENDSHAPE.Msg(), _separateByBlendShape); - if (TabMeshIntegrator.TryExecutable(_exportTarget, out string msg)) + if (MeshIntegrateGui()) { - if (GUILayout.Button("Process", GUILayout.MinWidth(100))) - { - processed = TabMeshIntegrator.Execute(_exportTarget, _separateByBlendShape); - } - } - else - { - EditorGUILayout.HelpBox(msg, MessageType.Error); + modified = true; } break; } - case MeshProcessDialogTabs.BoneMeshEraser: + case Tabs.BoneMeshEraser: { + // TODO: FirstPerson 処理と統合する EditorGUILayout.HelpBox(MeshUtilityMessages.BONE_MESH_ERASER.Msg(), MessageType.Info); - if (_boneMeshEraserEditor) - { - _boneMeshEraserEditor.OnInspectorGUI(); - } - if (TabBoneMeshRemover.TryExecutable(_exportTarget, _skinnedMeshRenderer, out string msg)) - { - processed = TabBoneMeshRemover.OnGUI(_exportTarget, _skinnedMeshRenderer, _eraseBones); - } - else - { - EditorGUILayout.HelpBox(msg, MessageType.Error); - } + // if (_boneMeshEraserEditor) + // { + // _boneMeshEraserEditor.OnInspectorGUI(); + // } + // if (TabBoneMeshRemover.TryExecutable(_exportTarget, _skinnedMeshRenderer, out string msg)) + // { + // processed = TabBoneMeshRemover.OnGUI(_exportTarget, _skinnedMeshRenderer, _eraseBones); + // } + // else + // { + // EditorGUILayout.HelpBox(msg, MessageType.Error); + // } break; } } EditorGUILayout.EndScrollView(); - if (processed) + if (modified) { - Close(); - GUIUtility.ExitGUI(); + Validate(); } + + GUI.enabled = IsValid; + var pressed = GUILayout.Button("Process", GUILayout.MinWidth(100)); + GUI.enabled = true; + if (pressed) + { + Undo.RegisterFullObjectHierarchyUndo(exportTarget, "MeshUtility"); + foreach (var go in MeshUtility.Process(exportTarget)) + { + Undo.RegisterCreatedObjectUndo(go, "MeshUtility"); + } + _exportTarget = null; + // Show Result ? + // Close(); + // GUIUtility.ExitGUI(); + } + } + + protected bool ToggleIsModified(string label, ref bool value) + { + var newValue = EditorGUILayout.Toggle(label, value); + if (newValue == value) + { + return false; + } + value = newValue; + return true; + } + + bool MeshFreezeGui() + { + var forceUniqueName = ToggleIsModified("ForceUniqueName", ref MeshUtility.ForceUniqueName); + var blendShape = ToggleIsModified("BlendShape", ref MeshUtility.FreezeBlendShape); + var scale = ToggleIsModified("Scale", ref MeshUtility.FreezeScaling); + var rotation = ToggleIsModified("Rotation", ref MeshUtility.FreezeRotation); + return forceUniqueName || blendShape || scale || rotation; + } + + protected virtual bool MeshIntegrateGui() + { + var split = ToggleIsModified("Separate by BlendShape", ref MeshUtility.SplitByBlendShape); + var p = position; + var last = GUILayoutUtility.GetLastRect(); + var y = last.y + last.height; + var rect = new Rect + { + x = last.x, + y = y, + width = p.width, + height = p.height - y + // process button の高さ + - 30 + }; + var mod = MeshIntegration.OnGui(rect); + return split || mod; } } } \ No newline at end of file diff --git a/Assets/VRM10/Editor/MeshUtility/Splitter.cs b/Assets/UniGLTF/Editor/MeshUtility/Splitter.cs similarity index 99% rename from Assets/VRM10/Editor/MeshUtility/Splitter.cs rename to Assets/UniGLTF/Editor/MeshUtility/Splitter.cs index 743bae80c..f1fd2e221 100644 --- a/Assets/VRM10/Editor/MeshUtility/Splitter.cs +++ b/Assets/UniGLTF/Editor/MeshUtility/Splitter.cs @@ -2,7 +2,7 @@ using UnityEngine; using UnityEditor; using System; -namespace UniVRM10 +namespace UniGLTF.MeshUtility { [Serializable] public abstract class Splitter diff --git a/Assets/VRM10/Editor/MeshUtility/Splitter.cs.meta b/Assets/UniGLTF/Editor/MeshUtility/Splitter.cs.meta similarity index 83% rename from Assets/VRM10/Editor/MeshUtility/Splitter.cs.meta rename to Assets/UniGLTF/Editor/MeshUtility/Splitter.cs.meta index 57ca79cfc..4ef6a69d1 100644 --- a/Assets/VRM10/Editor/MeshUtility/Splitter.cs.meta +++ b/Assets/UniGLTF/Editor/MeshUtility/Splitter.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 385274edf555ed84a9f3706ca2a99023 +guid: dbb5f5bceb86592499a56fc18011553e MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/VRM10/Editor/MeshUtility/Vrm10MeshIntegrationTab.cs b/Assets/VRM10/Editor/MeshUtility/Vrm10MeshIntegrationTab.cs new file mode 100644 index 000000000..9a2d13fd8 --- /dev/null +++ b/Assets/VRM10/Editor/MeshUtility/Vrm10MeshIntegrationTab.cs @@ -0,0 +1,23 @@ +using UnityEditor; +using UnityEngine; + +namespace UniVRM10 +{ + class Vrm10MeshIntegrationTab : UniGLTF.MeshUtility.MeshIntegrationTab + { + Vrm10MeshUtility _vrmMeshUtil; + + public Vrm10MeshIntegrationTab(EditorWindow editor, Vrm10MeshUtility meshUtility) : base(editor, meshUtility) + { + _vrmMeshUtil = meshUtility; + } + + public override void UpdateMeshIntegrationList(GameObject root) + { + _selected = -1; + _meshUti.MeshIntegrationGroups.Clear(); + _vrmMeshUtil.IntegrateFirstPerson(root); + Selected = 0; + } + } +} \ No newline at end of file diff --git a/Assets/UniGLTF/Editor/MeshUtility/BoneMeshEraserEditor.cs.meta b/Assets/VRM10/Editor/MeshUtility/Vrm10MeshIntegrationTab.cs.meta similarity index 83% rename from Assets/UniGLTF/Editor/MeshUtility/BoneMeshEraserEditor.cs.meta rename to Assets/VRM10/Editor/MeshUtility/Vrm10MeshIntegrationTab.cs.meta index d256f2e98..078ce5177 100644 --- a/Assets/UniGLTF/Editor/MeshUtility/BoneMeshEraserEditor.cs.meta +++ b/Assets/VRM10/Editor/MeshUtility/Vrm10MeshIntegrationTab.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 2021859c0d7255643bd93c95ab3fcf3d +guid: ec2a4df10a08bab4a980b7203d341bda MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/VRM10/Editor/MeshUtility/Vrm10MeshUtilityDialog.cs b/Assets/VRM10/Editor/MeshUtility/Vrm10MeshUtilityDialog.cs index 1ac07d0b4..138421761 100644 --- a/Assets/VRM10/Editor/MeshUtility/Vrm10MeshUtilityDialog.cs +++ b/Assets/VRM10/Editor/MeshUtility/Vrm10MeshUtilityDialog.cs @@ -1,163 +1,61 @@ using UnityEngine; using UnityEditor; -using UniGLTF.M17N; -using System.Collections.Generic; -using UniGLTF.MeshUtility; using UniGLTF; -using System.Linq; namespace UniVRM10 { - public class Vrm10MeshUtilityDialog : EditorWindow + public class Vrm10MeshUtilityDialog : UniGLTF.MeshUtility.MeshUtilityDialog { - public const string MENU_NAME = "VRM 1.0 MeshUtility"; - - enum Tabs - { - Freeze, - IntegrateSplit, - } - Tabs _tab; - - public static void OpenWindow() + public new const string MENU_NAME = "VRM 1.0 MeshUtility"; + public new static void OpenWindow() { var window = (Vrm10MeshUtilityDialog)EditorWindow.GetWindow(typeof(Vrm10MeshUtilityDialog)); window.titleContent = new GUIContent(MENU_NAME); window.Show(); } - - Vrm10MeshUtility _meshUtility = new Vrm10MeshUtility(); - - List _validations = new List(); - private void Validate() + protected override void Validate() { - _validations.Clear(); - if (_exportTarget == null) - { - _validations.Add(Validation.Error("set vrm1")); - return; - } + base.Validate(); if (_exportTarget.GetComponent() == null) { _validations.Add(Validation.Error("target is not vrm1")); return; } } - bool IsValid => !_validations.Any(v => !v.CanExport); - Vector2 _scrollPos; - GameObject _exportTarget; - MeshIntegrationTab _meshIntegration; - void OnEnable() + Vrm10MeshUtility _meshUtil; + Vrm10MeshUtility Vrm10MeshUtility { - _meshIntegration = new MeshIntegrationTab(this, _meshUtility); - } - - private void OnGUI() - { - var modified = false; - _scrollPos = EditorGUILayout.BeginScrollView(_scrollPos); - EditorGUIUtility.labelWidth = 200; - LanguageGetter.OnGuiSelectLang(); - var exportTarget = (GameObject)EditorGUILayout.ObjectField( - MeshUtilityMessages.TARGET_OBJECT.Msg(), - _exportTarget, typeof(GameObject), true); - if (exportTarget != _exportTarget) + get { - _exportTarget = exportTarget; - _meshIntegration.UpdateMeshIntegrationList(_exportTarget); - modified = true; - } - _tab = TabBar.OnGUI(_tab, "LargeButton", GUI.ToolbarButtonSize.Fixed); - - foreach (var validation in _validations) - { - validation.DrawGUI(); - } - - switch (_tab) - { - case Tabs.Freeze: - { - if (MeshFreezeGui()) - { - modified = true; - } - break; - } - - case Tabs.IntegrateSplit: - { - if (MeshIntegrateGui()) - { - modified = true; - } - break; - } - } - EditorGUILayout.EndScrollView(); - - if (modified) - { - Validate(); - } - - GUI.enabled = IsValid; - var pressed = GUILayout.Button("Process", GUILayout.MinWidth(100)); - GUI.enabled = true; - if (pressed) - { - Undo.RegisterFullObjectHierarchyUndo(exportTarget, "MeshUtility"); - foreach (var go in _meshUtility.Process(exportTarget)) + if (_meshUtil == null) { - Undo.RegisterCreatedObjectUndo(go, "MeshUtility"); + _meshUtil = new Vrm10MeshUtility(); } - _exportTarget = null; - // Show Result ? - // Close(); - // GUIUtility.ExitGUI(); + return _meshUtil; + } + } + protected override UniGLTF.MeshUtility.GltfMeshUtility MeshUtility => Vrm10MeshUtility; + + Vrm10MeshIntegrationTab _integrationTab; + protected override UniGLTF.MeshUtility.MeshIntegrationTab MeshIntegration + { + get + { + if (_integrationTab == null) + { + _integrationTab = new Vrm10MeshIntegrationTab(this, Vrm10MeshUtility); + } + return _integrationTab; } } - bool ToggleIsModified(string label, ref bool value) + protected override bool MeshIntegrateGui() { - var newValue = EditorGUILayout.Toggle(label, value); - if (newValue == value) - { - return false; - } - value = newValue; - return true; - } - - bool MeshFreezeGui() - { - var forceUniqueName = ToggleIsModified("ForceUniqueName", ref _meshUtility.ForceUniqueName); - var blendShape = ToggleIsModified("BlendShape", ref _meshUtility.FreezeBlendShape); - var scale = ToggleIsModified("Scale", ref _meshUtility.FreezeScaling); - var rotation = ToggleIsModified("Rotation", ref _meshUtility.FreezeRotation); - return forceUniqueName || blendShape || scale || rotation; - } - - bool MeshIntegrateGui() - { - var firstPerson = ToggleIsModified("FirstPerson == AUTO の生成", ref _meshUtility.GenerateMeshForFirstPersonAuto); - var split = ToggleIsModified("Separate by BlendShape", ref _meshUtility.SplitByBlendShape); - var p = position; - var last = GUILayoutUtility.GetLastRect(); - var y = last.y + last.height; - var rect = new Rect - { - x = last.x, - y = y, - width = p.width, - height = p.height - y - // process button の高さ - - 30 - }; - var mod = _meshIntegration.OnGui(rect); - return firstPerson || split || mod; + var firstPerson = ToggleIsModified("FirstPerson == AUTO の生成", ref MeshUtility.GenerateMeshForFirstPersonAuto); + var mod = base.MeshIntegrateGui(); + return firstPerson || mod; } } } \ No newline at end of file From 0394b2a5fe664b4daf45c81666519f36f89bfe29 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 17 Nov 2023 21:39:40 +0900 Subject: [PATCH 03/25] UpdateMeshIntegrationGroups --- .../Editor/MeshUtility/MeshIntegrationTab.cs | 16 +++++------ .../Runtime/MeshUtility/GltfMeshUtility.cs | 27 +++++++++++++++++++ .../MeshUtility/Vrm10MeshIntegrationTab.cs | 8 ------ .../Runtime/MeshUtility/Vrm10MeshUtility.cs | 18 +------------ 4 files changed, 36 insertions(+), 33 deletions(-) diff --git a/Assets/UniGLTF/Editor/MeshUtility/MeshIntegrationTab.cs b/Assets/UniGLTF/Editor/MeshUtility/MeshIntegrationTab.cs index cf90961e5..6c9c6ec93 100644 --- a/Assets/UniGLTF/Editor/MeshUtility/MeshIntegrationTab.cs +++ b/Assets/UniGLTF/Editor/MeshUtility/MeshIntegrationTab.cs @@ -8,7 +8,7 @@ namespace UniGLTF.MeshUtility public class MeshIntegrationTab { bool _modified = false; - protected GltfMeshUtility _meshUti; + protected GltfMeshUtility _meshUtil; Splitter _splitter; ReorderableList _groupList; @@ -23,29 +23,29 @@ namespace UniGLTF.MeshUtility { return; } - if (value < 0 || value >= _meshUti.MeshIntegrationGroups.Count) + if (value < 0 || value >= _meshUtil.MeshIntegrationGroups.Count) { return; } _selected = value; _renderers.Clear(); - _renderers.AddRange(_meshUti.MeshIntegrationGroups[_selected].Renderers); + _renderers.AddRange(_meshUtil.MeshIntegrationGroups[_selected].Renderers); } } public MeshIntegrationTab(EditorWindow editor, GltfMeshUtility meshUtility) { - _meshUti = meshUtility; + _meshUtil = meshUtility; _splitter = new VerticalSplitter(editor, 200, 50); - _groupList = new ReorderableList(_meshUti.MeshIntegrationGroups, typeof(MeshIntegrationGroup)); + _groupList = new ReorderableList(_meshUtil.MeshIntegrationGroups, typeof(MeshIntegrationGroup)); _groupList.drawHeaderCallback = (Rect rect) => { GUI.Label(rect, "Integration group"); }; _groupList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) => { - var group = _meshUti.MeshIntegrationGroups[index]; + var group = _meshUtil.MeshIntegrationGroups[index]; EditorGUI.TextField(rect, group.Name); }; _groupList.onSelectCallback = rl => @@ -65,10 +65,10 @@ namespace UniGLTF.MeshUtility }; } - public virtual void UpdateMeshIntegrationList(GameObject root) + public void UpdateMeshIntegrationList(GameObject root) { _selected = -1; - _meshUti.MeshIntegrationGroups.Clear(); + _meshUtil.UpdateMeshIntegrationGroups(root); Selected = 0; } diff --git a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs index 4a4af9177..41e1132f5 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs @@ -59,6 +59,33 @@ namespace UniGLTF.MeshUtility /// public bool SplitByBlendShape = false; + protected UniGLTF.MeshUtility.MeshIntegrationGroup _GetOrCreateGroup(string name) + { + foreach (var g in MeshIntegrationGroups) + { + if (g.Name == name) + { + return g; + } + } + MeshIntegrationGroups.Add(new UniGLTF.MeshUtility.MeshIntegrationGroup + { + Name = name, + }); + return MeshIntegrationGroups.Last(); + } + + public virtual void UpdateMeshIntegrationGroups(GameObject root) + { + MeshIntegrationGroups.Clear(); + if (root == null) + { + return; + } + var group = _GetOrCreateGroup("all mesh"); + group.Renderers.AddRange(root.GetComponentsInChildren()); + } + public void IntegrateAll(GameObject root) { if (root == null) diff --git a/Assets/VRM10/Editor/MeshUtility/Vrm10MeshIntegrationTab.cs b/Assets/VRM10/Editor/MeshUtility/Vrm10MeshIntegrationTab.cs index 9a2d13fd8..4bee935da 100644 --- a/Assets/VRM10/Editor/MeshUtility/Vrm10MeshIntegrationTab.cs +++ b/Assets/VRM10/Editor/MeshUtility/Vrm10MeshIntegrationTab.cs @@ -11,13 +11,5 @@ namespace UniVRM10 { _vrmMeshUtil = meshUtility; } - - public override void UpdateMeshIntegrationList(GameObject root) - { - _selected = -1; - _meshUti.MeshIntegrationGroups.Clear(); - _vrmMeshUtil.IntegrateFirstPerson(root); - Selected = 0; - } } } \ No newline at end of file diff --git a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs index 48b79d617..60e665dd5 100644 --- a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs +++ b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs @@ -117,7 +117,7 @@ namespace UniVRM10 } } - public void IntegrateFirstPerson(GameObject root) + public override void UpdateMeshIntegrationGroups(GameObject root) { if (root == null) { @@ -144,21 +144,5 @@ namespace UniVRM10 g.Renderers.Add(a.GetRenderer(root.transform)); } } - - UniGLTF.MeshUtility.MeshIntegrationGroup _GetOrCreateGroup(string name) - { - foreach (var g in MeshIntegrationGroups) - { - if (g.Name == name) - { - return g; - } - } - MeshIntegrationGroups.Add(new UniGLTF.MeshUtility.MeshIntegrationGroup - { - Name = name, - }); - return MeshIntegrationGroups.Last(); - } } } \ No newline at end of file From 6dd4320656945e823e46bbf1085e7f6ae5a4f237 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Tue, 21 Nov 2023 18:19:18 +0900 Subject: [PATCH 04/25] TargetIsPrefab and DialogMessage --- .../UniGLTF/Editor/MeshUtility/MaterialKey.cs | 82 ++++ .../Editor/MeshUtility/MaterialKey.cs.meta | 11 + .../Editor/MeshUtility/MeshUtilityDialog.cs | 270 ++++++++++-- .../Editor/MeshUtility/MeshUtilityMessages.cs | 93 ++-- .../Runtime/MeshUtility/GltfMeshUtility.cs | 47 +- .../VrmMeshIntegratorWizard.cs | 406 +++--------------- Assets/VRM/Editor/VrmTopMenu.cs | 2 +- .../MeshUtility/Vrm10MeshUtilityDialog.cs | 47 ++ .../Runtime/MeshUtility/Vrm10MeshUtility.cs | 16 +- 9 files changed, 534 insertions(+), 440 deletions(-) create mode 100644 Assets/UniGLTF/Editor/MeshUtility/MaterialKey.cs create mode 100644 Assets/UniGLTF/Editor/MeshUtility/MaterialKey.cs.meta diff --git a/Assets/UniGLTF/Editor/MeshUtility/MaterialKey.cs b/Assets/UniGLTF/Editor/MeshUtility/MaterialKey.cs new file mode 100644 index 000000000..f7f2832d3 --- /dev/null +++ b/Assets/UniGLTF/Editor/MeshUtility/MaterialKey.cs @@ -0,0 +1,82 @@ +// namespace UniGLTF.MeshUtility +// { +// [Serializable] +// struct MaterialKey +// { +// public string Shader; +// public KeyValuePair[] Properties; + +// public override bool Equals(object obj) +// { +// if (!(obj is MaterialKey)) +// { +// return base.Equals(obj); +// } + +// var key = (MaterialKey)obj; + +// return Shader == key.Shader +// && Properties.SequenceEqual(key.Properties) +// ; +// } + +// public override int GetHashCode() +// { +// return base.GetHashCode(); +// } +// } + +// [Serializable] +// struct MaterialList +// { +// public Material[] Materials; + +// public MaterialList(Material[] list) +// { +// Materials = list; +// } +// } + +// static object GetPropertyValue(Shader shader, int i, Material m) +// { +// var propType = ShaderUtil.GetPropertyType(shader, i); +// switch (propType) +// { +// case ShaderUtil.ShaderPropertyType.Color: +// return m.GetColor(ShaderUtil.GetPropertyName(shader, i)); + +// case ShaderUtil.ShaderPropertyType.Range: +// case ShaderUtil.ShaderPropertyType.Float: +// return m.GetFloat(ShaderUtil.GetPropertyName(shader, i)); + +// case ShaderUtil.ShaderPropertyType.Vector: +// return m.GetVector(ShaderUtil.GetPropertyName(shader, i)); + +// case ShaderUtil.ShaderPropertyType.TexEnv: +// return m.GetTexture(ShaderUtil.GetPropertyName(shader, i)); + +// default: +// throw new NotImplementedException(propType.ToString()); +// } +// } + +// static MaterialKey GetMaterialKey(Material m) +// { +// var key = new MaterialKey +// { +// Shader = m.shader.name, +// }; + +// key.Properties = Enumerable.Range(0, ShaderUtil.GetPropertyCount(m.shader)) +// .Select(x => new KeyValuePair( +// ShaderUtil.GetPropertyName(m.shader, x), +// GetPropertyValue(m.shader, x, m)) +// ) +// .OrderBy(x => x.Key) +// .ToArray() +// ; + +// return key; +// } + +// } \ No newline at end of file diff --git a/Assets/UniGLTF/Editor/MeshUtility/MaterialKey.cs.meta b/Assets/UniGLTF/Editor/MeshUtility/MaterialKey.cs.meta new file mode 100644 index 000000000..e6645775a --- /dev/null +++ b/Assets/UniGLTF/Editor/MeshUtility/MaterialKey.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 91c86a6f42c50c9438c124f0dbd048a7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs b/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs index ba7ff48e9..07faa5bfd 100644 --- a/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs +++ b/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs @@ -3,12 +3,15 @@ using UnityEditor; using UniGLTF.M17N; using System.Collections.Generic; using System.Linq; +using System.IO; + namespace UniGLTF.MeshUtility { public class MeshUtilityDialog : EditorWindow { public const string MENU_NAME = "glTF MeshUtility"; + protected const string ASSET_SUFFIX = ".mesh.asset"; public static void OpenWindow() { var window = @@ -21,7 +24,6 @@ namespace UniGLTF.MeshUtility { Freeze, IntegrateSplit, - BoneMeshEraser, } protected Tabs _tab; protected GameObject _exportTarget; @@ -62,10 +64,109 @@ namespace UniGLTF.MeshUtility } } bool IsValid => !_validations.Any(v => !v.CanExport); + + MeshInfo[] integrationResults; + Vector2 _scrollPos; 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(); + // var excludes = new List(); + // foreach (var x in m_root.GetComponentsInChildren()) + // { + // 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); + // } + + /// + /// Scene と Prefab で挙動をスイッチする。 + /// + /// - Scene: ヒエラルキーを操作する。Asset の 書き出しはしない。UNDO はする。TODO: 明示的な Asset の書き出し。 + /// - Prefab: 対象をコピーして処理する。Undo は実装しない。結果を Asset として書き出し、処理後にコピーは削除する。 + /// + /// + bool TargetIsPrefab => _exportTarget != null && _exportTarget.scene.name == null; + + protected virtual void DialogMessage() + { + EditorGUILayout.HelpBox(MeshUtilityMessages.MESH_UTILITY.Msg(), MessageType.Info); } private void OnGUI() @@ -74,6 +175,9 @@ namespace UniGLTF.MeshUtility _scrollPos = EditorGUILayout.BeginScrollView(_scrollPos); EditorGUIUtility.labelWidth = 200; LanguageGetter.OnGuiSelectLang(); + + DialogMessage(); + var exportTarget = (GameObject)EditorGUILayout.ObjectField( MeshUtilityMessages.TARGET_OBJECT.Msg(), _exportTarget, typeof(GameObject), true); @@ -83,6 +187,14 @@ namespace UniGLTF.MeshUtility MeshIntegration.UpdateMeshIntegrationList(_exportTarget); modified = true; } + + // GameObject or Prefab ? + if (TargetIsPrefab) + { + EditorGUILayout.HelpBox(MeshUtilityMessages.PREFAB_TARGET.Msg(), MessageType.Warning); + } + + // tab bar _tab = TabBar.OnGUI(_tab, "LargeButton", GUI.ToolbarButtonSize.Fixed); foreach (var validation in _validations) @@ -90,9 +202,6 @@ namespace UniGLTF.MeshUtility validation.DrawGUI(); } - EditorGUILayout.HelpBox(MeshUtilityMessages.MESH_SEPARATOR.Msg(), MessageType.Info); - EditorGUILayout.HelpBox(MeshUtilityMessages.MESH_INTEGRATOR.Msg(), MessageType.Info); - switch (_tab) { case Tabs.Freeze: @@ -113,24 +222,26 @@ namespace UniGLTF.MeshUtility break; } - case Tabs.BoneMeshEraser: - { - // TODO: FirstPerson 処理と統合する - EditorGUILayout.HelpBox(MeshUtilityMessages.BONE_MESH_ERASER.Msg(), MessageType.Info); - // if (_boneMeshEraserEditor) - // { - // _boneMeshEraserEditor.OnInspectorGUI(); - // } - // if (TabBoneMeshRemover.TryExecutable(_exportTarget, _skinnedMeshRenderer, out string msg)) - // { - // processed = TabBoneMeshRemover.OnGUI(_exportTarget, _skinnedMeshRenderer, _eraseBones); - // } - // else - // { - // EditorGUILayout.HelpBox(msg, MessageType.Error); - // } - break; - } + // TODO: + // Mesh統合のオプション + // case Tabs.BoneMeshEraser: + // { + // // TODO: FirstPerson 処理と統合する + // EditorGUILayout.HelpBox(MeshUtilityMessages.BONE_MESH_ERASER.Msg(), MessageType.Info); + // // if (_boneMeshEraserEditor) + // // { + // // _boneMeshEraserEditor.OnInspectorGUI(); + // // } + // // if (TabBoneMeshRemover.TryExecutable(_exportTarget, _skinnedMeshRenderer, out string msg)) + // // { + // // processed = TabBoneMeshRemover.OnGUI(_exportTarget, _skinnedMeshRenderer, _eraseBones); + // // } + // // else + // // { + // // EditorGUILayout.HelpBox(msg, MessageType.Error); + // // } + // break; + // } } EditorGUILayout.EndScrollView(); @@ -144,18 +255,121 @@ namespace UniGLTF.MeshUtility GUI.enabled = true; if (pressed) { - Undo.RegisterFullObjectHierarchyUndo(exportTarget, "MeshUtility"); - foreach (var go in MeshUtility.Process(exportTarget)) + if (TargetIsPrefab) { - Undo.RegisterCreatedObjectUndo(go, "MeshUtility"); + /// [prefab] + /// + /// * backup するのではなく 変更した copy を作成する。元は変えない + /// * copy 先の統合前の renderer を disable で残さず destroy する + /// * 実行すると mesh, blendshape, blendShape を新規に作成する + /// * 新しいヒエラルキーを prefab に保存してから削除して終了する + + // 出力フォルダを決める + var folder = "Assets"; + var prefab = _exportTarget.GetPrefab(); + if (prefab != null) + { + folder = AssetDatabase.GetAssetPath(prefab); + // Debug.Log(folder); + } + // 新規で作成されるアセットはすべてこのフォルダの中に作る。上書きチェックはしない + var assetFolder = EditorUtility.SaveFolderPanel("select asset save folder", Path.GetDirectoryName(folder), "VrmIntegrated"); + var unityPath = UniGLTF.UnityPath.FromFullpath(assetFolder); + if (!unityPath.IsUnderWritableFolder) + { + EditorUtility.DisplayDialog("asset folder", "Target folder must be in the Assets or writable Packages folder", "cancel"); + return; + } + assetFolder = unityPath.Value; + + var copy = GameObject.Instantiate(_exportTarget); + + var (results, created) = MeshUtility.Process(copy); + + WriteAssets(copy, assetFolder, results); + + // destroy scene + UnityEngine.Object.DestroyImmediate(copy); } + else + { + Undo.RegisterFullObjectHierarchyUndo(_exportTarget, "MeshUtility"); + var (results, created) = MeshUtility.Process(_exportTarget); + foreach (var go in created) + { + Undo.RegisterCreatedObjectUndo(go, "MeshUtility"); + } + } + + // TODO: Show Result ? _exportTarget = null; - // Show Result ? - // Close(); - // GUIUtility.ExitGUI(); } } + void WriteAssets(GameObject copy, string assetFolder, List results) + { + // + // write mesh asset + foreach (var result in results) + { + var childAssetPath = $"{assetFolder}/{result.Integrated.IntegratedRenderer.gameObject.name}{ASSET_SUFFIX}"; + Debug.LogFormat("CreateAsset: {0}", childAssetPath); + AssetDatabase.CreateAsset(result.Integrated.IntegratedRenderer.sharedMesh, childAssetPath); + } + + // 統合した結果をヒエラルキーに追加する + foreach (var result in results) + { + if (result.Integrated.IntegratedRenderer != null) + { + result.Integrated.IntegratedRenderer.transform.SetParent(copy.transform, false); + } + } + + // 統合した結果を反映した BlendShapeClip を作成して置き換える + // var clips = VRMMeshIntegratorUtility.FollowBlendshapeRendererChange(results, copy, assetFolder); + + // 用が済んだ 統合前 の renderer を削除する + foreach (var result in results) + { + foreach (var renderer in result.SourceMeshRenderers) + { + GameObject.DestroyImmediate(renderer); + } + foreach (var renderer in result.SourceSkinnedMeshRenderers) + { + GameObject.DestroyImmediate(renderer); + } + } + + // reset firstperson + // var firstperson = copy.GetComponent(); + // if (firstperson != null) + // { + // firstperson.Reset(); + // } + + // prefab + var prefabPath = $"{assetFolder}/VrmIntegrated.prefab"; + Debug.Log(prefabPath); + PrefabUtility.SaveAsPrefabAsset(copy, prefabPath, out bool success); + if (!success) + { + throw new System.Exception($"PrefabUtility.SaveAsPrefabAsset: {prefabPath}"); + } + + // var prefabReference = AssetDatabase.LoadAssetAtPath(prefabPath); + // foreach (var clip in clips) + // { + // var so = new SerializedObject(clip); + // so.Update(); + // // clip.Prefab = copy; + // var prop = so.FindProperty("m_prefab"); + // prop.objectReferenceValue = prefabReference; + // so.ApplyModifiedProperties(); + // } + } + protected bool ToggleIsModified(string label, ref bool value) { var newValue = EditorGUILayout.Toggle(label, value); diff --git a/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityMessages.cs b/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityMessages.cs index f87c06c5b..c48251e22 100644 --- a/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityMessages.cs +++ b/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityMessages.cs @@ -8,61 +8,80 @@ namespace UniGLTF.MeshUtility [LangMsg(Languages.en, "TargetObject")] TARGET_OBJECT, - [LangMsg(Languages.ja, @"ターゲットオブジェクト下の SkinnedMeshRenderer にアタッチされたメッシュを、 BlendShape の有無で分割します。 + [LangMsg(Languages.ja, @"凍結 > 統合 > 分割 という一連の処理を実行します。 -* Asset: 新しい Mesh Asset が元と同じフォルダに作成されます。例: Original -> Original_WithBlendShape.mesh & Original_WithoutBlendShape.mesh -* Scene: コピーされたヒエラルキーでは、分割された Mesh は BlendShape のある Mesh で置き換えられて、BlendShape の無い Mesh を使った SkinnedMeshRenderer が追加されます。 +[凍結] +- ヒエラルキーの 回転・拡縮を Mesh に焼き付けます。 +- BlendShape の現状を Mesh に焼き付けます。 + +[統合] +- ヒエラルキーに含まれる MeshRenderer と SkinnedMeshRenderer をひとつの SkinnedMeshRenderer に統合します。 + +[分割] +- 統合結果を BlendShape の有無を基準に分割します。 + +[Scene と Prefab] +Scene と Prefab で挙動が異なります。 + +(Scene/Runtime) +- 対象のヒエラルキーを変更します。UNDO可能。 +- Asset の書き出しはしません。Unityを再起動すると、書き出していない Mesh などの Asset が消滅します。 + +(Prefab/Editor) +- 対象の prefab をシーンにコピーして処理を実行し、生成する Asset を指定されたフォルダに書き出します。 +- Asset 書き出し後にコピーを削除します。 +- Undo はありません。 ")] - [LangMsg(Languages.en, @"Separate the mesh attached to the SkinnedMeshRenderer under the target object with or without BlendShape. + [LangMsg(Languages.en, @" +Separate the mesh attached to the SkinnedMeshRenderer under the target object with or without BlendShape. * Asset: A new Mesh Asset will be created in the same folder as the original. Example: Original-> Original_WithBlendShape.mesh & Original_WithoutBlendShape.mesh * Scene: In the copied hierarchy, the split Mesh is replaced with a Mesh that holds the BlendShape, and a SkinnedMeshRenderer with a Mesh without BlendShape is added. ")] - MESH_SEPARATOR, - + MESH_UTILITY, [LangMsg(Languages.ja, "ブレンドシェイプの有無で分割する")] [LangMsg(Languages.en, "Divide by the presence or absence of `blendshape`")] MESH_SEPARATOR_BY_BLENDSHAPE, - [LangMsg(Languages.ja, @"ターゲットオブジェクト下の SkinnedMeshRenderer または MeshFilter にアタッチされたメッシュを統合します。 +// [LangMsg(Languages.ja, @"ターゲットオブジェクト下の SkinnedMeshRenderer または MeshFilter にアタッチされたメッシュを統合します。 -* Asset: Assets/MeshIntegrated.mesh が作成されます(上書きされるので注意してください)。 -* Scene: コピーされたヒエラルキーでは、統合された Mesh は除去されます。新しく MeshIntegrator ノードが追加されます。 -* VRMではBlendShapeClipの統合など追加の処理が必要です。`VRM0-MeshIntegratorWizard` を使ってください。 -")] - [LangMsg(Languages.en, @"Integrates the attached mesh into the SkinnedMeshRenderer or MeshFilter under the target object. +// * Asset: Assets/MeshIntegrated.mesh が作成されます(上書きされるので注意してください)。 +// * Scene: コピーされたヒエラルキーでは、統合された Mesh は除去されます。新しく MeshIntegrator ノードが追加されます。 +// * VRMではBlendShapeClipの統合など追加の処理が必要です。`VRM0-MeshIntegratorWizard` を使ってください。 +// ")] +// [LangMsg(Languages.en, @"Integrates the attached mesh into the SkinnedMeshRenderer or MeshFilter under the target object. -* Asset: Assets/MeshIntegrated.mesh is created (note that it will be overwritten). -* Scene: In the copied hierarchy, the integrated mesh is removed. A new MeshIntegrator node is added. -* VRM requires additional processing such as BlendShapeClip integration. Use the `VRM0-MeshIntegratorWizard` integration feature. -")] - MESH_INTEGRATOR, +// * Asset: Assets/MeshIntegrated.mesh is created (note that it will be overwritten). +// * Scene: In the copied hierarchy, the integrated mesh is removed. A new MeshIntegrator node is added. +// * VRM requires additional processing such as BlendShapeClip integration. Use the `VRM0-MeshIntegratorWizard` integration feature. +// ")] +// MESH_INTEGRATOR, - // [LangMsg(Languages.ja, "静的メッシュを一つに統合します")] - // [LangMsg(Languages.en, "Integrate static meshes into one")] - // STATIC_MESH_INTEGRATOR, +// // [LangMsg(Languages.ja, "静的メッシュを一つに統合します")] +// // [LangMsg(Languages.en, "Integrate static meshes into one")] +// // STATIC_MESH_INTEGRATOR, - [LangMsg(Languages.ja, @"指定された SkinnedMeshRenderer から、指定されたボーンに対する Weight を保持する三角形を除去します。 +// [LangMsg(Languages.ja, @"指定された SkinnedMeshRenderer から、指定されたボーンに対する Weight を保持する三角形を除去します。 -* Asset: 元の Mesh と同じフォルダに、三角形を除去した Mesh を保存します。 -* Scene: コピーされたヒエラルキーでは、三角形が除去された Mesh に差し替えられます。 -")] - [LangMsg(Languages.en, @"Removes the triangle that holds the weight for the specified bone from the specified SkinnedMeshRenderer. +// * Asset: 元の Mesh と同じフォルダに、三角形を除去した Mesh を保存します。 +// * Scene: コピーされたヒエラルキーでは、三角形が除去された Mesh に差し替えられます。 +// ")] +// [LangMsg(Languages.en, @"Removes the triangle that holds the weight for the specified bone from the specified SkinnedMeshRenderer. -* Assets: Save the mesh with the triangles removed in the same folder as the original mesh. -* Scene: In the copied hierarchy, it will be replaced with a Mesh with the triangles removed. -")] +// * Assets: Save the mesh with the triangles removed in the same folder as the original mesh. +// * Scene: In the copied hierarchy, it will be replaced with a Mesh with the triangles removed. +// ")] - BONE_MESH_ERASER, +// BONE_MESH_ERASER, [LangMsg(Languages.ja, "Skinned Meshを選んでください")] [LangMsg(Languages.en, "Select a skinned mesh")] SELECT_SKINNED_MESH, - [LangMsg(Languages.ja, "Erase Rootを選んでください")] - [LangMsg(Languages.en, "Select a erase root")] - SELECT_ERASE_ROOT, + // [LangMsg(Languages.ja, "Erase Rootを選んでください")] + // [LangMsg(Languages.en, "Select a erase root")] + // SELECT_ERASE_ROOT, [LangMsg(Languages.ja, "GameObjectを選んでください")] [LangMsg(Languages.en, "Select a GameObject first")] @@ -72,9 +91,9 @@ namespace UniGLTF.MeshUtility [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, "No static mesh is contained")] + // NO_STATIC_MESH, [LangMsg(Languages.ja, "GameObjectにスキンメッシュ・静的メッシュが含まれていません")] [LangMsg(Languages.en, "Skinned/Static mesh is not contained")] @@ -83,5 +102,9 @@ namespace UniGLTF.MeshUtility [LangMsg(Languages.ja, "BlendShapeClipが不整合を起こすので、`VRM0-> MeshIntegrator`を使ってください")] [LangMsg(Languages.en, "Because BlendShapeClip causes inconsistency , use `VRM0 -> MeshIntegrator` instead")] VRM_DETECTED, + + [LangMsg(Languages.ja, "対象は, Prefab です。実行時に書き出しファイルの指定があります。")] + [LangMsg(Languages.en, "The target is prefab. A temporary file is specified during execution.")] + PREFAB_TARGET, } } \ No newline at end of file diff --git a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs index 41e1132f5..c7ae49c62 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs @@ -155,7 +155,7 @@ namespace UniGLTF.MeshUtility return MeshIntegrationGroups.ToList(); } - public virtual List Process(GameObject go) + public virtual (List, List) Process(GameObject go) { // TODO unpack prefab @@ -181,48 +181,45 @@ namespace UniGLTF.MeshUtility var copy = CopyMeshIntegrationGroups(); - var newGo = new List(); + var newList = new List(); + + var empty = GetOrCreateEmpty(go, "mesh"); + + var results = new List(); + foreach (var group in copy) { - var empty = GetOrCreateEmpty(go, "mesh"); + var (result, newGo) = Integrate(empty, group); + results.Add(result); + newList.AddRange(newGo); + } - var results = new List(); - foreach (var group in copy) + foreach (var result in results) + { + foreach (var r in result.SourceMeshRenderers) { - Integrate(newGo, empty, results, group); + RemoveComponent(r); } - - foreach (var result in results) + foreach (var r in result.SourceSkinnedMeshRenderers) { - foreach (var r in result.SourceMeshRenderers) - { - RemoveComponent(r); - } - foreach (var r in result.SourceSkinnedMeshRenderers) - { - RemoveComponent(r); - } + RemoveComponent(r); } } MeshIntegrationGroups.Clear(); - return newGo; + return (results, newList); } - protected virtual MeshIntegrationResult Integrate(List newGo, - GameObject empty, List results, MeshIntegrationGroup group) + protected virtual (MeshIntegrationResult, GameObject[]) Integrate(GameObject empty, + 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); - } + var newGo = result.AddIntegratedRendererTo(empty).ToArray(); - return result; + return (result, newGo); } } } diff --git a/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs b/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs index 6249dcbf3..73610670f 100644 --- a/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs +++ b/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs @@ -1,370 +1,88 @@ #pragma warning disable 0414, 0649 using UnityEditor; using UnityEngine; -using System.Linq; -using System; -using System.Collections.Generic; -using UniGLTF.MeshUtility; -using System.IO; using UniGLTF.M17N; + namespace VRM { - public class VrmMeshIntegratorWizard : ScriptableWizard + public class VrmMeshIntegratorWizard : UniGLTF.MeshUtility.MeshUtilityDialog { - public const string MENU_NAME = "VRM 0.x MeshUtility"; - const string ASSET_SUFFIX = ".mesh.asset"; + public new const string MENU_NAME = "VRM 0.x MeshUtility"; - enum HelpMessage + public new static void OpenWindow() { - Ready, - SetTarget, - InvalidTarget, + var window = + (VrmMeshIntegratorWizard)EditorWindow.GetWindow(typeof(VrmMeshIntegratorWizard)); + window.titleContent = new GUIContent(MENU_NAME); + window.Show(); } - enum ValidationError + // void Integrate() + // { + // // 統合 + // var excludes = m_excludes.Where(x => x.Exclude).Select(x => x.Mesh); + // var results = Integrate(copy, excludes, m_separateByBlendShape); + + // } + + // static List Integrate(GameObject root, IEnumerable excludes, bool separateByBlendShape) + // { + // var results = new List(); + // if (separateByBlendShape) + // { + // results.Add(MeshIntegratorUtility.Integrate(root, onlyBlendShapeRenderers: MeshEnumerateOption.OnlyWithoutBlendShape, excludes: excludes)); + // results.Add(MeshIntegratorUtility.Integrate(root, onlyBlendShapeRenderers: MeshEnumerateOption.OnlyWithBlendShape, excludes: excludes)); + // } + // else + // { + // results.Add(MeshIntegratorUtility.Integrate(root, onlyBlendShapeRenderers: MeshEnumerateOption.All, excludes: excludes)); + // } + // return results; + // } + + protected override void DialogMessage() { - None, - NoTarget, - HasParent, - NotPrefab, + EditorGUILayout.HelpBox(Message.MESH_UTILITY.Msg(), MessageType.Info); } - - [SerializeField] - GameObject m_root; - - [SerializeField] - bool m_separateByBlendShape = true; - - [Header("Validation")] - [SerializeField] - Material[] m_uniqueMaterials; - - [Serializable] - struct MaterialKey + enum Message { - public string Shader; - public KeyValuePair[] Properties; + [LangMsg(Languages.ja, @"(VRM-0.x専用) 凍結 > 統合 > 分割 という一連の処理を実行します。 - public override bool Equals(object obj) - { - if (!(obj is MaterialKey)) - { - return base.Equals(obj); - } +[凍結] +- ヒエラルキーの 回転・拡縮を Mesh に焼き付けます。 +- BlendShape の現状を Mesh に焼き付けます。 - var key = (MaterialKey)obj; +- VRM-0.x の正規化処理です。 +- HumanoidAvatar の再生成。 +- BlendShapeClip, SpringBone, Constraint なども影響を受けます。 - return Shader == key.Shader - && Properties.SequenceEqual(key.Properties) - ; - } +[統合] +- ヒエラルキーに含まれる MeshRenderer と SkinnedMeshRenderer をひとつの SkinnedMeshRenderer に統合します。 - public override int GetHashCode() - { - return base.GetHashCode(); - } - } +- VRM の FirstPerson 設定に応じて3種類(BOTH, FirstPerson, ThirdPerson) にグループ化して統合します。 +- FirstPerson=AUTO を前処理できます。 + - 元の Mesh は ThirdPerson として処理されます。頭なしのモデルを追加生成して FirstPersonOnly とします。 - [Serializable] - struct MaterialList - { - public Material[] Materials; +[分割] +- 統合結果を BlendShape の有無を基準に分割します。 +- BOTH, FirstPerson, ThirdPerson x 2 で、最大で 6Mesh になります。空の部分ができることが多いので 3Mesh くらいが多くなります。 - public MaterialList(Material[] list) - { - Materials = list; - } - } - [SerializeField] - MaterialList[] m_duplicateMaterials; +[Scene と Prefab] +Scene と Prefab で挙動が異なります。 - [Serializable] - public class ExcludeItem - { - public Mesh Mesh; - public bool Exclude; - } +(Scene/Runtime) +- 対象のヒエラルキーを変更します。UNDO可能。 +- Asset の書き出しはしません。Unityを再起動すると、書き出していない Mesh などの Asset が消滅します。 - [Header("Options")] - [SerializeField] - List m_excludes = new List(); - - [Header("Result")] - [SerializeField] - MeshInfo[] integrationResults; - - public static void CreateWizard() - { - ScriptableWizard.DisplayWizard(MENU_NAME, "Integrate and close window", "Integrate"); - } - - private void OnEnable() - { - Clear(HelpMessage.Ready, ValidationError.None); - OnValidate(); - } - - protected override bool DrawWizardGUI() - { - var t = m_root.GetGameObjectType(); - EditorGUILayout.HelpBox($"{t}", MessageType.Info); - return base.DrawWizardGUI(); - } - - static object GetPropertyValue(Shader shader, int i, Material m) - { - var propType = ShaderUtil.GetPropertyType(shader, i); - switch (propType) - { - case ShaderUtil.ShaderPropertyType.Color: - return m.GetColor(ShaderUtil.GetPropertyName(shader, i)); - - case ShaderUtil.ShaderPropertyType.Range: - case ShaderUtil.ShaderPropertyType.Float: - return m.GetFloat(ShaderUtil.GetPropertyName(shader, i)); - - case ShaderUtil.ShaderPropertyType.Vector: - return m.GetVector(ShaderUtil.GetPropertyName(shader, i)); - - case ShaderUtil.ShaderPropertyType.TexEnv: - return m.GetTexture(ShaderUtil.GetPropertyName(shader, i)); - - default: - throw new NotImplementedException(propType.ToString()); - } - } - - static MaterialKey GetMaterialKey(Material m) - { - var key = new MaterialKey - { - Shader = m.shader.name, - }; - - key.Properties = Enumerable.Range(0, ShaderUtil.GetPropertyCount(m.shader)) - .Select(x => new KeyValuePair( - ShaderUtil.GetPropertyName(m.shader, x), - GetPropertyValue(m.shader, x, m)) - ) - .OrderBy(x => x.Key) - .ToArray() - ; - - return key; - } - - 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(); - var excludes = new List(); - foreach (var x in m_root.GetComponentsInChildren()) - { - 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); - } - - void OnWizardUpdate() - { - } - - /// 2022.05 仕様変更 - /// - /// * prefab 専用 - /// * backup するのではなく 変更した copy を作成する。元は変えない - /// * copy 先の統合前の renderer を disable で残さず destroy する - /// * 実行すると mesh, blendshape, blendShape を新規に作成する - /// * 新しいヒエラルキーを prefab に保存してから削除して終了する - /// - void Integrate() - { - if (m_root.GetGameObjectType() != GameObjectType.AssetPrefab) - { - throw new Exception("for prefab only"); - } - - String folder = "Assets"; - var prefab = m_root.GetPrefab(); - if (prefab != null) - { - folder = AssetDatabase.GetAssetPath(prefab); - Debug.Log(folder); - } - - // 新規で作成されるアセットはすべてこのフォルダの中に作る。上書きチェックはしない - var assetFolder = EditorUtility.SaveFolderPanel("select asset save folder", Path.GetDirectoryName(folder), "VrmIntegrated"); - var unityPath = UniGLTF.UnityPath.FromFullpath(assetFolder); - if (!unityPath.IsUnderWritableFolder) - { - EditorUtility.DisplayDialog("asset folder", "Target folder must be in the Assets or writable Packages folder", "cancel"); - return; - } - assetFolder = unityPath.Value; - - var copy = GameObject.Instantiate(m_root); - - // 統合 - var excludes = m_excludes.Where(x => x.Exclude).Select(x => x.Mesh); - var results = Integrate(copy, excludes, m_separateByBlendShape); - - // write mesh asset - foreach (var result in results) - { - var childAssetPath = $"{assetFolder}/{result.Integrated.IntegratedRenderer.gameObject.name}{ASSET_SUFFIX}"; - Debug.LogFormat("CreateAsset: {0}", childAssetPath); - AssetDatabase.CreateAsset(result.Integrated.IntegratedRenderer.sharedMesh, childAssetPath); - } - - // 統合した結果をヒエラルキーに追加する - foreach (var result in results) - { - if (result.Integrated.IntegratedRenderer != null) - { - result.Integrated.IntegratedRenderer.transform.SetParent(copy.transform, false); - } - } - - // 統合した結果を反映した BlendShapeClip を作成して置き換える - var clips = VRMMeshIntegratorUtility.FollowBlendshapeRendererChange(results, copy, assetFolder); - - // 用が済んだ 統合前 の renderer を削除する - foreach (var result in results) - { - foreach (var renderer in result.SourceMeshRenderers) - { - GameObject.DestroyImmediate(renderer); - } - foreach (var renderer in result.SourceSkinnedMeshRenderers) - { - GameObject.DestroyImmediate(renderer); - } - } - - // reset firstperson - var firstperson = copy.GetComponent(); - if (firstperson != null) - { - firstperson.Reset(); - } - - // prefab - var prefabPath = $"{assetFolder}/VrmIntegrated.prefab"; - Debug.Log(prefabPath); - PrefabUtility.SaveAsPrefabAsset(copy, prefabPath, out bool success); - if (!success) - { - throw new System.Exception($"PrefabUtility.SaveAsPrefabAsset: {prefabPath}"); - } - - // destroy scene - UnityEngine.Object.DestroyImmediate(copy); - - var prefabReference = AssetDatabase.LoadAssetAtPath(prefabPath); - foreach (var clip in clips) - { - var so = new SerializedObject(clip); - so.Update(); - // clip.Prefab = copy; - var prop = so.FindProperty("m_prefab"); - prop.objectReferenceValue = prefabReference; - so.ApplyModifiedProperties(); - } - } - - static List Integrate(GameObject root, IEnumerable excludes, bool separateByBlendShape) - { - var results = new List(); - if (separateByBlendShape) - { - results.Add(MeshIntegratorUtility.Integrate(root, onlyBlendShapeRenderers: MeshEnumerateOption.OnlyWithoutBlendShape, excludes: excludes)); - results.Add(MeshIntegratorUtility.Integrate(root, onlyBlendShapeRenderers: MeshEnumerateOption.OnlyWithBlendShape, excludes: excludes)); - } - else - { - results.Add(MeshIntegratorUtility.Integrate(root, onlyBlendShapeRenderers: MeshEnumerateOption.All, excludes: excludes)); - } - return results; - } - - void OnWizardCreate() - { - Integrate(); - // close - } - - void OnWizardOtherButton() - { - Integrate(); +(Prefab/Editor) +- 対象の prefab をシーンにコピーして処理を実行し、生成する Asset を指定されたフォルダに書き出します。 +- Asset 書き出し後にコピーを削除します。 +- Undo はありません。 +")] + [LangMsg(Languages.en, @"TODO +")] + MESH_UTILITY, } } } diff --git a/Assets/VRM/Editor/VrmTopMenu.cs b/Assets/VRM/Editor/VrmTopMenu.cs index 6f130f3fc..7bcfe8c36 100644 --- a/Assets/VRM/Editor/VrmTopMenu.cs +++ b/Assets/VRM/Editor/VrmTopMenu.cs @@ -25,7 +25,7 @@ namespace VRM [MenuItem(UserMenuPrefix + "/" + VrmMeshIntegratorWizard.MENU_NAME, false, 3)] - private static void OpenMeshIntegratorWizard() => VrmMeshIntegratorWizard.CreateWizard(); + private static void OpenMeshIntegratorWizard() => VrmMeshIntegratorWizard.OpenWindow(); [MenuItem(UserMenuPrefix + "/" + VRMHumanoidNormalizerMenu.MENU_NAME, true, 51)] diff --git a/Assets/VRM10/Editor/MeshUtility/Vrm10MeshUtilityDialog.cs b/Assets/VRM10/Editor/MeshUtility/Vrm10MeshUtilityDialog.cs index 138421761..eb4afcbdd 100644 --- a/Assets/VRM10/Editor/MeshUtility/Vrm10MeshUtilityDialog.cs +++ b/Assets/VRM10/Editor/MeshUtility/Vrm10MeshUtilityDialog.cs @@ -1,6 +1,8 @@ using UnityEngine; using UnityEditor; using UniGLTF; +using UniGLTF.M17N; + namespace UniVRM10 { @@ -57,5 +59,50 @@ namespace UniVRM10 var mod = base.MeshIntegrateGui(); return firstPerson || mod; } + + protected override void DialogMessage() + { + EditorGUILayout.HelpBox(Message.MESH_UTILITY.Msg(), MessageType.Info); + } + enum Message + { + [LangMsg(Languages.ja, @"(VRM-1.0専用) 凍結 > 統合 > 分割 という一連の処理を実行します。 + +[凍結] +- ヒエラルキーの 回転・拡縮を Mesh に焼き付けます。 +- BlendShape の現状を Mesh に焼き付けます。 + +- VRM-1.0 では正規化は必須でなくなりました。任意のオプションです。 +- VRM-1.0 でも拡縮の凍結は推奨しています。 +- HumanoidAvatar の再生成。 +- Expression, SpringBone, Constraint なども影響を受けます。 + +[統合] +- ヒエラルキーに含まれる MeshRenderer と SkinnedMeshRenderer をひとつの SkinnedMeshRenderer に統合します。 + +- VRM の FirstPerson 設定に応じて3種類(BOTH, FirstPerson, ThirdPerson) にグループ化して統合します。 +- FirstPerson=AUTO を前処理できます。 + - 元の Mesh は ThirdPerson として処理されます。頭なしのモデルを追加生成して FirstPersonOnly とします。 + +[分割] +- 統合結果を BlendShape の有無を基準に分割します。 +- BOTH, FirstPerson, ThirdPerson x 2 で、最大で 6Mesh になります。空の部分ができることが多いので 3Mesh くらいが多くなります。 + +[Scene と Prefab] +Scene と Prefab で挙動が異なります。 + +(Scene/Runtime) +- 対象のヒエラルキーを変更します。UNDO可能。 +- Asset の書き出しはしません。Unityを再起動すると、書き出していない Mesh などの Asset が消滅します。 + +(Prefab/Editor) +- 対象の prefab をシーンにコピーして処理を実行し、生成する Asset を指定されたフォルダに書き出します。 +- Asset 書き出し後にコピーを削除します。 +- Undo はありません。 +")] + [LangMsg(Languages.en, @"TODO +")] + MESH_UTILITY, + } } } \ No newline at end of file diff --git a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs index 60e665dd5..d9e17f84a 100644 --- a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs +++ b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; using System.Linq; +using UniGLTF.MeshUtility; using UniHumanoid; using UnityEngine; +using UnityEngine.Rendering; namespace UniVRM10 { @@ -37,12 +39,12 @@ namespace UniVRM10 return copy; } - protected override UniGLTF.MeshUtility.MeshIntegrationResult Integrate(List newGo, + protected override + (UniGLTF.MeshUtility.MeshIntegrationResult, GameObject[]) Integrate( GameObject empty, - List results, UniGLTF.MeshUtility.MeshIntegrationGroup group) { - var result = base.Integrate(newGo, empty, results, group); + var (result, newList) = base.Integrate(empty, group); if (_generateFirstPerson && group.Name == "auto") { @@ -57,14 +59,14 @@ namespace UniVRM10 } } - return result; + return (result, newList); } Vrm10Instance _vrmInstance = null; /// /// glTF に比べて Humanoid や FirstPerson の処理が追加される /// - public override List Process(GameObject go) + public override (List, List) Process(GameObject go) { _vrmInstance = go.GetComponent(); if (_vrmInstance == null) @@ -85,7 +87,7 @@ namespace UniVRM10 // TODO: update: spring // TODO: update: constraint // TODO: update: firstPerson offset - var list = base.Process(go); + var (list, newList) = base.Process(go); if (FreezeBlendShape || FreezeRotation || FreezeScaling) { @@ -94,7 +96,7 @@ namespace UniVRM10 animator.avatar = newAvatar; } - return list; + return (list, newList); } void _ProcessFirstPerson(Vrm10Instance vrmInstance, UniGLTF.MeshUtility.MeshInfo info) From 6d251c5993f4c95580f264b11cd9928ab706ea4a Mon Sep 17 00:00:00 2001 From: ousttrue Date: Mon, 27 Nov 2023 14:53:14 +0900 Subject: [PATCH 05/25] fix menu priority --- Assets/UniGLTF/Editor/TopMenu.cs | 6 +++--- Assets/VRM/Editor/VrmTopMenu.cs | 4 ++-- Assets/VRM10/Editor/Vrm10TopMenu.cs | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Assets/UniGLTF/Editor/TopMenu.cs b/Assets/UniGLTF/Editor/TopMenu.cs index c5efaf46d..597e97196 100644 --- a/Assets/UniGLTF/Editor/TopMenu.cs +++ b/Assets/UniGLTF/Editor/TopMenu.cs @@ -25,18 +25,18 @@ namespace UniGLTF private static void ImportGltfFile() => GltfImportMenu.ImportGltfFileToGameObject(); - [MenuItem(UserGltfMenuPrefix + "/" + MeshUtility.MeshUtilityDialog.MENU_NAME, priority = 3)] + [MenuItem(UserGltfMenuPrefix + "/" + MeshUtility.MeshUtilityDialog.MENU_NAME, priority = 31)] private static void OpenMeshProcessingWindow() => MeshUtility.MeshUtilityDialog.OpenWindow(); #if VRM_DEVELOP - [MenuItem(DevelopmentMenuPrefix + "/Generate Serialization Code", priority = 40)] + [MenuItem(DevelopmentMenuPrefix + "/Generate Serialization Code", priority = 51)] private static void GenerateSerializationCode() { SerializerGenerator.GenerateSerializer(); DeserializerGenerator.GenerateSerializer(); } - [MenuItem(DevelopmentMenuPrefix + "/Generate UniJSON ConcreteCast", priority = 41)] + [MenuItem(DevelopmentMenuPrefix + "/Generate UniJSON ConcreteCast", priority = 52)] private static void GenerateUniJsonConcreteCastCode() => UniJSON.ConcreteCast.GenerateGenericCast(); #endif } diff --git a/Assets/VRM/Editor/VrmTopMenu.cs b/Assets/VRM/Editor/VrmTopMenu.cs index 7bcfe8c36..663159a61 100644 --- a/Assets/VRM/Editor/VrmTopMenu.cs +++ b/Assets/VRM/Editor/VrmTopMenu.cs @@ -24,11 +24,11 @@ namespace VRM private static void ImportFromVrmFile() => VRMImporterMenu.OpenImportMenu(); - [MenuItem(UserMenuPrefix + "/" + VrmMeshIntegratorWizard.MENU_NAME, false, 3)] + [MenuItem(UserMenuPrefix + "/" + VrmMeshIntegratorWizard.MENU_NAME, false, 51)] private static void OpenMeshIntegratorWizard() => VrmMeshIntegratorWizard.OpenWindow(); - [MenuItem(UserMenuPrefix + "/" + VRMHumanoidNormalizerMenu.MENU_NAME, true, 51)] + [MenuItem(UserMenuPrefix + "/" + VRMHumanoidNormalizerMenu.MENU_NAME, true, 52)] private static bool FreezeTPoseValidation() => VRMHumanoidNormalizerMenu.NormalizeValidation(); [MenuItem(UserMenuPrefix + "/" + VRMHumanoidNormalizerMenu.MENU_NAME, false, 52)] private static void FreezeTPose() => VRMHumanoidNormalizerMenu.Normalize(); diff --git a/Assets/VRM10/Editor/Vrm10TopMenu.cs b/Assets/VRM10/Editor/Vrm10TopMenu.cs index 999283894..3749c5e63 100644 --- a/Assets/VRM10/Editor/Vrm10TopMenu.cs +++ b/Assets/VRM10/Editor/Vrm10TopMenu.cs @@ -13,15 +13,15 @@ namespace UniVRM10 [MenuItem(UserMenuPrefix + "/" + VRM10ExportDialog.MENU_NAME, priority = 1)] private static void OpenExportDialog() => VRM10ExportDialog.Open(); - [MenuItem(UserMenuPrefix + "/" + Vrm10MeshUtilityDialog.MENU_NAME, priority = 2)] + [MenuItem(UserMenuPrefix + "/" + Vrm10MeshUtilityDialog.MENU_NAME, priority = 21)] private static void OpenMeshUtility() => Vrm10MeshUtilityDialog.OpenWindow(); - [MenuItem(ExperimentalMenuPrefix + "/" + VrmAnimationMenu.MENU_NAME, priority = 21)] + [MenuItem(ExperimentalMenuPrefix + "/" + VrmAnimationMenu.MENU_NAME, priority = 22)] private static void ConvertVrmAnimation() => VrmAnimationMenu.BvhToVrmAnimationMenu(); #if VRM_DEVELOP - [MenuItem(ExperimentalMenuPrefix + "/" + VRM10Window.MENU_NAME, false, 22)] + [MenuItem(ExperimentalMenuPrefix + "/" + VRM10Window.MENU_NAME, false, 23)] private static void OpenWindow() => VRM10Window.Open(); [MenuItem(DevelopmentMenuPrefix + "/Generate from JsonSchema", false, 100)] From ff6864903691b4055154b02f7fed15c04aaa75a9 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Mon, 27 Nov 2023 18:58:50 +0900 Subject: [PATCH 06/25] MeshAttachInfo --- .../Runtime/MeshUtility/BoneNormalizer.cs | 104 ++++++++++-------- .../Runtime/MeshUtility/GltfMeshUtility.cs | 7 +- .../Runtime/MeshUtility/MeshAttachInfo.cs | 30 +++++ .../MeshUtility/MeshAttachInfo.cs.meta | 11 ++ .../SkinnedMeshUtility/VRMBoneNormalizer.cs | 7 +- 5 files changed, 110 insertions(+), 49 deletions(-) create mode 100644 Assets/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs create mode 100644 Assets/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs.meta diff --git a/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs b/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs index 40981e773..a94a45c7f 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs @@ -71,6 +71,56 @@ namespace UniGLTF.MeshUtility } } + public static MeshAttachInfo CreateMeshInfo(Transform src, Dictionary boneMap, bool freezeBlendShape) + { + Transform dst; + if (!boneMap.TryGetValue(src, out dst)) + { + return default; + } + + // SkinnedMeshRenderer + var smr = src.GetComponent(); + var (mesh, dstBones) = MeshFreezer.NormalizeSkinnedMesh( + smr, + boneMap, + dst.localToWorldMatrix, + freezeBlendShape); + if (mesh != null) + { + var info = new MeshAttachInfo + { + Mesh = mesh, + Materials = smr.sharedMaterials, + }; + if (smr.rootBone != null) + { + if (boneMap.TryGetValue(smr.rootBone, out Transform found)) + { + info.RootBone = found; + } + } + return info; + } + + // MeshRenderer + var mr = src.GetComponent(); + if (mr != null) + { + var dstMesh = MeshFreezer.NormalizeNoneSkinnedMesh(mr); + if (dstMesh != null) + { + return new MeshAttachInfo + { + Mesh = dstMesh, + Materials = mr.sharedMaterials, + }; + } + } + + return default; + } + /// /// 回転とスケールを除去したヒエラルキーのコピーを作成する(MeshをBakeする) @@ -79,7 +129,8 @@ namespace UniGLTF.MeshUtility /// BlendShapeを0クリアするか否か。false の場合 BlendShape の現状を Bake する /// Avatarを作る関数 /// - public static (GameObject, Dictionary) NormalizeHierarchyFreezeMesh(GameObject go, + public static (GameObject, Dictionary, Dictionary) NormalizeHierarchyFreezeMesh( + GameObject go, bool removeScaling = true, bool removeRotation = true, bool freezeBlendShape = true @@ -93,57 +144,16 @@ namespace UniGLTF.MeshUtility // // 各メッシュから回転・スケールを取り除いてBinding行列を再計算する // + var result = new Dictionary(); foreach (var src in go.transform.Traverse()) { - Transform dst; - if (!boneMap.TryGetValue(src, out dst)) + var info = CreateMeshInfo(src, boneMap, freezeBlendShape); + if (info != null) { - continue; - } - - { - // SkinnedMeshRenderer - var srcRenderer = src.GetComponent(); - var (mesh, dstBones) = MeshFreezer.NormalizeSkinnedMesh( - srcRenderer, - boneMap, - dst.localToWorldMatrix, - freezeBlendShape); - if (mesh != null) - { - var dstRenderer = dst.gameObject.AddComponent(); - dstRenderer.sharedMaterials = srcRenderer.sharedMaterials; - if (srcRenderer.rootBone != null) - { - if (boneMap.TryGetValue(srcRenderer.rootBone, out Transform found)) - { - dstRenderer.rootBone = found; - } - } - dstRenderer.bones = dstBones; - dstRenderer.sharedMesh = mesh; - } - } - - { - // MeshRenderer - var srcRenderer = src.GetComponent(); - if (srcRenderer != null) - { - var dstMesh = MeshFreezer.NormalizeNoneSkinnedMesh(srcRenderer); - if (dstMesh != null) - { - var dstFilter = dst.gameObject.AddComponent(); - dstFilter.sharedMesh = dstMesh; - // Materialをコピー - var dstRenderer = dst.gameObject.AddComponent(); - dstRenderer.sharedMaterials = srcRenderer.sharedMaterials; - } - } + result.Add(src, info); } } - - return (normalized, boneMap); + return (normalized, boneMap, result); } public static void WriteBackResult(GameObject go, GameObject normalized, Dictionary boneMap) diff --git a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs index c7ae49c62..9960b6058 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs @@ -162,11 +162,16 @@ namespace UniGLTF.MeshUtility // 正規化されたヒエラルキーを作る if (FreezeBlendShape || FreezeRotation || FreezeScaling) { - var (normalized, boneMap) = BoneNormalizer.NormalizeHierarchyFreezeMesh(go, + var (normalized, boneMap, newMesh) = BoneNormalizer.NormalizeHierarchyFreezeMesh(go, removeScaling: FreezeScaling, removeRotation: FreezeRotation, freezeBlendShape: FreezeBlendShape); + foreach (var (k, v) in newMesh) + { + v.AttachTo(k.gameObject); + } + // write back normalized transform to boneMap BoneNormalizer.WriteBackResult(go, normalized, boneMap); if (Application.isPlaying) diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs new file mode 100644 index 000000000..0eb16c63f --- /dev/null +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs @@ -0,0 +1,30 @@ +using UnityEngine; + +namespace UniGLTF.MeshUtility +{ + public class MeshAttachInfo + { + public Mesh Mesh; + public Material[] Materials; + public Transform[] Bones; + public Transform RootBone; + public void AttachTo(GameObject dst) + { + if (Bones != null) + { + var dstRenderer = dst.AddComponent(); + dstRenderer.sharedMesh = Mesh; + dstRenderer.sharedMaterials = Materials; + dstRenderer.bones = Bones; + dstRenderer.rootBone = RootBone; + } + else + { + var dstFilter = dst.AddComponent(); + dstFilter.sharedMesh = Mesh; + var dstRenderer = dst.gameObject.AddComponent(); + dstRenderer.sharedMaterials = Materials; + } + } + } +} \ No newline at end of file diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs.meta b/Assets/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs.meta new file mode 100644 index 000000000..0db6210ad --- /dev/null +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e6eff3bee96e61849ac190387ec28542 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM/Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs b/Assets/VRM/Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs index e0901616a..479641975 100644 --- a/Assets/VRM/Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs +++ b/Assets/VRM/Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs @@ -67,7 +67,12 @@ namespace VRM } // 正規化されたヒエラルキーを作る - var (normalized, bMap) = BoneNormalizer.NormalizeHierarchyFreezeMesh(go); + var (normalized, bMap, newMesh) = BoneNormalizer.NormalizeHierarchyFreezeMesh(go); + + foreach (var (k, v) in newMesh) + { + v.AttachTo(k.gameObject); + } // 新しいヒエラルキーからAvatarを作る var newAvatar = UniHumanoid.AvatarDescription.CreateAvatarForCopyHierarchy( From 0f751d0892362adfbacd62a88b43ee6f6696ae7b Mon Sep 17 00:00:00 2001 From: ousttrue Date: Mon, 27 Nov 2023 19:16:17 +0900 Subject: [PATCH 07/25] remove arg and return from NormalizeSkinnedMesh. --- .../Runtime/MeshUtility/BoneNormalizer.cs | 13 +++---- .../Runtime/MeshUtility/GltfMeshUtility.cs | 3 +- .../Runtime/MeshUtility/MeshAttachInfo.cs | 4 ++ .../Runtime/MeshUtility/MeshFreezer.cs | 39 ++++++++----------- 4 files changed, 26 insertions(+), 33 deletions(-) diff --git a/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs b/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs index a94a45c7f..f9d5a2cfb 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs @@ -71,7 +71,7 @@ namespace UniGLTF.MeshUtility } } - public static MeshAttachInfo CreateMeshInfo(Transform src, Dictionary boneMap, bool freezeBlendShape) + public static MeshAttachInfo CreateMeshInfo(Transform src, Dictionary boneMap) { Transform dst; if (!boneMap.TryGetValue(src, out dst)) @@ -81,11 +81,9 @@ namespace UniGLTF.MeshUtility // SkinnedMeshRenderer var smr = src.GetComponent(); - var (mesh, dstBones) = MeshFreezer.NormalizeSkinnedMesh( + var mesh = MeshFreezer.NormalizeSkinnedMesh( smr, - boneMap, - dst.localToWorldMatrix, - freezeBlendShape); + boneMap); if (mesh != null) { var info = new MeshAttachInfo @@ -132,8 +130,7 @@ namespace UniGLTF.MeshUtility public static (GameObject, Dictionary, Dictionary) NormalizeHierarchyFreezeMesh( GameObject go, bool removeScaling = true, - bool removeRotation = true, - bool freezeBlendShape = true + bool removeRotation = true ) { // @@ -147,7 +144,7 @@ namespace UniGLTF.MeshUtility var result = new Dictionary(); foreach (var src in go.transform.Traverse()) { - var info = CreateMeshInfo(src, boneMap, freezeBlendShape); + var info = CreateMeshInfo(src, boneMap); if (info != null) { result.Add(src, info); diff --git a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs index 9960b6058..d230b666e 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs @@ -164,8 +164,7 @@ namespace UniGLTF.MeshUtility { var (normalized, boneMap, newMesh) = BoneNormalizer.NormalizeHierarchyFreezeMesh(go, removeScaling: FreezeScaling, - removeRotation: FreezeRotation, - freezeBlendShape: FreezeBlendShape); + removeRotation: FreezeRotation); foreach (var (k, v) in newMesh) { diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs index 0eb16c63f..16b4f0fdf 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs @@ -1,3 +1,4 @@ +using System.Linq; using UnityEngine; namespace UniGLTF.MeshUtility @@ -12,6 +13,9 @@ namespace UniGLTF.MeshUtility { if (Bones != null) { + // recalc bindposes + Mesh.bindposes = Bones.Select(x => x.worldToLocalMatrix * dst.transform.localToWorldMatrix).ToArray(); + var dstRenderer = dst.AddComponent(); dstRenderer.sharedMesh = Mesh; dstRenderer.sharedMaterials = Materials; diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs index 98c4f8af1..4b65f6094 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs @@ -126,14 +126,11 @@ namespace UniGLTF.MeshUtility /// /// /// 正規化前のボーンから正規化後のボーンを得る - /// /// /// - public static (Mesh, Transform[]) NormalizeSkinnedMesh( + public static Mesh NormalizeSkinnedMesh( SkinnedMeshRenderer src, - Dictionary boneMap, - Matrix4x4 dstLocalToWorldMatrix, - bool FreezeBlendShape = true) + Dictionary boneMap) { if (src == null || !src.enabled @@ -180,16 +177,6 @@ namespace UniGLTF.MeshUtility src.sharedMesh = srcMesh; } - var blendShapeBackup = new List(); - if (!FreezeBlendShape) - { - for (int i = 0; i < srcMesh.blendShapeCount; ++i) - { - blendShapeBackup.Add(src.GetBlendShapeWeight(i)); - src.SetBlendShapeWeight(i, 0); - } - } - // BakeMesh var mesh = srcMesh.Copy(false); mesh.name = srcMesh.name + ".baked"; @@ -198,9 +185,6 @@ namespace UniGLTF.MeshUtility // 新しい骨格のボーンウェイトを作成する mesh.boneWeights = MapBoneWeight(srcMesh.boneWeights, boneMap, src.bones, dstBones); - // recalc bindposes - mesh.bindposes = dstBones.Select(x => x.worldToLocalMatrix * dstLocalToWorldMatrix).ToArray(); - //var m = src.localToWorldMatrix; // include scaling var m = default(Matrix4x4); m.SetTRS(Vector3.zero, src.transform.rotation, Vector3.one); // rotation only @@ -211,10 +195,19 @@ namespace UniGLTF.MeshUtility // CopyBlendShapes(src, srcMesh, mesh, m); - for (int i = 0; i < blendShapeBackup.Count; ++i) - { - src.SetBlendShapeWeight(i, blendShapeBackup[i]); - } + // var blendShapeBackup = new List(); + // if (!FreezeBlendShape) + // { + // for (int i = 0; i < srcMesh.blendShapeCount; ++i) + // { + // blendShapeBackup.Add(src.GetBlendShapeWeight(i)); + // src.SetBlendShapeWeight(i, 0); + // } + // } + // for (int i = 0; i < blendShapeBackup.Count; ++i) + // { + // src.SetBlendShapeWeight(i, blendShapeBackup[i]); + // } if (!hasBoneWeight) { @@ -223,7 +216,7 @@ namespace UniGLTF.MeshUtility src.sharedMesh = originalSrcMesh; } - return (mesh, dstBones); + return mesh; } private static void CopyBlendShapes(SkinnedMeshRenderer src, Mesh srcMesh, Mesh mesh, Matrix4x4 m) From 4ec5d54588f04fb3897878079b0a2151cf337d7e Mon Sep 17 00:00:00 2001 From: ousttrue Date: Mon, 27 Nov 2023 20:05:01 +0900 Subject: [PATCH 08/25] bake mesh inplace --- .../Runtime/MeshUtility/BoneNormalizer.cs | 154 +++++------------- .../Runtime/MeshUtility/GltfMeshUtility.cs | 25 +-- .../Runtime/MeshUtility/MeshAttachInfo.cs | 6 +- .../Runtime/MeshUtility/MeshFreezer.cs | 28 +--- .../SkinnedMeshUtility/VRMBoneNormalizer.cs | 34 +--- 5 files changed, 63 insertions(+), 184 deletions(-) diff --git a/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs b/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs index f9d5a2cfb..bfad06d94 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using UniGLTF.Utils; using UnityEngine; @@ -8,97 +9,20 @@ namespace UniGLTF.MeshUtility { public static class BoneNormalizer { - public static (GameObject, Dictionary) CreateNormalizedHierarchy(GameObject go, - bool removeScaling = true, - bool removeRotation = true) + private static MeshAttachInfo CreateMeshInfo(Transform src) { - var boneMap = new Dictionary(); - var normalized = new GameObject(go.name + "(normalized)"); - normalized.transform.position = go.transform.position; - - if (removeScaling && removeRotation) - { - RemoveScaleAndRotationRecursive(go.transform, normalized.transform, boneMap); - } - else if (removeScaling) - { - RemoveScaleAndRotationRecursive(go.transform, normalized.transform, boneMap); - } - else if (removeRotation) - { - throw new NotImplementedException(); - } - else - { - throw new ArgumentNullException(); - } - - return (normalized, boneMap); - } - - static void RemoveScaleRecursive(Transform src, Transform dst, Dictionary boneMap) - { - boneMap[src] = dst; - - foreach (Transform child in src) - { - if (child.gameObject.activeSelf) - { - var dstChild = new GameObject(child.name); - dstChild.transform.SetParent(dst); - dstChild.transform.position = child.position; // copy world position - dstChild.transform.rotation = child.localToWorldMatrix.rotation; // copy world rotation - // scale is removed - RemoveScaleRecursive(child, dstChild.transform, boneMap); - } - } - } - - static void RemoveScaleAndRotationRecursive(Transform src, Transform dst, Dictionary boneMap) - { - boneMap[src] = dst; - - foreach (Transform child in src) - { - if (child.gameObject.activeSelf) - { - var dstChild = new GameObject(child.name); - dstChild.transform.SetParent(dst); - dstChild.transform.position = child.position; // copy world position - - RemoveScaleAndRotationRecursive(child, dstChild.transform, boneMap); - } - } - } - - public static MeshAttachInfo CreateMeshInfo(Transform src, Dictionary boneMap) - { - Transform dst; - if (!boneMap.TryGetValue(src, out dst)) - { - return default; - } - // SkinnedMeshRenderer var smr = src.GetComponent(); - var mesh = MeshFreezer.NormalizeSkinnedMesh( - smr, - boneMap); + var mesh = MeshFreezer.NormalizeSkinnedMesh(smr); if (mesh != null) { - var info = new MeshAttachInfo + return new MeshAttachInfo { Mesh = mesh, Materials = smr.sharedMaterials, + Bones = smr.bones, + RootBone = smr.rootBone, }; - if (smr.rootBone != null) - { - if (boneMap.TryGetValue(smr.rootBone, out Transform found)) - { - info.RootBone = found; - } - } - return info; } // MeshRenderer @@ -127,58 +51,68 @@ namespace UniGLTF.MeshUtility /// BlendShapeを0クリアするか否か。false の場合 BlendShape の現状を Bake する /// Avatarを作る関数 /// - public static (GameObject, Dictionary, Dictionary) NormalizeHierarchyFreezeMesh( + public static Dictionary NormalizeHierarchyFreezeMesh( GameObject go, bool removeScaling = true, bool removeRotation = true ) { - // - // 正規化されたヒエラルキーを作る - // - var (normalized, boneMap) = CreateNormalizedHierarchy(go, removeScaling, removeRotation); - // // 各メッシュから回転・スケールを取り除いてBinding行列を再計算する // var result = new Dictionary(); foreach (var src in go.transform.Traverse()) { - var info = CreateMeshInfo(src, boneMap); + var info = CreateMeshInfo(src); if (info != null) { result.Add(src, info); } } - return (normalized, boneMap, result); + return result; } - public static void WriteBackResult(GameObject go, GameObject normalized, Dictionary boneMap) + public static void Replace(GameObject go, Dictionary newMesh, + bool FreezeRotation, bool FreezeScaling) { - Func getSrc = dst => + var boneMap = go.transform.Traverse().ToDictionary(x => x, x => new EuclideanTransform(x.rotation, x.position)); + // Func getSrc = dst => + // { + // foreach (var (k, v) in boneMap) + // { + // if (v == dst) + // { + // return k; + // } + // } + // throw new NotImplementedException(); + // }; + + foreach (var (src, tr) in boneMap) { - foreach (var (k, v) in boneMap) + src.position = tr.Translation; + if (FreezeRotation) { - if (v == dst) - { - return k; - } + src.rotation = Quaternion.identity; } - throw new NotImplementedException(); - }; - foreach (var (src, dst) in boneMap) - { - src.localPosition = dst.localPosition; - src.localRotation = dst.localRotation; - src.localScale = dst.localScale; - var srcR = src.GetComponent(); - var dstR = dst.GetComponent(); - if (srcR != null && dstR != null) + else { - srcR.sharedMesh = dstR.sharedMesh; - srcR.bones = dstR.bones.Select(x => getSrc(x)).ToArray(); + src.rotation = tr.Rotation; + } + if (FreezeScaling) + { + src.localScale = Vector3.one; + } + else + { + throw new NotImplementedException(); + } + + if (newMesh.TryGetValue(src, out var info)) + { + info.ReplaceMesh(src.gameObject); } } } } -} +} \ No newline at end of file diff --git a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs index d230b666e..2ebd9e15d 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs @@ -157,30 +157,17 @@ namespace UniGLTF.MeshUtility public virtual (List, List) Process(GameObject go) { - // TODO unpack prefab - - // 正規化されたヒエラルキーを作る if (FreezeBlendShape || FreezeRotation || FreezeScaling) { - var (normalized, boneMap, newMesh) = BoneNormalizer.NormalizeHierarchyFreezeMesh(go, + // MeshをBakeする + var newMesh = BoneNormalizer.NormalizeHierarchyFreezeMesh(go, removeScaling: FreezeScaling, removeRotation: FreezeRotation); - foreach (var (k, v) in newMesh) - { - v.AttachTo(k.gameObject); - } - - // write back normalized transform to boneMap - BoneNormalizer.WriteBackResult(go, normalized, boneMap); - if (Application.isPlaying) - { - GameObject.Destroy(normalized); - } - else - { - GameObject.DestroyImmediate(normalized); - } + // - ヒエラルキーから回転・拡縮を除去する + // - BakeされたMeshで置き換える + // - bindPoses を再計算する + BoneNormalizer.Replace(go, newMesh, FreezeRotation, FreezeScaling); } var copy = CopyMeshIntegrationGroups(); diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs index 16b4f0fdf..6684777c4 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs @@ -9,14 +9,14 @@ namespace UniGLTF.MeshUtility public Material[] Materials; public Transform[] Bones; public Transform RootBone; - public void AttachTo(GameObject dst) + public void ReplaceMesh(GameObject dst) { if (Bones != null) { // recalc bindposes Mesh.bindposes = Bones.Select(x => x.worldToLocalMatrix * dst.transform.localToWorldMatrix).ToArray(); - var dstRenderer = dst.AddComponent(); + var dstRenderer = dst.GetComponent(); dstRenderer.sharedMesh = Mesh; dstRenderer.sharedMaterials = Materials; dstRenderer.bones = Bones; @@ -24,7 +24,7 @@ namespace UniGLTF.MeshUtility } else { - var dstFilter = dst.AddComponent(); + var dstFilter = dst.GetComponent(); dstFilter.sharedMesh = Mesh; var dstRenderer = dst.gameObject.AddComponent(); dstRenderer.sharedMaterials = Materials; diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs index 4b65f6094..3a7c5c804 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs @@ -128,9 +128,7 @@ namespace UniGLTF.MeshUtility /// 正規化前のボーンから正規化後のボーンを得る /// /// - public static Mesh NormalizeSkinnedMesh( - SkinnedMeshRenderer src, - Dictionary boneMap) + public static Mesh NormalizeSkinnedMesh(SkinnedMeshRenderer src) { if (src == null || !src.enabled @@ -144,12 +142,6 @@ namespace UniGLTF.MeshUtility var srcMesh = src.sharedMesh; var originalSrcMesh = srcMesh; - // 元の Transform[] bones から、無効なboneを取り除いて前に詰めた配列を作る - var dstBones = src.bones - .Where(x => x != null && boneMap.ContainsKey(x)) - .Select(x => boneMap[x]) - .ToArray(); - var hasBoneWeight = src.bones != null && src.bones.Length > 0; if (!hasBoneWeight) { @@ -172,7 +164,6 @@ namespace UniGLTF.MeshUtility srcMesh.bindposes = new Matrix4x4[] { Matrix4x4.identity }; src.rootBone = src.transform; - dstBones = new[] { boneMap[src.transform] }; src.bones = new[] { src.transform }; src.sharedMesh = srcMesh; } @@ -182,8 +173,7 @@ namespace UniGLTF.MeshUtility mesh.name = srcMesh.name + ".baked"; src.BakeMesh(mesh); - // 新しい骨格のボーンウェイトを作成する - mesh.boneWeights = MapBoneWeight(srcMesh.boneWeights, boneMap, src.bones, dstBones); + mesh.boneWeights = srcMesh.boneWeights; //var m = src.localToWorldMatrix; // include scaling var m = default(Matrix4x4); @@ -195,20 +185,6 @@ namespace UniGLTF.MeshUtility // CopyBlendShapes(src, srcMesh, mesh, m); - // var blendShapeBackup = new List(); - // if (!FreezeBlendShape) - // { - // for (int i = 0; i < srcMesh.blendShapeCount; ++i) - // { - // blendShapeBackup.Add(src.GetBlendShapeWeight(i)); - // src.SetBlendShapeWeight(i, 0); - // } - // } - // for (int i = 0; i < blendShapeBackup.Count; ++i) - // { - // src.SetBlendShapeWeight(i, blendShapeBackup[i]); - // } - if (!hasBoneWeight) { // restore bones diff --git a/Assets/VRM/Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs b/Assets/VRM/Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs index 479641975..3004d866a 100644 --- a/Assets/VRM/Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs +++ b/Assets/VRM/Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs @@ -66,37 +66,19 @@ namespace VRM } } - // 正規化されたヒエラルキーを作る - var (normalized, bMap, newMesh) = BoneNormalizer.NormalizeHierarchyFreezeMesh(go); - - foreach (var (k, v) in newMesh) - { - v.AttachTo(k.gameObject); - } + // Meshの焼きこみ + var newMesh = BoneNormalizer.NormalizeHierarchyFreezeMesh(go); + // 焼いたMeshで置き換える + BoneNormalizer.Replace(go, newMesh, true, true); // 新しいヒエラルキーからAvatarを作る - var newAvatar = UniHumanoid.AvatarDescription.CreateAvatarForCopyHierarchy( - go.GetComponent(), normalized, bMap, avatarDescription => - { - var vrmHuman = go.GetComponent(); - if (vrmHuman != null && vrmHuman.Description != null) - { - avatarDescription.armStretch = vrmHuman.Description.armStretch; - avatarDescription.legStretch = vrmHuman.Description.legStretch; - avatarDescription.upperArmTwist = vrmHuman.Description.upperArmTwist; - avatarDescription.lowerArmTwist = vrmHuman.Description.lowerArmTwist; - avatarDescription.upperLegTwist = vrmHuman.Description.upperLegTwist; - avatarDescription.lowerLegTwist = vrmHuman.Description.lowerLegTwist; - avatarDescription.feetSpacing = vrmHuman.Description.feetSpacing; - avatarDescription.hasTranslationDoF = vrmHuman.Description.hasTranslationDoF; - } - }); - var newAnimator = normalized.GetOrAddComponent(); + var newAnimator = go.GetComponent(); + var newAvatar = UniHumanoid.AvatarDescription.RecreateAvatar(newAnimator); newAnimator.avatar = newAvatar; - CopyVRMComponents(go, normalized, bMap); + // CopyVRMComponents(go, normalized, bMap); - return normalized; + return go; } /// From b890201581cf01642f499584b3dcdab3e2c1a1cc Mon Sep 17 00:00:00 2001 From: ousttrue Date: Mon, 27 Nov 2023 20:23:16 +0900 Subject: [PATCH 09/25] PrefabUtility.UnpackPrefabInstance --- .../Editor/MeshUtility/MeshUtilityDialog.cs | 34 ++++++----- .../Editor/MeshUtility/MeshUtilityMessages.cs | 56 ++++++++++--------- .../Runtime/Extensions/UnityExtensions.cs | 37 +++++++++++- 3 files changed, 87 insertions(+), 40 deletions(-) diff --git a/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs b/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs index 07faa5bfd..d940c312a 100644 --- a/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs +++ b/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs @@ -155,15 +155,6 @@ namespace UniGLTF.MeshUtility // m_excludes.AddRange(excludes); // } - /// - /// Scene と Prefab で挙動をスイッチする。 - /// - /// - Scene: ヒエラルキーを操作する。Asset の 書き出しはしない。UNDO はする。TODO: 明示的な Asset の書き出し。 - /// - Prefab: 対象をコピーして処理する。Undo は実装しない。結果を Asset として書き出し、処理後にコピーは削除する。 - /// - /// - bool TargetIsPrefab => _exportTarget != null && _exportTarget.scene.name == null; - protected virtual void DialogMessage() { EditorGUILayout.HelpBox(MeshUtilityMessages.MESH_UTILITY.Msg(), MessageType.Info); @@ -172,7 +163,6 @@ namespace UniGLTF.MeshUtility private void OnGUI() { var modified = false; - _scrollPos = EditorGUILayout.BeginScrollView(_scrollPos); EditorGUIUtility.labelWidth = 200; LanguageGetter.OnGuiSelectLang(); @@ -187,11 +177,23 @@ namespace UniGLTF.MeshUtility MeshIntegration.UpdateMeshIntegrationList(_exportTarget); modified = true; } + if (_exportTarget == null) + { + return; + } + + _scrollPos = EditorGUILayout.BeginScrollView(_scrollPos); // GameObject or Prefab ? - if (TargetIsPrefab) + switch (_exportTarget.GetPrefabType()) { - EditorGUILayout.HelpBox(MeshUtilityMessages.PREFAB_TARGET.Msg(), MessageType.Warning); + case UnityExtensions.PrefabType.PrefabAsset: + EditorGUILayout.HelpBox(MeshUtilityMessages.PREFAB_ASSET.Msg(), MessageType.Warning); + break; + + case UnityExtensions.PrefabType.PrefabInstance: + EditorGUILayout.HelpBox(MeshUtilityMessages.PREFAB_INSTANCE.Msg(), MessageType.Warning); + break; } // tab bar @@ -255,7 +257,7 @@ namespace UniGLTF.MeshUtility GUI.enabled = true; if (pressed) { - if (TargetIsPrefab) + if (_exportTarget.GetPrefabType() == UnityExtensions.PrefabType.PrefabAsset) { /// [prefab] /// @@ -283,6 +285,7 @@ namespace UniGLTF.MeshUtility assetFolder = unityPath.Value; var copy = GameObject.Instantiate(_exportTarget); + PrefabUtility.UnpackPrefabInstance(copy, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction); var (results, created) = MeshUtility.Process(copy); @@ -294,6 +297,11 @@ namespace UniGLTF.MeshUtility else { Undo.RegisterFullObjectHierarchyUndo(_exportTarget, "MeshUtility"); + + if (_exportTarget.GetPrefabType() == UnityExtensions.PrefabType.PrefabInstance) + { + PrefabUtility.UnpackPrefabInstance(_exportTarget, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction); + } var (results, created) = MeshUtility.Process(_exportTarget); foreach (var go in created) { diff --git a/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityMessages.cs b/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityMessages.cs index c48251e22..a516e0c96 100644 --- a/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityMessages.cs +++ b/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityMessages.cs @@ -44,36 +44,36 @@ Separate the mesh attached to the SkinnedMeshRenderer under the target object wi [LangMsg(Languages.en, "Divide by the presence or absence of `blendshape`")] MESH_SEPARATOR_BY_BLENDSHAPE, -// [LangMsg(Languages.ja, @"ターゲットオブジェクト下の SkinnedMeshRenderer または MeshFilter にアタッチされたメッシュを統合します。 + // [LangMsg(Languages.ja, @"ターゲットオブジェクト下の SkinnedMeshRenderer または MeshFilter にアタッチされたメッシュを統合します。 -// * Asset: Assets/MeshIntegrated.mesh が作成されます(上書きされるので注意してください)。 -// * Scene: コピーされたヒエラルキーでは、統合された Mesh は除去されます。新しく MeshIntegrator ノードが追加されます。 -// * VRMではBlendShapeClipの統合など追加の処理が必要です。`VRM0-MeshIntegratorWizard` を使ってください。 -// ")] -// [LangMsg(Languages.en, @"Integrates the attached mesh into the SkinnedMeshRenderer or MeshFilter under the target object. + // * Asset: Assets/MeshIntegrated.mesh が作成されます(上書きされるので注意してください)。 + // * Scene: コピーされたヒエラルキーでは、統合された Mesh は除去されます。新しく MeshIntegrator ノードが追加されます。 + // * VRMではBlendShapeClipの統合など追加の処理が必要です。`VRM0-MeshIntegratorWizard` を使ってください。 + // ")] + // [LangMsg(Languages.en, @"Integrates the attached mesh into the SkinnedMeshRenderer or MeshFilter under the target object. -// * Asset: Assets/MeshIntegrated.mesh is created (note that it will be overwritten). -// * Scene: In the copied hierarchy, the integrated mesh is removed. A new MeshIntegrator node is added. -// * VRM requires additional processing such as BlendShapeClip integration. Use the `VRM0-MeshIntegratorWizard` integration feature. -// ")] -// MESH_INTEGRATOR, + // * Asset: Assets/MeshIntegrated.mesh is created (note that it will be overwritten). + // * Scene: In the copied hierarchy, the integrated mesh is removed. A new MeshIntegrator node is added. + // * VRM requires additional processing such as BlendShapeClip integration. Use the `VRM0-MeshIntegratorWizard` integration feature. + // ")] + // MESH_INTEGRATOR, -// // [LangMsg(Languages.ja, "静的メッシュを一つに統合します")] -// // [LangMsg(Languages.en, "Integrate static meshes into one")] -// // STATIC_MESH_INTEGRATOR, + // // [LangMsg(Languages.ja, "静的メッシュを一つに統合します")] + // // [LangMsg(Languages.en, "Integrate static meshes into one")] + // // STATIC_MESH_INTEGRATOR, -// [LangMsg(Languages.ja, @"指定された SkinnedMeshRenderer から、指定されたボーンに対する Weight を保持する三角形を除去します。 + // [LangMsg(Languages.ja, @"指定された SkinnedMeshRenderer から、指定されたボーンに対する Weight を保持する三角形を除去します。 -// * Asset: 元の Mesh と同じフォルダに、三角形を除去した Mesh を保存します。 -// * Scene: コピーされたヒエラルキーでは、三角形が除去された Mesh に差し替えられます。 -// ")] -// [LangMsg(Languages.en, @"Removes the triangle that holds the weight for the specified bone from the specified SkinnedMeshRenderer. + // * Asset: 元の Mesh と同じフォルダに、三角形を除去した Mesh を保存します。 + // * Scene: コピーされたヒエラルキーでは、三角形が除去された Mesh に差し替えられます。 + // ")] + // [LangMsg(Languages.en, @"Removes the triangle that holds the weight for the specified bone from the specified SkinnedMeshRenderer. -// * Assets: Save the mesh with the triangles removed in the same folder as the original mesh. -// * Scene: In the copied hierarchy, it will be replaced with a Mesh with the triangles removed. -// ")] + // * Assets: Save the mesh with the triangles removed in the same folder as the original mesh. + // * Scene: In the copied hierarchy, it will be replaced with a Mesh with the triangles removed. + // ")] -// BONE_MESH_ERASER, + // BONE_MESH_ERASER, [LangMsg(Languages.ja, "Skinned Meshを選んでください")] [LangMsg(Languages.en, "Select a skinned mesh")] @@ -103,8 +103,12 @@ Separate the mesh attached to the SkinnedMeshRenderer under the target object wi [LangMsg(Languages.en, "Because BlendShapeClip causes inconsistency , use `VRM0 -> MeshIntegrator` instead")] VRM_DETECTED, - [LangMsg(Languages.ja, "対象は, Prefab です。実行時に書き出しファイルの指定があります。")] - [LangMsg(Languages.en, "The target is prefab. A temporary file is specified during execution.")] - PREFAB_TARGET, + [LangMsg(Languages.ja, "対象は, Prefab Asset です。実行時に書き出しファイルの指定があります。")] + [LangMsg(Languages.en, "The target is prefab asset. A temporary file is specified during execution.")] + PREFAB_ASSET, + + [LangMsg(Languages.ja, "対象は, Prefab Instance です。Unpack されます。")] + [LangMsg(Languages.en, "The target is prefab asset. A temporary file is specified during execution.")] + PREFAB_INSTANCE, } } \ No newline at end of file diff --git a/Assets/UniGLTF/Runtime/Extensions/UnityExtensions.cs b/Assets/UniGLTF/Runtime/Extensions/UnityExtensions.cs index 58321b08f..17bbb3bba 100644 --- a/Assets/UniGLTF/Runtime/Extensions/UnityExtensions.cs +++ b/Assets/UniGLTF/Runtime/Extensions/UnityExtensions.cs @@ -449,5 +449,40 @@ namespace UniGLTF } return true; } + + public enum PrefabType + { + PrefabAsset, + PrefabInstance, + NotPrefab, + } + + /// + /// Scene と Prefab で挙動をスイッチする。 + /// + /// - Scene: ヒエラルキーを操作する。Asset の 書き出しはしない。UNDO はする。TODO: 明示的な Asset の書き出し。 + /// - Prefab: 対象をコピーして処理する。Undo は実装しない。結果を Asset として書き出し、処理後にコピーは削除する。 + /// + /// + public static PrefabType GetPrefabType(this GameObject go) + { + if (go == null) + { + throw new ArgumentNullException(); + } + if (!go.scene.IsValid()) + { + return PrefabType.PrefabAsset; + } + +#if UNITY_EDITOR + if (PrefabUtility.GetOutermostPrefabInstanceRoot(go) != null) + { + return PrefabType.PrefabInstance; + } +#endif + + return PrefabType.NotPrefab; + } } -} +} \ No newline at end of file From 32401b0318715e5213bb1756df287454ade828ff Mon Sep 17 00:00:00 2001 From: ousttrue Date: Mon, 27 Nov 2023 21:29:09 +0900 Subject: [PATCH 10/25] fix BoneNormalizer --- .../Runtime/MeshUtility/BoneNormalizer.cs | 45 ++++++++----------- .../Runtime/MeshUtility/GltfMeshUtility.cs | 4 +- .../Runtime/MeshUtility/MeshFreezer.cs | 2 - 3 files changed, 20 insertions(+), 31 deletions(-) diff --git a/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs b/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs index bfad06d94..e3db9e0c9 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs @@ -51,11 +51,7 @@ namespace UniGLTF.MeshUtility /// BlendShapeを0クリアするか否か。false の場合 BlendShape の現状を Bake する /// Avatarを作る関数 /// - public static Dictionary NormalizeHierarchyFreezeMesh( - GameObject go, - bool removeScaling = true, - bool removeRotation = true - ) + public static Dictionary NormalizeHierarchyFreezeMesh(GameObject go) { // // 各メッシュから回転・スケールを取り除いてBinding行列を再計算する @@ -76,29 +72,11 @@ namespace UniGLTF.MeshUtility bool FreezeRotation, bool FreezeScaling) { var boneMap = go.transform.Traverse().ToDictionary(x => x, x => new EuclideanTransform(x.rotation, x.position)); - // Func getSrc = dst => - // { - // foreach (var (k, v) in boneMap) - // { - // if (v == dst) - // { - // return k; - // } - // } - // throw new NotImplementedException(); - // }; - foreach (var (src, tr) in boneMap) + // first, update hierarchy + foreach (var src in go.transform.Traverse()) { - src.position = tr.Translation; - if (FreezeRotation) - { - src.rotation = Quaternion.identity; - } - else - { - src.rotation = tr.Rotation; - } + var tr = boneMap[src]; if (FreezeScaling) { src.localScale = Vector3.one; @@ -108,6 +86,21 @@ namespace UniGLTF.MeshUtility throw new NotImplementedException(); } + if (FreezeRotation) + { + src.rotation = Quaternion.identity; + } + else + { + src.rotation = tr.Rotation; + } + + src.position = tr.Translation; + } + + // second, replace mesh + foreach (var (src, tr) in boneMap) + { if (newMesh.TryGetValue(src, out var info)) { info.ReplaceMesh(src.gameObject); diff --git a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs index 2ebd9e15d..91c584b1d 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs @@ -160,9 +160,7 @@ namespace UniGLTF.MeshUtility if (FreezeBlendShape || FreezeRotation || FreezeScaling) { // MeshをBakeする - var newMesh = BoneNormalizer.NormalizeHierarchyFreezeMesh(go, - removeScaling: FreezeScaling, - removeRotation: FreezeRotation); + var newMesh = BoneNormalizer.NormalizeHierarchyFreezeMesh(go); // - ヒエラルキーから回転・拡縮を除去する // - BakeされたMeshで置き換える diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs index 3a7c5c804..4648bbf7c 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs @@ -161,8 +161,6 @@ namespace UniGLTF.MeshUtility weight3 = 0.0f, }; srcMesh.boneWeights = Enumerable.Range(0, srcMesh.vertexCount).Select(x => bw).ToArray(); - srcMesh.bindposes = new Matrix4x4[] { Matrix4x4.identity }; - src.rootBone = src.transform; src.bones = new[] { src.transform }; src.sharedMesh = srcMesh; From 171cdef7d13a10d8dd8bacfceb476bca746d1b0a Mon Sep 17 00:00:00 2001 From: ousttrue Date: Mon, 27 Nov 2023 21:29:32 +0900 Subject: [PATCH 11/25] fix RecreateAvatar ??? --- .../Runtime/UniHumanoid/AvatarDescription.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Assets/UniGLTF/Runtime/UniHumanoid/AvatarDescription.cs b/Assets/UniGLTF/Runtime/UniHumanoid/AvatarDescription.cs index c4224252c..5478f008e 100644 --- a/Assets/UniGLTF/Runtime/UniHumanoid/AvatarDescription.cs +++ b/Assets/UniGLTF/Runtime/UniHumanoid/AvatarDescription.cs @@ -327,7 +327,19 @@ namespace UniHumanoid var avatarDescription = UniHumanoid.AvatarDescription.Create(); avatarDescription.SetHumanBones(map); - var avatar = avatarDescription.CreateAvatar(src.transform); + + // ??? clear old avatar ??? + var t = src.transform; + if (Application.isPlaying) + { + GameObject.Destroy(src); + } + else + { + GameObject.DestroyImmediate(src, true); + } + + var avatar = avatarDescription.CreateAvatar(t); avatar.name = "created"; return avatar; } From 32af053a6224b49fbee1f20600c98374ea19b2c8 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Tue, 28 Nov 2023 18:02:56 +0900 Subject: [PATCH 12/25] vrm-0.x firstperson --- .../VrmMeshIntegratorWizard.cs | 51 ++++--- .../VRM/Runtime/FirstPerson/VRMFirstPerson.cs | 11 ++ .../SkinnedMeshUtility/VrmMeshUtility.cs | 138 ++++++++++++++++++ .../SkinnedMeshUtility/VrmMeshUtility.cs.meta | 11 ++ .../Runtime/MeshUtility/Vrm10MeshUtility.cs | 55 +++---- 5 files changed, 218 insertions(+), 48 deletions(-) create mode 100644 Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs create mode 100644 Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs.meta diff --git a/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs b/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs index 73610670f..ed590ef40 100644 --- a/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs +++ b/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs @@ -2,6 +2,7 @@ using UnityEditor; using UnityEngine; using UniGLTF.M17N; +using UniGLTF; namespace VRM @@ -9,7 +10,6 @@ namespace VRM public class VrmMeshIntegratorWizard : UniGLTF.MeshUtility.MeshUtilityDialog { public new const string MENU_NAME = "VRM 0.x MeshUtility"; - public new static void OpenWindow() { var window = @@ -17,29 +17,36 @@ namespace VRM window.titleContent = new GUIContent(MENU_NAME); window.Show(); } + protected override void Validate() + { + base.Validate(); + if (_exportTarget.GetComponent() == null) + { + _validations.Add(Validation.Error("target is not vrm1")); + return; + } + } - // void Integrate() - // { - // // 統合 - // var excludes = m_excludes.Where(x => x.Exclude).Select(x => x.Mesh); - // var results = Integrate(copy, excludes, m_separateByBlendShape); + VrmMeshUtility _meshUtil; + VrmMeshUtility VrmMeshUtility + { + get + { + if (_meshUtil == null) + { + _meshUtil = new VrmMeshUtility(); + } + return _meshUtil; + } + } + protected override UniGLTF.MeshUtility.GltfMeshUtility MeshUtility => VrmMeshUtility; - // } - - // static List Integrate(GameObject root, IEnumerable excludes, bool separateByBlendShape) - // { - // var results = new List(); - // if (separateByBlendShape) - // { - // results.Add(MeshIntegratorUtility.Integrate(root, onlyBlendShapeRenderers: MeshEnumerateOption.OnlyWithoutBlendShape, excludes: excludes)); - // results.Add(MeshIntegratorUtility.Integrate(root, onlyBlendShapeRenderers: MeshEnumerateOption.OnlyWithBlendShape, excludes: excludes)); - // } - // else - // { - // results.Add(MeshIntegratorUtility.Integrate(root, onlyBlendShapeRenderers: MeshEnumerateOption.All, excludes: excludes)); - // } - // return results; - // } + protected override bool MeshIntegrateGui() + { + var firstPerson = ToggleIsModified("FirstPerson == AUTO の生成", ref MeshUtility.GenerateMeshForFirstPersonAuto); + var mod = base.MeshIntegrateGui(); + return firstPerson || mod; + } protected override void DialogMessage() { diff --git a/Assets/VRM/Runtime/FirstPerson/VRMFirstPerson.cs b/Assets/VRM/Runtime/FirstPerson/VRMFirstPerson.cs index 5f9e6a3fd..4bd4ff060 100644 --- a/Assets/VRM/Runtime/FirstPerson/VRMFirstPerson.cs +++ b/Assets/VRM/Runtime/FirstPerson/VRMFirstPerson.cs @@ -367,6 +367,17 @@ namespace VRM } } + /// + /// for MeshUtility interface + /// + public Mesh ProcessFirstPerson(Transform firstPersonBone, SkinnedMeshRenderer smr) + { + SetVisibilityFunc dummy = (Renderer renderer, bool firstPerson, bool thirdPerson) => + { + }; + return CreateHeadlessModel(smr, FirstPersonBone, dummy); + } + void OnDestroy() { foreach (var mesh in m_headlessMeshes) diff --git a/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs b/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs new file mode 100644 index 000000000..62ffd4187 --- /dev/null +++ b/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UniHumanoid; +using UnityEngine; + + +namespace VRM +{ + public class VrmMeshUtility : UniGLTF.MeshUtility.GltfMeshUtility + { + bool _generateFirstPerson = false; + protected override List CopyMeshIntegrationGroups() + { + var copy = new List(); + _generateFirstPerson = false; + if (GenerateMeshForFirstPersonAuto) + { + foreach (var g in MeshIntegrationGroups) + { + if (g.Name == "auto") + { + _generateFirstPerson = true; + // 元のメッシュを三人称に変更 + copy.Add(new UniGLTF.MeshUtility.MeshIntegrationGroup + { + Name = FirstPersonFlag.ThirdPersonOnly.ToString(), + Renderers = g.Renderers.ToList(), + }); + } + copy.Add(g); + } + } + else + { + copy.AddRange(MeshIntegrationGroups); + } + return copy; + } + + protected override + (UniGLTF.MeshUtility.MeshIntegrationResult, GameObject[]) Integrate( + GameObject empty, + UniGLTF.MeshUtility.MeshIntegrationGroup group) + { + var (result, newList) = base.Integrate(empty, group); + + if (_generateFirstPerson && group.Name == nameof(FirstPersonFlag.Auto)) + { + // Mesh 統合の後処理 + // FirstPerson == "auto" の場合に + // 頭部の無いモデルを追加で作成する + Debug.Log("generateFirstPerson"); + if (result.Integrated.Mesh != null) + { + // BlendShape 有り + _ProcessFirstPerson(_vrmInstance.FirstPersonBone, result.Integrated.IntegratedRenderer); + } + if (result.IntegratedNoBlendShape.Mesh != null) + { + // BlendShape 無しの方 + _ProcessFirstPerson(_vrmInstance.FirstPersonBone, result.IntegratedNoBlendShape.IntegratedRenderer); + } + } + + return (result, newList); + } + + private void _ProcessFirstPerson(Transform firstPersonBone, SkinnedMeshRenderer smr) + { + var mesh = _vrmInstance.ProcessFirstPerson(firstPersonBone, smr); + if (mesh != null) + { + smr.sharedMesh = mesh; + smr.name = "auto.headless"; + } + else + { + Debug.LogWarning("no result"); + } + } + + VRMFirstPerson _vrmInstance = null; + /// + /// glTF に比べて Humanoid や FirstPerson の処理が追加される + /// + public override (List, 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, newList) = base.Process(go); + + if (FreezeBlendShape || FreezeRotation || FreezeScaling) + { + var animator = go.GetComponent(); + var newAvatar = AvatarDescription.RecreateAvatar(animator); + animator.avatar = newAvatar; + } + + return (list, newList); + } + + public override void UpdateMeshIntegrationGroups(GameObject root) + { + if (root == null) + { + return; + } + var vrm1 = root.GetComponent(); + if (vrm1 == null) + { + return; + } + foreach (var a in vrm1.Renderers) + { + var g = _GetOrCreateGroup(a.FirstPersonFlag.ToString()); + g.Renderers.Add(a.Renderer); + } + } + } +} \ No newline at end of file diff --git a/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs.meta b/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs.meta new file mode 100644 index 000000000..851cb3e0c --- /dev/null +++ b/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fb346da8b7688c74eb627bebe1b21060 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs index d9e17f84a..2b8f039fb 100644 --- a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs +++ b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs @@ -1,10 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; -using UniGLTF.MeshUtility; using UniHumanoid; using UnityEngine; -using UnityEngine.Rendering; + namespace UniVRM10 { @@ -46,27 +45,51 @@ namespace UniVRM10 { var (result, newList) = base.Integrate(empty, group); - if (_generateFirstPerson && group.Name == "auto") + if (_generateFirstPerson && group.Name == nameof(UniGLTF.Extensions.VRMC_vrm.FirstPersonType.auto)) { + // Mesh 統合の後処理 + // FirstPerson == "auto" の場合に + // 頭部の無いモデルを追加で作成する Debug.Log("generateFirstPerson"); if (result.Integrated.Mesh != null) { - _ProcessFirstPerson(_vrmInstance, result.Integrated); + // BlendShape 有り + _ProcessFirstPerson(_vrmInstance.Humanoid.Head, result.Integrated.IntegratedRenderer); } if (result.IntegratedNoBlendShape.Mesh != null) { - _ProcessFirstPerson(_vrmInstance, result.IntegratedNoBlendShape); + // BlendShape 無しの方 + _ProcessFirstPerson(_vrmInstance.Humanoid.Head, result.IntegratedNoBlendShape.IntegratedRenderer); } } return (result, newList); } + private void _ProcessFirstPerson(Transform firstPersonBone, SkinnedMeshRenderer smr) + { + var task = VRM10ObjectFirstPerson.CreateErasedMeshAsync( + smr, + firstPersonBone, + new VRMShaders.ImmediateCaller()); + task.Wait(); + var mesh = task.Result; + if (mesh != null) + { + smr.sharedMesh = mesh; + smr.name = "auto.headless"; + } + else + { + Debug.LogWarning("no result"); + } + } + Vrm10Instance _vrmInstance = null; /// /// glTF に比べて Humanoid や FirstPerson の処理が追加される /// - public override (List, List) Process(GameObject go) + public override (List, List) Process(GameObject go) { _vrmInstance = go.GetComponent(); if (_vrmInstance == null) @@ -99,26 +122,6 @@ namespace UniVRM10 return (list, newList); } - 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 override void UpdateMeshIntegrationGroups(GameObject root) { if (root == null) From ddfe6921646b13e3816ec608e0c9523839f2f694 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Wed, 29 Nov 2023 18:45:15 +0900 Subject: [PATCH 13/25] CheckPrefabType --- .../Editor/MeshUtility/MeshUtilityDialog.cs | 5 ++++- Assets/UniGLTF/Editor/TopMenu.cs | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs b/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs index d940c312a..b1aa8de6f 100644 --- a/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs +++ b/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs @@ -285,7 +285,10 @@ namespace UniGLTF.MeshUtility assetFolder = unityPath.Value; var copy = GameObject.Instantiate(_exportTarget); - PrefabUtility.UnpackPrefabInstance(copy, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction); + if (PrefabUtility.IsOutermostPrefabInstanceRoot(copy)) + { + PrefabUtility.UnpackPrefabInstance(copy, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction); + } var (results, created) = MeshUtility.Process(copy); diff --git a/Assets/UniGLTF/Editor/TopMenu.cs b/Assets/UniGLTF/Editor/TopMenu.cs index 597e97196..cb98950bf 100644 --- a/Assets/UniGLTF/Editor/TopMenu.cs +++ b/Assets/UniGLTF/Editor/TopMenu.cs @@ -1,4 +1,6 @@ using UnityEditor; +using UnityEngine; + namespace UniGLTF { @@ -38,6 +40,20 @@ namespace UniGLTF [MenuItem(DevelopmentMenuPrefix + "/Generate UniJSON ConcreteCast", priority = 52)] private static void GenerateUniJsonConcreteCastCode() => UniJSON.ConcreteCast.GenerateGenericCast(); + + [MenuItem("GameObject/CheckPrefabType", false, 53)] + [MenuItem("Assets/CheckPrefabType", false, 53)] + private static void CheckPrefabType() + { + if (Selection.activeObject is GameObject go) + { + Debug.Log(go.GetPrefabType()); + } + else + { + Debug.Log(Selection.activeContext.GetType()); + } + } #endif } } From f8f27d0619009c8b2a05024ccdaae416ec44fba8 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Wed, 29 Nov 2023 20:02:46 +0900 Subject: [PATCH 14/25] =?UTF-8?q?prefab=20=E3=81=A8=20runtime=20=E3=81=A7?= =?UTF-8?q?=E6=95=B4=E5=90=88=E6=80=A7=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - prefab 時は instance 化する。統合グループをの内容をインスタンス後のもので置き換える - 未使用削除 --- .../Editor/MeshUtility/MeshUtilityDialog.cs | 86 +------- .../Editor/MeshUtility/TabMeshIntegrator.cs | 120 ----------- .../MeshUtility/TabMeshIntegrator.cs.meta | 11 - .../Runtime/MeshUtility/GltfMeshUtility.cs | 29 ++- .../MeshUtility/MeshIntegrationGroup.cs | 21 +- .../MeshUtility/MeshIntegratorUtility.cs | 199 ------------------ .../MeshUtility/MeshIntegratorUtility.cs.meta | 3 - .../SkinnedMeshUtility/VrmMeshUtility.cs | 6 +- .../Runtime/MeshUtility/Vrm10MeshUtility.cs | 6 +- 9 files changed, 50 insertions(+), 431 deletions(-) delete mode 100644 Assets/UniGLTF/Editor/MeshUtility/TabMeshIntegrator.cs delete mode 100644 Assets/UniGLTF/Editor/MeshUtility/TabMeshIntegrator.cs.meta delete mode 100644 Assets/UniGLTF/Runtime/MeshUtility/MeshIntegratorUtility.cs delete mode 100644 Assets/UniGLTF/Runtime/MeshUtility/MeshIntegratorUtility.cs.meta diff --git a/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs b/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs index b1aa8de6f..332324a10 100644 --- a/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs +++ b/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs @@ -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(); - // var excludes = new List(); - // foreach (var x in m_root.GetComponentsInChildren()) - // { - // 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"); diff --git a/Assets/UniGLTF/Editor/MeshUtility/TabMeshIntegrator.cs b/Assets/UniGLTF/Editor/MeshUtility/TabMeshIntegrator.cs deleted file mode 100644 index 035c1a6f2..000000000 --- a/Assets/UniGLTF/Editor/MeshUtility/TabMeshIntegrator.cs +++ /dev/null @@ -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().Length == 0 && root.GetComponentsInChildren().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}"; - } - } - - /// GameObject instance in scene or prefab - public static bool Execute(GameObject src, bool onlyBlendShapeRenderers) - { - var results = new List(); - - // 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; - } - } -} diff --git a/Assets/UniGLTF/Editor/MeshUtility/TabMeshIntegrator.cs.meta b/Assets/UniGLTF/Editor/MeshUtility/TabMeshIntegrator.cs.meta deleted file mode 100644 index 5c60a51fe..000000000 --- a/Assets/UniGLTF/Editor/MeshUtility/TabMeshIntegrator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 65a227dcf3cb5f34085bd6829894fb64 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs index 91c584b1d..0e4f8ebce 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs @@ -150,12 +150,31 @@ namespace UniGLTF.MeshUtility return empty; } - protected virtual List CopyMeshIntegrationGroups() + /// + /// + /// + /// MeshIntegrationGroup を作ったとき root + /// go が prefab だった場合に instance されたもの + /// + protected virtual IEnumerable 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, List) Process(GameObject go) + public virtual (List, List) 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(); - var empty = GetOrCreateEmpty(go, "mesh"); + var empty = GetOrCreateEmpty(instance ?? go, "mesh"); var results = new List(); foreach (var group in copy) diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationGroup.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationGroup.cs index 7d7158691..bf0b969e4 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationGroup.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationGroup.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using UnityEngine; @@ -9,9 +8,25 @@ namespace UniGLTF.MeshUtility public string Name; public List Renderers = new List(); - public static List 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()); + } + else if (r is MeshRenderer mr) + { + copy.Renderers.Add(instance.transform.GetFromPath(relative).GetComponent()); + } + } + return copy; } } } \ No newline at end of file diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegratorUtility.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegratorUtility.cs deleted file mode 100644 index 283fe3fc8..000000000 --- a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegratorUtility.cs +++ /dev/null @@ -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)"; - - /// - /// go を root としたヒエラルキーから Renderer を集めて、統合された Mesh 作成する - /// - /// - /// - /// true: BlendShapeを保持するSkinnedMeshRendererのみ - /// false: BlendShapeを保持しないSkinnedMeshRenderer + MeshRenderer - /// null: すべてのSkinnedMeshRenderer + MeshRenderer - /// - /// - public static MeshIntegrationResult Integrate(GameObject go, MeshEnumerateOption onlyBlendShapeRenderers, - IEnumerable 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 EnumerateSkinnedMeshRenderer(Transform root, MeshEnumerateOption hasBlendShape) - { - foreach (var x in Traverse(root)) - { - var renderer = x.GetComponent(); - 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 EnumerateMeshRenderer(Transform root) - { - foreach (var x in Traverse(root)) - { - var renderer = x.GetComponent(); - var filter = x.GetComponent(); - - if (renderer != null && - filter != null && - renderer.gameObject.activeInHierarchy && - filter.sharedMesh != null) - { - yield return renderer; - } - } - } - - private static IEnumerable 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 results) - { - // destroy original meshes - foreach (var skinnedMesh in copy.GetComponentsInChildren()) - { - GameObject.DestroyImmediate(skinnedMesh); - } - foreach (var normalMesh in copy.GetComponentsInChildren()) - { - if (normalMesh.gameObject.GetComponent()) - { - GameObject.DestroyImmediate(normalMesh.gameObject.GetComponent()); - } - GameObject.DestroyImmediate(normalMesh); - } - - // Add integrated - foreach (var result in results) - { - result.AddIntegratedRendererTo(copy); - } - } - } -} \ No newline at end of file diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegratorUtility.cs.meta b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegratorUtility.cs.meta deleted file mode 100644 index b9075e71b..000000000 --- a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegratorUtility.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: a982d9d30c0145038245b0214dc2f2e4 -timeCreated: 1560190306 \ No newline at end of file diff --git a/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs b/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs index 62ffd4187..afb4d3f3d 100644 --- a/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs +++ b/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs @@ -10,7 +10,7 @@ namespace VRM public class VrmMeshUtility : UniGLTF.MeshUtility.GltfMeshUtility { bool _generateFirstPerson = false; - protected override List CopyMeshIntegrationGroups() + protected override IEnumerable CopyInstantiate(GameObject go, GameObject instance) { var copy = new List(); _generateFirstPerson = false; @@ -84,7 +84,7 @@ namespace VRM /// /// glTF に比べて Humanoid や FirstPerson の処理が追加される /// - public override (List, List) Process(GameObject go) + public override (List, List) Process(GameObject go, GameObject instance) { _vrmInstance = go.GetComponent(); 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) { diff --git a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs index 2b8f039fb..15728a027 100644 --- a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs +++ b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs @@ -10,7 +10,7 @@ namespace UniVRM10 public class Vrm10MeshUtility : UniGLTF.MeshUtility.GltfMeshUtility { bool _generateFirstPerson = false; - protected override List CopyMeshIntegrationGroups() + protected override IEnumerable CopyInstantiate(GameObject go, GameObject instance) { var copy = new List(); _generateFirstPerson = false; @@ -89,7 +89,7 @@ namespace UniVRM10 /// /// glTF に比べて Humanoid や FirstPerson の処理が追加される /// - public override (List, List) Process(GameObject go) + public override (List, List) Process(GameObject go, GameObject instance) { _vrmInstance = go.GetComponent(); 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) { From f84a6ccb730760d52270ad6fc329c59776cec69e Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 1 Dec 2023 17:06:31 +0900 Subject: [PATCH 15/25] fix GltfMeshUtility.WriteAssets --- .../Editor/MeshUtility/MeshUtilityDialog.cs | 130 +++++++----------- .../Editor/MeshUtility/PrefabContext.cs | 63 +++++++++ .../Editor/MeshUtility/PrefabContext.cs.meta | 11 ++ .../UniGLTF/Editor/MeshUtility/UndoContext.cs | 27 ++++ .../Editor/MeshUtility/UndoContext.cs.meta | 11 ++ .../Runtime/MeshUtility/BoneNormalizer.cs | 10 +- .../Runtime/MeshUtility/GltfMeshUtility.cs | 54 +++++--- .../Runtime/MeshUtility/MeshAttachInfo.cs | 42 ++++-- .../MeshUtility/MeshIntegrationResult.cs | 8 ++ .../Runtime/MeshUtility/MeshIntegrator.cs | 15 +- .../VrmMeshIntegratorWizard.cs | 28 ++++ .../SkinnedMeshUtility/VrmMeshUtility.cs | 17 ++- .../Runtime/MeshUtility/Vrm10MeshUtility.cs | 14 +- 13 files changed, 300 insertions(+), 130 deletions(-) create mode 100644 Assets/UniGLTF/Editor/MeshUtility/PrefabContext.cs create mode 100644 Assets/UniGLTF/Editor/MeshUtility/PrefabContext.cs.meta create mode 100644 Assets/UniGLTF/Editor/MeshUtility/UndoContext.cs create mode 100644 Assets/UniGLTF/Editor/MeshUtility/UndoContext.cs.meta diff --git a/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs b/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs index 332324a10..b06889160 100644 --- a/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs +++ b/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs @@ -3,7 +3,7 @@ using UnityEditor; using UniGLTF.M17N; using System.Collections.Generic; using System.Linq; -using System.IO; +using System; namespace UniGLTF.MeshUtility @@ -179,54 +179,50 @@ namespace UniGLTF.MeshUtility { /// [prefab] /// - /// * backup するのではなく 変更した copy を作成する。元は変えない - /// * copy 先の統合前の renderer を disable で残さず destroy する - /// * 実行すると mesh, blendshape, blendShape を新規に作成する - /// * 新しいヒエラルキーを prefab に保存してから削除して終了する - - // 出力フォルダを決める - var folder = "Assets"; - var prefab = _exportTarget.GetPrefab(); - if (prefab != null) + /// * prefab から instance を作る + /// * instance に対して 焼き付け, 統合, 分離 を実行する + /// * instance のヒエラルキーが改変され、mesh 等のアセットは改変版が作成される(元は変わらない) + /// * instance を asset に保存してから prefab を削除して終了する + /// + UnityPath assetFolder = default; + try { - folder = AssetDatabase.GetAssetPath(prefab); - // Debug.Log(folder); + assetFolder = PrefabContext.GetOutFolder(_exportTarget); } - // 新規で作成されるアセットはすべてこのフォルダの中に作る。上書きチェックはしない - var assetFolder = EditorUtility.SaveFolderPanel("select asset save folder", Path.GetDirectoryName(folder), "VrmIntegrated"); - var unityPath = UniGLTF.UnityPath.FromFullpath(assetFolder); - if (!unityPath.IsUnderWritableFolder) + catch (Exception) { EditorUtility.DisplayDialog("asset folder", "Target folder must be in the Assets or writable Packages folder", "cancel"); return; } - assetFolder = unityPath.Value; - var copy = GameObject.Instantiate(_exportTarget); - if (PrefabUtility.IsOutermostPrefabInstanceRoot(copy)) + using (var context = new PrefabContext(_exportTarget, assetFolder)) { - PrefabUtility.UnpackPrefabInstance(copy, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction); + try + { + var (results, created) = MeshUtility.Process(_exportTarget, context.Instance); + + WriteAssets(context.Instance, context.AssetFolder, results); + } + catch (Exception ex) + { +#if DEBUG + Debug.LogException(ex, context.Instance); + context.Keep = true; +#endif + } } - - var (results, created) = MeshUtility.Process(_exportTarget, copy); - - WriteAssets(copy, assetFolder, results); - - // destroy scene - UnityEngine.Object.DestroyImmediate(copy); } else { - Undo.RegisterFullObjectHierarchyUndo(_exportTarget, "MeshUtility"); + using (var context = new UndoContext("MeshUtility", _exportTarget)) + { + var (results, created) = MeshUtility.Process(_exportTarget, null); - if (_exportTarget.GetPrefabType() == UnityExtensions.PrefabType.PrefabInstance) - { - PrefabUtility.UnpackPrefabInstance(_exportTarget, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction); - } - var (results, created) = MeshUtility.Process(_exportTarget, null); - foreach (var go in created) - { - Undo.RegisterCreatedObjectUndo(go, "MeshUtility"); + foreach (var go in created) + { + // 処理後の mesh をアタッチした Renderer.gameobject + Undo.RegisterCreatedObjectUndo(go, "MeshUtility"); + } } } @@ -235,68 +231,36 @@ namespace UniGLTF.MeshUtility } } - void WriteAssets(GameObject copy, string assetFolder, List results) + /// + /// Write Mesh & Prefab + /// + protected virtual void WriteAssets(GameObject copy, string assetFolder, List results) { - // // write mesh asset foreach (var result in results) { - var childAssetPath = $"{assetFolder}/{result.Integrated.IntegratedRenderer.gameObject.name}{ASSET_SUFFIX}"; - Debug.LogFormat("CreateAsset: {0}", childAssetPath); - AssetDatabase.CreateAsset(result.Integrated.IntegratedRenderer.sharedMesh, childAssetPath); - } - - // 統合した結果をヒエラルキーに追加する - foreach (var result in results) - { - if (result.Integrated.IntegratedRenderer != null) + if (result.Integrated != null) { - result.Integrated.IntegratedRenderer.transform.SetParent(copy.transform, false); + var childAssetPath = $"{assetFolder}/{result.Integrated.IntegratedRenderer.gameObject.name}{ASSET_SUFFIX}"; + Debug.LogFormat("CreateAsset: {0}", childAssetPath); + AssetDatabase.CreateAsset(result.Integrated.IntegratedRenderer.sharedMesh, childAssetPath); + } + if (result.IntegratedNoBlendShape != null) + { + var childAssetPath = $"{assetFolder}/{result.IntegratedNoBlendShape.IntegratedRenderer.gameObject.name}{ASSET_SUFFIX}"; + Debug.LogFormat("CreateAsset: {0}", childAssetPath); + AssetDatabase.CreateAsset(result.IntegratedNoBlendShape.IntegratedRenderer.sharedMesh, childAssetPath); } } - // 統合した結果を反映した BlendShapeClip を作成して置き換える - // var clips = VRMMeshIntegratorUtility.FollowBlendshapeRendererChange(results, copy, assetFolder); - - // 用が済んだ 統合前 の renderer を削除する - foreach (var result in results) - { - foreach (var renderer in result.SourceMeshRenderers) - { - GameObject.DestroyImmediate(renderer); - } - foreach (var renderer in result.SourceSkinnedMeshRenderers) - { - GameObject.DestroyImmediate(renderer); - } - } - - // reset firstperson - // var firstperson = copy.GetComponent(); - // if (firstperson != null) - // { - // firstperson.Reset(); - // } - // prefab - var prefabPath = $"{assetFolder}/VrmIntegrated.prefab"; + var prefabPath = $"{assetFolder}/Integrated.prefab"; Debug.Log(prefabPath); PrefabUtility.SaveAsPrefabAsset(copy, prefabPath, out bool success); if (!success) { throw new System.Exception($"PrefabUtility.SaveAsPrefabAsset: {prefabPath}"); } - - // var prefabReference = AssetDatabase.LoadAssetAtPath(prefabPath); - // foreach (var clip in clips) - // { - // var so = new SerializedObject(clip); - // so.Update(); - // // clip.Prefab = copy; - // var prop = so.FindProperty("m_prefab"); - // prop.objectReferenceValue = prefabReference; - // so.ApplyModifiedProperties(); - // } } protected bool ToggleIsModified(string label, ref bool value) diff --git a/Assets/UniGLTF/Editor/MeshUtility/PrefabContext.cs b/Assets/UniGLTF/Editor/MeshUtility/PrefabContext.cs new file mode 100644 index 000000000..df80d3f3b --- /dev/null +++ b/Assets/UniGLTF/Editor/MeshUtility/PrefabContext.cs @@ -0,0 +1,63 @@ +using System; +using System.IO; +using UnityEditor; +using UnityEngine; + +namespace UniGLTF.MeshUtility +{ + // Instantiate + class PrefabContext : IDisposable + { + public readonly GameObject Instance; + + readonly UnityPath _assetFolder; + + public bool Keep = false; + + public string AssetFolder => _assetFolder.Value; + + public PrefabContext(GameObject prefab, UnityPath assetFolder) + { + this._assetFolder = assetFolder; + this.Instance = GameObject.Instantiate(prefab); + if (PrefabUtility.IsOutermostPrefabInstanceRoot(this.Instance)) + { + // どういう条件でここに来るかはよくわからない + PrefabUtility.UnpackPrefabInstance(this.Instance, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction); + } + } + + // - Instance を Asset に書き出す + // - Instance を削除する + public void Dispose() + { + if (Keep) + { + // for debug + return; + } + UnityEngine.Object.DestroyImmediate(Instance); + } + + public static UnityPath GetOutFolder(GameObject _exportTarget) + { + // 出力フォルダを決める + var folder = "Assets"; + var prefab = _exportTarget.GetPrefab(); + if (prefab != null) + { + folder = AssetDatabase.GetAssetPath(prefab); + // Debug.Log(folder); + } + + // 新規で作成されるアセットはすべてこのフォルダの中に作る。上書きチェックはしない + var assetFolder = EditorUtility.SaveFolderPanel("select asset save folder", Path.GetDirectoryName(folder), "Integrated"); + var unityPath = UniGLTF.UnityPath.FromFullpath(assetFolder); + if (!unityPath.IsUnderWritableFolder) + { + throw new Exception("not in asset folder"); + } + return unityPath; + } + } +} \ No newline at end of file diff --git a/Assets/UniGLTF/Editor/MeshUtility/PrefabContext.cs.meta b/Assets/UniGLTF/Editor/MeshUtility/PrefabContext.cs.meta new file mode 100644 index 000000000..6cc2fba37 --- /dev/null +++ b/Assets/UniGLTF/Editor/MeshUtility/PrefabContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 948458ced6bcc904781eed04ebe7cd01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UniGLTF/Editor/MeshUtility/UndoContext.cs b/Assets/UniGLTF/Editor/MeshUtility/UndoContext.cs new file mode 100644 index 000000000..eaf53f0f8 --- /dev/null +++ b/Assets/UniGLTF/Editor/MeshUtility/UndoContext.cs @@ -0,0 +1,27 @@ +using System; +using UnityEditor; +using UnityEngine; + +namespace UniGLTF.MeshUtility +{ + // Instantiate + class UndoContext : IDisposable + { + public UndoContext(string undoName, GameObject go) + { + Undo.RegisterFullObjectHierarchyUndo(go, undoName); + if (go.GetPrefabType() == UnityExtensions.PrefabType.PrefabInstance) + { + PrefabUtility.UnpackPrefabInstance(go, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction); + } + } + + public void Dispose() + { + // 特に何もしない + // Undo すると元に戻ってしまう + + // TODO: あれば一時オブジェクトの破棄 + } + } +} diff --git a/Assets/UniGLTF/Editor/MeshUtility/UndoContext.cs.meta b/Assets/UniGLTF/Editor/MeshUtility/UndoContext.cs.meta new file mode 100644 index 000000000..bf4202411 --- /dev/null +++ b/Assets/UniGLTF/Editor/MeshUtility/UndoContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5019966789c0e094a8f58fc2734c9a35 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs b/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs index e3db9e0c9..81be0e9ac 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs @@ -45,17 +45,11 @@ namespace UniGLTF.MeshUtility /// - /// 回転とスケールを除去したヒエラルキーのコピーを作成する(MeshをBakeする) + /// 各レンダラー(SkinnedMeshRenderer と MeshRenderer)にアタッチされた sharedMesh に対して + /// 回転とスケールを除去し、BlendShape の現状を焼き付けた版を作成する(まだ、アタッチしない) /// - /// 対象のヒエラルキーのルート - /// BlendShapeを0クリアするか否か。false の場合 BlendShape の現状を Bake する - /// Avatarを作る関数 - /// public static Dictionary NormalizeHierarchyFreezeMesh(GameObject go) { - // - // 各メッシュから回転・スケールを取り除いてBinding行列を再計算する - // var result = new Dictionary(); foreach (var src in go.transform.Traverse()) { diff --git a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs index 0e4f8ebce..270876ccf 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs @@ -174,33 +174,40 @@ namespace UniGLTF.MeshUtility } } - public virtual (List, List) Process(GameObject go, GameObject instance) + public virtual (List, List) Process(GameObject _go, GameObject _instance) { + var target = _instance ?? _go; if (FreezeBlendShape || FreezeRotation || FreezeScaling) { // MeshをBakeする - var newMesh = BoneNormalizer.NormalizeHierarchyFreezeMesh(go); + var newMesh = BoneNormalizer.NormalizeHierarchyFreezeMesh(target); // - ヒエラルキーから回転・拡縮を除去する // - BakeされたMeshで置き換える // - bindPoses を再計算する - BoneNormalizer.Replace(go, newMesh, FreezeRotation, FreezeScaling); + BoneNormalizer.Replace(target, newMesh, FreezeRotation, FreezeScaling); } - var copy = CopyInstantiate(go, instance); + // prefab が instantiate されていた場合に + // Mesh統合設定を instantiate に置き換える + var groupCopy = CopyInstantiate(_go, _instance); var newList = new List(); - var empty = GetOrCreateEmpty(instance ?? go, "mesh"); + var empty = GetOrCreateEmpty(target, "mesh"); var results = new List(); - foreach (var group in copy) + foreach (var group in groupCopy) { - var (result, newGo) = Integrate(empty, group); - results.Add(result); - newList.AddRange(newGo); + if (TryIntegrate(empty, group, out var resultAndAdded)) + { + var (result, newGo) = resultAndAdded; + results.Add(result); + newList.AddRange(newGo); + } } + // // 用が済んだ 統合前 の renderer を削除する foreach (var result in results) { foreach (var r in result.SourceMeshRenderers) @@ -212,22 +219,37 @@ namespace UniGLTF.MeshUtility RemoveComponent(r); } } + // foreach (var result in results) + // { + // foreach (var renderer in result.SourceMeshRenderers) + // { + // GameObject.DestroyImmediate(renderer); + // } + // foreach (var renderer in result.SourceSkinnedMeshRenderers) + // { + // GameObject.DestroyImmediate(renderer); + // } + // } MeshIntegrationGroups.Clear(); return (results, newList); } - protected virtual (MeshIntegrationResult, GameObject[]) Integrate(GameObject empty, - MeshIntegrationGroup group) + protected virtual bool TryIntegrate(GameObject empty, + MeshIntegrationGroup group, out (MeshIntegrationResult, GameObject[]) resultAndAdded) { - var result = MeshIntegrator.Integrate(group, SplitByBlendShape + if (MeshIntegrator.TryIntegrate(group, SplitByBlendShape ? MeshIntegrator.BlendShapeOperation.Split - : MeshIntegrator.BlendShapeOperation.Use); + : MeshIntegrator.BlendShapeOperation.Use, out var result)) + { + var newGo = result.AddIntegratedRendererTo(empty).ToArray(); + resultAndAdded = (result, newGo); + return true; + } - var newGo = result.AddIntegratedRendererTo(empty).ToArray(); - - return (result, newGo); + resultAndAdded = default; + return false; } } } diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs index 6684777c4..54f36ee4f 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshAttachInfo.cs @@ -1,3 +1,4 @@ +using System; using System.Linq; using UnityEngine; @@ -11,23 +12,46 @@ namespace UniGLTF.MeshUtility public Transform RootBone; public void ReplaceMesh(GameObject dst) { + if (dst == null) + { + throw new ArgumentNullException(); + } + if (Bones != null) { // recalc bindposes Mesh.bindposes = Bones.Select(x => x.worldToLocalMatrix * dst.transform.localToWorldMatrix).ToArray(); - var dstRenderer = dst.GetComponent(); - dstRenderer.sharedMesh = Mesh; - dstRenderer.sharedMaterials = Materials; - dstRenderer.bones = Bones; - dstRenderer.rootBone = RootBone; + if (dst.GetComponent() is SkinnedMeshRenderer dstRenderer) + { + dstRenderer.sharedMesh = Mesh; + dstRenderer.sharedMaterials = Materials; + dstRenderer.bones = Bones; + dstRenderer.rootBone = RootBone; + } + else + { + Debug.LogError($"SkinnedMeshRenderer not found", dst); + } } else { - var dstFilter = dst.GetComponent(); - dstFilter.sharedMesh = Mesh; - var dstRenderer = dst.gameObject.AddComponent(); - dstRenderer.sharedMaterials = Materials; + if (dst.GetComponent() is MeshFilter dstFilter) + { + dstFilter.sharedMesh = Mesh; + if (dst.gameObject.GetComponent() is MeshRenderer dstRenderer) + { + dstRenderer.sharedMaterials = Materials; + } + else + { + Debug.LogError($"MeshRenderer not found", dst); + } + } + else + { + Debug.LogError($"MeshFilter not found", dst); + } } } } diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationResult.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationResult.cs index 493ca7071..34b42df5a 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationResult.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationResult.cs @@ -48,16 +48,24 @@ namespace UniGLTF.MeshUtility public IEnumerable AddIntegratedRendererTo(GameObject parent) { + int count = 0; if (Integrated != null) { Integrated.AddIntegratedRendererTo(parent, Bones); + ++count; yield return Integrated.IntegratedRenderer.gameObject; } if (IntegratedNoBlendShape != null) { IntegratedNoBlendShape.AddIntegratedRendererTo(parent, Bones); + ++count; yield return IntegratedNoBlendShape.IntegratedRenderer.gameObject; } + + if (count == 0) + { + throw new NotImplementedException(); + } } } } diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrator.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrator.cs index 9dd280350..6c3b26bb0 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrator.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrator.cs @@ -275,7 +275,8 @@ namespace UniGLTF.MeshUtility return found; } - public static MeshIntegrationResult Integrate(MeshIntegrationGroup group, BlendShapeOperation op) + public static bool TryIntegrate(MeshIntegrationGroup group, BlendShapeOperation op, + out MeshIntegrationResult result) { var integrator = new MeshUtility.MeshIntegrator(); foreach (var x in group.Renderers) @@ -289,7 +290,15 @@ namespace UniGLTF.MeshUtility integrator.Push(mr); } } - return integrator.Integrate(group.Name, op); + result = integrator.Integrate(group.Name, op); + if (result.Integrated != null || result.IntegratedNoBlendShape != null) + { + return true; + } + else + { + return false; + } } delegate bool TriangleFilter(int i0, int i1, int i2); @@ -351,7 +360,7 @@ namespace UniGLTF.MeshUtility return mesh; } - public MeshIntegrationResult Integrate(string name, BlendShapeOperation op) + MeshIntegrationResult Integrate(string name, BlendShapeOperation op) { if (_Bones.Count != _BindPoses.Count) { diff --git a/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs b/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs index ed590ef40..776cefccd 100644 --- a/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs +++ b/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs @@ -3,6 +3,8 @@ using UnityEditor; using UnityEngine; using UniGLTF.M17N; using UniGLTF; +using System.Collections.Generic; +using UniGLTF.MeshUtility; namespace VRM @@ -48,6 +50,32 @@ namespace VRM return firstPerson || mod; } + protected override void WriteAssets(GameObject copy, string assetFolder, List results) + { + base.WriteAssets(copy, assetFolder, results); + + // 統合した結果を反映した BlendShapeClip を作成して置き換える + // var clips = VRMMeshIntegratorUtility.FollowBlendshapeRendererChange(results, copy, assetFolder); + + // reset firstperson + // var firstperson = copy.GetComponent(); + // if (firstperson != null) + // { + // firstperson.Reset(); + // } + + // var prefabReference = AssetDatabase.LoadAssetAtPath(prefabPath); + // foreach (var clip in clips) + // { + // var so = new SerializedObject(clip); + // so.Update(); + // // clip.Prefab = copy; + // var prop = so.FindProperty("m_prefab"); + // prop.objectReferenceValue = prefabReference; + // so.ApplyModifiedProperties(); + // } + } + protected override void DialogMessage() { EditorGUILayout.HelpBox(Message.MESH_UTILITY.Msg(), MessageType.Info); diff --git a/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs b/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs index afb4d3f3d..161f0fddd 100644 --- a/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs +++ b/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs @@ -38,13 +38,19 @@ namespace VRM return copy; } - protected override - (UniGLTF.MeshUtility.MeshIntegrationResult, GameObject[]) Integrate( + protected override bool + TryIntegrate( GameObject empty, - UniGLTF.MeshUtility.MeshIntegrationGroup group) + UniGLTF.MeshUtility.MeshIntegrationGroup group, + out (UniGLTF.MeshUtility.MeshIntegrationResult, GameObject[]) resultAndAdded) { - var (result, newList) = base.Integrate(empty, group); + if (!base.TryIntegrate(empty, group, out resultAndAdded)) + { + resultAndAdded = default; + return false; + } + var (result, newGo) = resultAndAdded; if (_generateFirstPerson && group.Name == nameof(FirstPersonFlag.Auto)) { // Mesh 統合の後処理 @@ -62,8 +68,7 @@ namespace VRM _ProcessFirstPerson(_vrmInstance.FirstPersonBone, result.IntegratedNoBlendShape.IntegratedRenderer); } } - - return (result, newList); + return true; } private void _ProcessFirstPerson(Transform firstPersonBone, SkinnedMeshRenderer smr) diff --git a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs index 15728a027..e9caabcef 100644 --- a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs +++ b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs @@ -39,11 +39,16 @@ namespace UniVRM10 } protected override - (UniGLTF.MeshUtility.MeshIntegrationResult, GameObject[]) Integrate( + bool TryIntegrate( GameObject empty, - UniGLTF.MeshUtility.MeshIntegrationGroup group) + UniGLTF.MeshUtility.MeshIntegrationGroup group, + out (UniGLTF.MeshUtility.MeshIntegrationResult, GameObject[]) resultAndAdded) { - var (result, newList) = base.Integrate(empty, group); + if (!base.TryIntegrate(empty, group, out resultAndAdded)) + { + return false; + } + var (result, newList) = resultAndAdded; if (_generateFirstPerson && group.Name == nameof(UniGLTF.Extensions.VRMC_vrm.FirstPersonType.auto)) { @@ -62,8 +67,7 @@ namespace UniVRM10 _ProcessFirstPerson(_vrmInstance.Humanoid.Head, result.IntegratedNoBlendShape.IntegratedRenderer); } } - - return (result, newList); + return true; } private void _ProcessFirstPerson(Transform firstPersonBone, SkinnedMeshRenderer smr) From 00e12781233664bf847e7308d7d7deb5967642ca Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 1 Dec 2023 17:17:48 +0900 Subject: [PATCH 16/25] fix NormalizeNoneSkinnedMesh --- .../UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs | 9 +++++---- .../UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs | 2 +- Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs | 13 +++++++++++-- .../Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs | 2 +- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs b/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs index 81be0e9ac..a5f6891cd 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs @@ -9,7 +9,7 @@ namespace UniGLTF.MeshUtility { public static class BoneNormalizer { - private static MeshAttachInfo CreateMeshInfo(Transform src) + private static MeshAttachInfo CreateMeshInfo(Transform src, bool freezeRotation) { // SkinnedMeshRenderer var smr = src.GetComponent(); @@ -29,7 +29,7 @@ namespace UniGLTF.MeshUtility var mr = src.GetComponent(); if (mr != null) { - var dstMesh = MeshFreezer.NormalizeNoneSkinnedMesh(mr); + var dstMesh = MeshFreezer.NormalizeNoneSkinnedMesh(mr, freezeRotation); if (dstMesh != null) { return new MeshAttachInfo @@ -48,12 +48,13 @@ namespace UniGLTF.MeshUtility /// 各レンダラー(SkinnedMeshRenderer と MeshRenderer)にアタッチされた sharedMesh に対して /// 回転とスケールを除去し、BlendShape の現状を焼き付けた版を作成する(まだ、アタッチしない) /// - public static Dictionary NormalizeHierarchyFreezeMesh(GameObject go) + public static Dictionary NormalizeHierarchyFreezeMesh( + GameObject go, bool freezeRotation) { var result = new Dictionary(); foreach (var src in go.transform.Traverse()) { - var info = CreateMeshInfo(src); + var info = CreateMeshInfo(src, freezeRotation); if (info != null) { result.Add(src, info); diff --git a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs index 270876ccf..adad8582c 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs @@ -180,7 +180,7 @@ namespace UniGLTF.MeshUtility if (FreezeBlendShape || FreezeRotation || FreezeScaling) { // MeshをBakeする - var newMesh = BoneNormalizer.NormalizeHierarchyFreezeMesh(target); + var newMesh = BoneNormalizer.NormalizeHierarchyFreezeMesh(target, FreezeRotation); // - ヒエラルキーから回転・拡縮を除去する // - BakeされたMeshで置き換える diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs index 4648bbf7c..fcd185a04 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using UnityEngine; +using UnityEngine.UIElements; using VRMShaders; namespace UniGLTF.MeshUtility @@ -330,7 +331,7 @@ namespace UniGLTF.MeshUtility } } - public static Mesh NormalizeNoneSkinnedMesh(MeshRenderer srcRenderer) + public static Mesh NormalizeNoneSkinnedMesh(MeshRenderer srcRenderer, bool freezeRotation) { if (srcRenderer == null || !srcRenderer.enabled) { @@ -347,7 +348,15 @@ namespace UniGLTF.MeshUtility var dstMesh = srcFilter.sharedMesh.Copy(false); // Meshに乗っているボーンの姿勢を適用する - dstMesh.ApplyRotationAndScale(srcRenderer.transform.localToWorldMatrix); + if (freezeRotation) + { + dstMesh.ApplyRotationAndScale(srcRenderer.transform.localToWorldMatrix); + } + else + { + var (t, r, s) = srcRenderer.transform.localToWorldMatrix.Decompose(); + dstMesh.ApplyRotationAndScale(Matrix4x4.TRS(t, Quaternion.identity, s)); + } return dstMesh; } } diff --git a/Assets/VRM/Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs b/Assets/VRM/Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs index 3004d866a..81f630c52 100644 --- a/Assets/VRM/Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs +++ b/Assets/VRM/Runtime/SkinnedMeshUtility/VRMBoneNormalizer.cs @@ -67,7 +67,7 @@ namespace VRM } // Meshの焼きこみ - var newMesh = BoneNormalizer.NormalizeHierarchyFreezeMesh(go); + var newMesh = BoneNormalizer.NormalizeHierarchyFreezeMesh(go, true); // 焼いたMeshで置き換える BoneNormalizer.Replace(go, newMesh, true, true); From 103b575439a675c52f53a8e6ec5d14f80745dedf Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 1 Dec 2023 17:50:21 +0900 Subject: [PATCH 17/25] fix mesh bone. fix WriteAndReload --- .../Editor/MeshUtility/MeshUtilityDialog.cs | 4 ++-- .../Runtime/MeshUtility/MeshIntegrationResult.cs | 15 +++++++++++++++ .../UniGLTF/Runtime/MeshUtility/MeshIntegrator.cs | 5 ++--- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs b/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs index b06889160..a2ae3207a 100644 --- a/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs +++ b/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs @@ -243,13 +243,13 @@ namespace UniGLTF.MeshUtility { var childAssetPath = $"{assetFolder}/{result.Integrated.IntegratedRenderer.gameObject.name}{ASSET_SUFFIX}"; Debug.LogFormat("CreateAsset: {0}", childAssetPath); - AssetDatabase.CreateAsset(result.Integrated.IntegratedRenderer.sharedMesh, childAssetPath); + result.Integrated.WriteAndReload(childAssetPath); } if (result.IntegratedNoBlendShape != null) { var childAssetPath = $"{assetFolder}/{result.IntegratedNoBlendShape.IntegratedRenderer.gameObject.name}{ASSET_SUFFIX}"; Debug.LogFormat("CreateAsset: {0}", childAssetPath); - AssetDatabase.CreateAsset(result.IntegratedNoBlendShape.IntegratedRenderer.sharedMesh, childAssetPath); + result.IntegratedNoBlendShape.WriteAndReload(childAssetPath); } } diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationResult.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationResult.cs index 34b42df5a..20103d21d 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationResult.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationResult.cs @@ -2,6 +2,9 @@ using System.Collections.Generic; using System.Linq; using UnityEngine; +#if UNITY_EDITOR +using UnityEditor; +#endif namespace UniGLTF.MeshUtility { @@ -29,6 +32,18 @@ namespace UniGLTF.MeshUtility smr.bones = bones; IntegratedRenderer = smr; } + +#if UNITY_EDITOR + public void WriteAndReload(string assetPath) + { + AssetDatabase.CreateAsset(IntegratedRenderer.sharedMesh, assetPath); + var unityPath = UnityPath.FromUnityPath(assetPath); + unityPath.ImportAsset(); + var mesh = unityPath.LoadAsset(); + // replace reloaded + IntegratedRenderer.sharedMesh = mesh; + } +#endif } public class MeshIntegrationResult diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrator.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrator.cs index 6c3b26bb0..1f9c1c89e 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrator.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrator.cs @@ -128,11 +128,10 @@ namespace UniGLTF.MeshUtility }) ); - var self = renderer.transform; - var bone = self.parent; + var bone = renderer.transform; if (bone == null) { - Debug.LogWarningFormat("{0} is root gameobject.", self.name); + Debug.LogWarningFormat("{0} is root gameobject.", bone.name); return; } var boneIndex = AddBoneIfUnique(bone); From e3404e1f16d9c6ce421e1fc623b8f8e334175195 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Mon, 4 Dec 2023 17:00:15 +0900 Subject: [PATCH 18/25] refactor MeshUtility.Process params --- .../Editor/MeshUtility/MeshUtilityDialog.cs | 8 +- .../Runtime/MeshUtility/GltfMeshUtility.cs | 75 ++++++------------- .../SkinnedMeshUtility/VrmMeshUtility.cs | 13 ++-- .../Runtime/MeshUtility/Vrm10MeshUtility.cs | 13 ++-- 4 files changed, 41 insertions(+), 68 deletions(-) diff --git a/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs b/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs index a2ae3207a..3a35821f2 100644 --- a/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs +++ b/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs @@ -199,7 +199,11 @@ namespace UniGLTF.MeshUtility { try { - var (results, created) = MeshUtility.Process(_exportTarget, context.Instance); + // prefab が instantiate されていた場合に + // Mesh統合設定を instantiate に置き換える + var groupCopy = MeshUtility.CopyInstantiate(_exportTarget, context.Instance); + + var (results, created) = MeshUtility.Process(context.Instance, groupCopy); WriteAssets(context.Instance, context.AssetFolder, results); } @@ -216,7 +220,7 @@ namespace UniGLTF.MeshUtility { using (var context = new UndoContext("MeshUtility", _exportTarget)) { - var (results, created) = MeshUtility.Process(_exportTarget, null); + var (results, created) = MeshUtility.Process(_exportTarget, MeshUtility.MeshIntegrationGroups); foreach (var go in created) { diff --git a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs index adad8582c..bffca8e6d 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs @@ -99,40 +99,6 @@ namespace UniGLTF.MeshUtility }); } - 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()) @@ -156,7 +122,7 @@ namespace UniGLTF.MeshUtility /// MeshIntegrationGroup を作ったとき root /// go が prefab だった場合に instance されたもの /// - protected virtual IEnumerable CopyInstantiate(GameObject go, GameObject instance) + public virtual IEnumerable CopyInstantiate(GameObject go, GameObject instance) { if (instance == null) { @@ -174,9 +140,9 @@ namespace UniGLTF.MeshUtility } } - public virtual (List, List) Process(GameObject _go, GameObject _instance) + public virtual (List, List) Process( + GameObject target, IEnumerable groupCopy) { - var target = _instance ?? _go; if (FreezeBlendShape || FreezeRotation || FreezeScaling) { // MeshをBakeする @@ -188,10 +154,6 @@ namespace UniGLTF.MeshUtility BoneNormalizer.Replace(target, newMesh, FreezeRotation, FreezeScaling); } - // prefab が instantiate されていた場合に - // Mesh統合設定を instantiate に置き換える - var groupCopy = CopyInstantiate(_go, _instance); - var newList = new List(); var empty = GetOrCreateEmpty(target, "mesh"); @@ -212,24 +174,29 @@ namespace UniGLTF.MeshUtility { foreach (var r in result.SourceMeshRenderers) { - RemoveComponent(r); + if (Application.isPlaying) + { + GameObject.Destroy(r.gameObject.GetComponent()); + GameObject.Destroy(r); + } + else + { + GameObject.DestroyImmediate(r.gameObject.GetComponent()); + GameObject.DestroyImmediate(r); + } } foreach (var r in result.SourceSkinnedMeshRenderers) { - RemoveComponent(r); + if (Application.isPlaying) + { + GameObject.Destroy(r); + } + else + { + GameObject.DestroyImmediate(r); + } } } - // foreach (var result in results) - // { - // foreach (var renderer in result.SourceMeshRenderers) - // { - // GameObject.DestroyImmediate(renderer); - // } - // foreach (var renderer in result.SourceSkinnedMeshRenderers) - // { - // GameObject.DestroyImmediate(renderer); - // } - // } MeshIntegrationGroups.Clear(); diff --git a/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs b/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs index 161f0fddd..37a9abdf8 100644 --- a/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs +++ b/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs @@ -10,7 +10,7 @@ namespace VRM public class VrmMeshUtility : UniGLTF.MeshUtility.GltfMeshUtility { bool _generateFirstPerson = false; - protected override IEnumerable CopyInstantiate(GameObject go, GameObject instance) + public override IEnumerable CopyInstantiate(GameObject go, GameObject instance) { var copy = new List(); _generateFirstPerson = false; @@ -89,9 +89,10 @@ namespace VRM /// /// glTF に比べて Humanoid や FirstPerson の処理が追加される /// - public override (List, List) Process(GameObject go, GameObject instance) + public override (List, List) Process( + GameObject target, IEnumerable copyGroup) { - _vrmInstance = go.GetComponent(); + _vrmInstance = target.GetComponent(); if (_vrmInstance == null) { throw new ArgumentException(); @@ -102,7 +103,7 @@ namespace VRM throw new NotImplementedException(); // 必用? - var animator = go.GetComponent(); + var animator = target.GetComponent(); var newAvatar = AvatarDescription.RecreateAvatar(animator); animator.avatar = newAvatar; } @@ -110,11 +111,11 @@ namespace VRM // TODO: update: spring // TODO: update: constraint // TODO: update: firstPerson offset - var (list, newList) = base.Process(go, instance); + var (list, newList) = base.Process(target, copyGroup); if (FreezeBlendShape || FreezeRotation || FreezeScaling) { - var animator = go.GetComponent(); + var animator = target.GetComponent(); var newAvatar = AvatarDescription.RecreateAvatar(animator); animator.avatar = newAvatar; } diff --git a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs index e9caabcef..c106b6c28 100644 --- a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs +++ b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs @@ -10,7 +10,7 @@ namespace UniVRM10 public class Vrm10MeshUtility : UniGLTF.MeshUtility.GltfMeshUtility { bool _generateFirstPerson = false; - protected override IEnumerable CopyInstantiate(GameObject go, GameObject instance) + public override IEnumerable CopyInstantiate(GameObject go, GameObject instance) { var copy = new List(); _generateFirstPerson = false; @@ -93,9 +93,10 @@ namespace UniVRM10 /// /// glTF に比べて Humanoid や FirstPerson の処理が追加される /// - public override (List, List) Process(GameObject go, GameObject instance) + public override (List, List) Process( + GameObject target, IEnumerable groupCopy) { - _vrmInstance = go.GetComponent(); + _vrmInstance = target.GetComponent(); if (_vrmInstance == null) { throw new ArgumentException(); @@ -106,7 +107,7 @@ namespace UniVRM10 throw new NotImplementedException(); // 必用? - var animator = go.GetComponent(); + var animator = target.GetComponent(); var newAvatar = AvatarDescription.RecreateAvatar(animator); animator.avatar = newAvatar; } @@ -114,11 +115,11 @@ namespace UniVRM10 // TODO: update: spring // TODO: update: constraint // TODO: update: firstPerson offset - var (list, newList) = base.Process(go, instance); + var (list, newList) = base.Process(target, groupCopy); if (FreezeBlendShape || FreezeRotation || FreezeScaling) { - var animator = go.GetComponent(); + var animator = target.GetComponent(); var newAvatar = AvatarDescription.RecreateAvatar(animator); animator.avatar = newAvatar; } From b5a7c1b13bdc4d01cfeefb54f162e519287a7103 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Mon, 4 Dec 2023 17:04:44 +0900 Subject: [PATCH 19/25] remove GltfMeshUtility.ForceUniqueName. automatically force when createAvatar --- Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs | 3 +-- Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs | 6 ------ .../VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs | 10 ---------- Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs | 10 ---------- 4 files changed, 1 insertion(+), 28 deletions(-) diff --git a/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs b/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs index 3a35821f2..7caaf44ae 100644 --- a/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs +++ b/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs @@ -280,11 +280,10 @@ namespace UniGLTF.MeshUtility bool MeshFreezeGui() { - var forceUniqueName = ToggleIsModified("ForceUniqueName", ref MeshUtility.ForceUniqueName); var blendShape = ToggleIsModified("BlendShape", ref MeshUtility.FreezeBlendShape); var scale = ToggleIsModified("Scale", ref MeshUtility.FreezeScaling); var rotation = ToggleIsModified("Rotation", ref MeshUtility.FreezeRotation); - return forceUniqueName || blendShape || scale || rotation; + return blendShape || scale || rotation; } protected virtual bool MeshIntegrateGui() diff --git a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs index bffca8e6d..ce3b5a23b 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs @@ -17,12 +17,6 @@ namespace UniGLTF.MeshUtility /// public class GltfMeshUtility { - /// - /// GameObject 名が重複している場合にリネームする。 - /// 最初に実行(Avatar生成時のエラーを回避?) - /// - public bool ForceUniqueName = false; - /// /// Same as VRM-0 normalization /// - Mesh diff --git a/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs b/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs index 37a9abdf8..aa3e0b272 100644 --- a/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs +++ b/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs @@ -98,16 +98,6 @@ namespace VRM throw new ArgumentException(); } - if (ForceUniqueName) - { - throw new NotImplementedException(); - - // 必用? - var animator = target.GetComponent(); - var newAvatar = AvatarDescription.RecreateAvatar(animator); - animator.avatar = newAvatar; - } - // TODO: update: spring // TODO: update: constraint // TODO: update: firstPerson offset diff --git a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs index c106b6c28..7c4330a98 100644 --- a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs +++ b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs @@ -102,16 +102,6 @@ namespace UniVRM10 throw new ArgumentException(); } - if (ForceUniqueName) - { - throw new NotImplementedException(); - - // 必用? - var animator = target.GetComponent(); - var newAvatar = AvatarDescription.RecreateAvatar(animator); - animator.avatar = newAvatar; - } - // TODO: update: spring // TODO: update: constraint // TODO: update: firstPerson offset From fb7cb163b12ea4b48e06d1b3eaf640ebda98ffe2 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Mon, 4 Dec 2023 17:55:36 +0900 Subject: [PATCH 20/25] fix VrmMeshIntegratorWizard.WriteAssets --- .../Editor/MeshUtility/MeshUtilityDialog.cs | 9 ++++- .../Runtime/MeshUtility/GltfMeshUtility.cs | 11 +++-- .../Runtime/UniHumanoid/AvatarDescription.cs | 13 +----- .../VRMMeshIntegratorUtility.cs | 2 +- .../VrmMeshIntegratorWizard.cs | 40 ++++++++++--------- .../SkinnedMeshUtility/VrmMeshUtility.cs | 37 ++++++++++++----- 6 files changed, 63 insertions(+), 49 deletions(-) diff --git a/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs b/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs index 7caaf44ae..343ecafa5 100644 --- a/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs +++ b/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs @@ -205,7 +205,9 @@ namespace UniGLTF.MeshUtility var (results, created) = MeshUtility.Process(context.Instance, groupCopy); - WriteAssets(context.Instance, context.AssetFolder, results); + WriteAssets(context.Instance, context.AssetFolder, results, _exportTarget); + + MeshUtility.clear(results); } catch (Exception ex) { @@ -221,6 +223,7 @@ namespace UniGLTF.MeshUtility using (var context = new UndoContext("MeshUtility", _exportTarget)) { var (results, created) = MeshUtility.Process(_exportTarget, MeshUtility.MeshIntegrationGroups); + MeshUtility.clear(results); foreach (var go in created) { @@ -238,7 +241,7 @@ namespace UniGLTF.MeshUtility /// /// Write Mesh & Prefab /// - protected virtual void WriteAssets(GameObject copy, string assetFolder, List results) + protected virtual string WriteAssets(GameObject copy, string assetFolder, List results, GameObject prefab) { // write mesh asset foreach (var result in results) @@ -265,6 +268,8 @@ namespace UniGLTF.MeshUtility { throw new System.Exception($"PrefabUtility.SaveAsPrefabAsset: {prefabPath}"); } + + return prefabPath; } protected bool ToggleIsModified(string label, ref bool value) diff --git a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs index ce3b5a23b..6366450b3 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs @@ -163,7 +163,12 @@ namespace UniGLTF.MeshUtility } } - // // 用が済んだ 統合前 の renderer を削除する + return (results, newList); + } + + public void clear(List results) + { + // 用が済んだ 統合前 の renderer を削除する foreach (var result in results) { foreach (var r in result.SourceMeshRenderers) @@ -187,14 +192,12 @@ namespace UniGLTF.MeshUtility } else { - GameObject.DestroyImmediate(r); + GameObject.DestroyImmediate(r, true); } } } MeshIntegrationGroups.Clear(); - - return (results, newList); } protected virtual bool TryIntegrate(GameObject empty, diff --git a/Assets/UniGLTF/Runtime/UniHumanoid/AvatarDescription.cs b/Assets/UniGLTF/Runtime/UniHumanoid/AvatarDescription.cs index 5478f008e..5a7f24a5b 100644 --- a/Assets/UniGLTF/Runtime/UniHumanoid/AvatarDescription.cs +++ b/Assets/UniGLTF/Runtime/UniHumanoid/AvatarDescription.cs @@ -328,18 +328,7 @@ namespace UniHumanoid var avatarDescription = UniHumanoid.AvatarDescription.Create(); avatarDescription.SetHumanBones(map); - // ??? clear old avatar ??? - var t = src.transform; - if (Application.isPlaying) - { - GameObject.Destroy(src); - } - else - { - GameObject.DestroyImmediate(src, true); - } - - var avatar = avatarDescription.CreateAvatar(t); + var avatar = avatarDescription.CreateAvatar(src.transform); avatar.name = "created"; return avatar; } diff --git a/Assets/VRM/Editor/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs b/Assets/VRM/Editor/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs index 33faa8359..4fe5542b6 100644 --- a/Assets/VRM/Editor/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs +++ b/Assets/VRM/Editor/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs @@ -21,7 +21,7 @@ namespace VRM { return clips; } - var result = results.FirstOrDefault(x => x.Integrated.Mesh.blendShapeCount > 0); + var result = results.FirstOrDefault(x => x.Integrated?.Mesh.blendShapeCount > 0); if (result == null) { return clips; diff --git a/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs b/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs index 776cefccd..7da4743f9 100644 --- a/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs +++ b/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs @@ -50,30 +50,32 @@ namespace VRM return firstPerson || mod; } - protected override void WriteAssets(GameObject copy, string assetFolder, List results) + protected override string WriteAssets(GameObject target, string assetFolder, List results, GameObject prefab) { - base.WriteAssets(copy, assetFolder, results); - // 統合した結果を反映した BlendShapeClip を作成して置き換える - // var clips = VRMMeshIntegratorUtility.FollowBlendshapeRendererChange(results, copy, assetFolder); + var clips = VRMMeshIntegratorUtility.FollowBlendshapeRendererChange(results, target, assetFolder); // reset firstperson - // var firstperson = copy.GetComponent(); - // if (firstperson != null) - // { - // firstperson.Reset(); - // } + if (target.GetComponent() is VRMFirstPerson firstperson) + { + firstperson.Reset(); + } - // var prefabReference = AssetDatabase.LoadAssetAtPath(prefabPath); - // foreach (var clip in clips) - // { - // var so = new SerializedObject(clip); - // so.Update(); - // // clip.Prefab = copy; - // var prop = so.FindProperty("m_prefab"); - // prop.objectReferenceValue = prefabReference; - // so.ApplyModifiedProperties(); - // } + // write mesh & prefab + var prefabPath = base.WriteAssets(target, assetFolder, results, prefab); + + var prefabReference = AssetDatabase.LoadAssetAtPath(prefabPath); + foreach (var clip in clips) + { + var so = new SerializedObject(clip); + so.Update(); + // clip.Prefab = copy; + var prop = so.FindProperty("m_prefab"); + prop.objectReferenceValue = prefabReference; + so.ApplyModifiedProperties(); + } + + return prefabPath; } protected override void DialogMessage() diff --git a/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs b/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs index aa3e0b272..21d9bdd4f 100644 --- a/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs +++ b/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs @@ -12,30 +12,33 @@ namespace VRM bool _generateFirstPerson = false; public override IEnumerable CopyInstantiate(GameObject go, GameObject instance) { - var copy = new List(); _generateFirstPerson = false; + + var copy = base.CopyInstantiate(go, instance); if (GenerateMeshForFirstPersonAuto) { - foreach (var g in MeshIntegrationGroups) + foreach (var g in copy) { if (g.Name == "auto") { _generateFirstPerson = true; // 元のメッシュを三人称に変更 - copy.Add(new UniGLTF.MeshUtility.MeshIntegrationGroup + yield return new UniGLTF.MeshUtility.MeshIntegrationGroup { Name = FirstPersonFlag.ThirdPersonOnly.ToString(), Renderers = g.Renderers.ToList(), - }); + }; } - copy.Add(g); + yield return g; } } else { - copy.AddRange(MeshIntegrationGroups); + foreach (var g in copy) + { + yield return g; + } } - return copy; } protected override bool @@ -107,7 +110,19 @@ namespace VRM { var animator = target.GetComponent(); var newAvatar = AvatarDescription.RecreateAvatar(animator); - animator.avatar = newAvatar; + + // ??? clear old avatar ??? + var t = animator.gameObject; + if (Application.isPlaying) + { + GameObject.Destroy(animator); + } + else + { + GameObject.DestroyImmediate(animator); + } + + t.AddComponent().avatar = newAvatar; } return (list, newList); @@ -119,12 +134,12 @@ namespace VRM { return; } - var vrm1 = root.GetComponent(); - if (vrm1 == null) + var vrm0 = root.GetComponent(); + if (vrm0 == null) { return; } - foreach (var a in vrm1.Renderers) + foreach (var a in vrm0.Renderers) { var g = _GetOrCreateGroup(a.FirstPersonFlag.ToString()); g.Renderers.Add(a.Renderer); From b12c9ed87c30652bb28f9dc545828f277ff97cc4 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Tue, 5 Dec 2023 16:21:35 +0900 Subject: [PATCH 21/25] WriteAssets and WritePrefab --- .../Editor/MeshUtility/MeshUtilityDialog.cs | 27 +++++++++++-------- .../Runtime/MeshUtility/GltfMeshUtility.cs | 2 +- .../VrmMeshIntegratorWizard.cs | 26 ++++++++++-------- 3 files changed, 32 insertions(+), 23 deletions(-) diff --git a/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs b/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs index 343ecafa5..1c10a6eab 100644 --- a/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs +++ b/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs @@ -205,9 +205,9 @@ namespace UniGLTF.MeshUtility var (results, created) = MeshUtility.Process(context.Instance, groupCopy); - WriteAssets(context.Instance, context.AssetFolder, results, _exportTarget); - - MeshUtility.clear(results); + // TODO: this should be replaced export and reimport ? + WriteAssets(context.AssetFolder, context.Instance, results); + WritePrefab(context.AssetFolder, context.Instance); } catch (Exception ex) { @@ -223,7 +223,7 @@ namespace UniGLTF.MeshUtility using (var context = new UndoContext("MeshUtility", _exportTarget)) { var (results, created) = MeshUtility.Process(_exportTarget, MeshUtility.MeshIntegrationGroups); - MeshUtility.clear(results); + MeshUtility.Clear(results); foreach (var go in created) { @@ -239,11 +239,10 @@ namespace UniGLTF.MeshUtility } /// - /// Write Mesh & Prefab + /// Write Mesh /// - protected virtual string WriteAssets(GameObject copy, string assetFolder, List results, GameObject prefab) + protected virtual void WriteAssets(string assetFolder, GameObject instance, List results) { - // write mesh asset foreach (var result in results) { if (result.Integrated != null) @@ -260,15 +259,21 @@ namespace UniGLTF.MeshUtility } } - // prefab + MeshUtility.Clear(results); + } + + /// + /// Write Prefab + /// + protected virtual string WritePrefab(string assetFolder, GameObject instance) + { var prefabPath = $"{assetFolder}/Integrated.prefab"; Debug.Log(prefabPath); - PrefabUtility.SaveAsPrefabAsset(copy, prefabPath, out bool success); + PrefabUtility.SaveAsPrefabAsset(instance, prefabPath, out bool success); if (!success) { - throw new System.Exception($"PrefabUtility.SaveAsPrefabAsset: {prefabPath}"); + throw new Exception($"PrefabUtility.SaveAsPrefabAsset: {prefabPath}"); } - return prefabPath; } diff --git a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs index 6366450b3..0ce1cad6e 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs @@ -166,7 +166,7 @@ namespace UniGLTF.MeshUtility return (results, newList); } - public void clear(List results) + public void Clear(List results) { // 用が済んだ 統合前 の renderer を削除する foreach (var result in results) diff --git a/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs b/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs index 7da4743f9..a059ac207 100644 --- a/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs +++ b/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs @@ -50,22 +50,27 @@ namespace VRM return firstPerson || mod; } - protected override string WriteAssets(GameObject target, string assetFolder, List results, GameObject prefab) + List _clips; + protected override void WriteAssets(string assetFolder, GameObject target, List results) { // 統合した結果を反映した BlendShapeClip を作成して置き換える - var clips = VRMMeshIntegratorUtility.FollowBlendshapeRendererChange(results, target, assetFolder); - - // reset firstperson - if (target.GetComponent() is VRMFirstPerson firstperson) - { - firstperson.Reset(); - } + _clips = VRMMeshIntegratorUtility.FollowBlendshapeRendererChange(results, target, assetFolder); // write mesh & prefab - var prefabPath = base.WriteAssets(target, assetFolder, results, prefab); + base.WriteAssets(assetFolder, target, results); + // reset firstPerson + if (target.GetComponent() is VRMFirstPerson firstPerson) + { + firstPerson.Reset(); + } + } + + protected override string WritePrefab(string assetFolder, GameObject instance) + { + var prefabPath = base.WritePrefab(assetFolder, instance); var prefabReference = AssetDatabase.LoadAssetAtPath(prefabPath); - foreach (var clip in clips) + foreach (var clip in _clips) { var so = new SerializedObject(clip); so.Update(); @@ -74,7 +79,6 @@ namespace VRM prop.objectReferenceValue = prefabReference; so.ApplyModifiedProperties(); } - return prefabPath; } From 3ed0f1741064287fbcade842b617a556a7221b55 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Tue, 5 Dec 2023 18:29:32 +0900 Subject: [PATCH 22/25] VrmBlendShapeUpdater --- .vscode/settings.json | 1 + .../VRMMeshIntegratorUtility.cs | 93 ----------- .../VrmBlendShapeUpdater.cs | 148 ++++++++++++++++++ ...y.cs.meta => VrmBlendShapeUpdater.cs.meta} | 2 +- .../VrmMeshIntegratorWizard.cs | 2 +- 5 files changed, 151 insertions(+), 95 deletions(-) delete mode 100644 Assets/VRM/Editor/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs create mode 100644 Assets/VRM/Editor/SkinnedMeshUtility/VrmBlendShapeUpdater.cs rename Assets/VRM/Editor/SkinnedMeshUtility/{VRMMeshIntegratorUtility.cs.meta => VrmBlendShapeUpdater.cs.meta} (83%) diff --git a/.vscode/settings.json b/.vscode/settings.json index b0ac5b0e0..1b47395b2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -54,6 +54,7 @@ }, "cSpell.words": [ "GLTF", + "Scriptable", "UNIVRM" ] } \ No newline at end of file diff --git a/Assets/VRM/Editor/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs b/Assets/VRM/Editor/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs deleted file mode 100644 index 4fe5542b6..000000000 --- a/Assets/VRM/Editor/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Text; -using UniGLTF; -using UniGLTF.MeshUtility; -using UnityEditor; -using UnityEngine; - -namespace VRM -{ - /// - /// Meshを統合し、統合後のMeshのBlendShapeの変化をVRMのBlendShapeClipに反映する - /// - public static class VRMMeshIntegratorUtility - { - public static List FollowBlendshapeRendererChange(List results, GameObject root, string assetFolder) - { - var clips = new List(); - var proxy = root.GetComponent(); - if (proxy == null || proxy.BlendShapeAvatar == null) - { - return clips; - } - var result = results.FirstOrDefault(x => x.Integrated?.Mesh.blendShapeCount > 0); - if (result == null) - { - return clips; - } - - var rendererDict = new Dictionary(); - foreach (var x in result.SourceSkinnedMeshRenderers) - { - rendererDict.Add(x.transform.RelativePathFrom(root.transform), x); - } - var dstPath = result.Integrated.IntegratedRenderer.transform.RelativePathFrom(root.transform); - - // copy modify and write - var clipAssetPathList = new List(); - var sb = new StringBuilder(); - foreach (var src in proxy.BlendShapeAvatar.Clips) - { - if (src == null) continue; - - // copy - var copy = ScriptableObject.CreateInstance(); - copy.CopyFrom(src); - copy.Prefab = null; - - // modify - for (var i = 0; i < copy.Values.Length; ++i) - { - var val = copy.Values[i]; - if (rendererDict.ContainsKey(val.RelativePath)) - { - var srcRenderer = rendererDict[val.RelativePath]; - var name = srcRenderer.sharedMesh.GetBlendShapeName(val.Index); - var newIndex = result.Integrated.IntegratedRenderer.sharedMesh.GetBlendShapeIndex(name); - if (newIndex == -1) - { - throw new KeyNotFoundException($"blendshape:{name} not found"); - } - - val.RelativePath = dstPath; - val.Index = newIndex; - } - copy.Values[i] = val; - } - - // write - var assetPath = $"{assetFolder}/{copy.name}.asset"; - sb.AppendLine($"write: {assetPath}"); - AssetDatabase.CreateAsset(copy, assetPath); - - clipAssetPathList.Add(assetPath); - clips.Add(copy); - } - Debug.Log(sb.ToString()); - - { - // create blendshape avatar & replace - var copy = ScriptableObject.CreateInstance(); - copy.Clips.AddRange(clips); - var assetPath = $"{assetFolder}/blendshape.asset"; - AssetDatabase.CreateAsset(copy, assetPath); - - // assign - proxy.BlendShapeAvatar = copy; - } - - return clips; - } - } -} \ No newline at end of file diff --git a/Assets/VRM/Editor/SkinnedMeshUtility/VrmBlendShapeUpdater.cs b/Assets/VRM/Editor/SkinnedMeshUtility/VrmBlendShapeUpdater.cs new file mode 100644 index 000000000..c550a0c9b --- /dev/null +++ b/Assets/VRM/Editor/SkinnedMeshUtility/VrmBlendShapeUpdater.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UniGLTF; +using UniGLTF.MeshUtility; +using UnityEditor; +using UnityEngine; + + +namespace VRM +{ + /// + /// Meshを統合し、統合後のMeshのBlendShapeの変化をVRMのBlendShapeClipに反映する + /// + public class VrmBlendShapeUpdater + { + // BlendShapeBinding.RelativePath からの逆引き + Dictionary> _rendererPathMap = new(); + GameObject _root; + + VrmBlendShapeUpdater(GameObject root, List results) + { + _root = root; + foreach (var result in results) + { + foreach (var x in result.SourceSkinnedMeshRenderers) + { + var srcPath = x.transform.RelativePathFrom(root.transform); + if (_rendererPathMap.TryGetValue(srcPath, out var value)) + { + value.Add(result); + } + else + { + value = new List(); + value.Add(result); + _rendererPathMap.Add(srcPath, value); + } + } + } + } + + // 分割されて増える => 増えない BlendShape のある方にいく + // 統合されて減る => 名前が同じものが統合される + private IEnumerable ReplaceBlendShapeBinding(IEnumerable values) + { + var used = new HashSet(); + foreach (var val in values) + { + if (_rendererPathMap.TryGetValue(val.RelativePath, out var results)) + { + foreach (var result in results) + { + if (result.Integrated == null) + { + continue; + } + var name = result.Integrated.Mesh.GetBlendShapeName(val.Index); + var newIndex = result.Integrated.Mesh.GetBlendShapeIndex(name); + if (newIndex == -1) + { + throw new KeyNotFoundException($"blendshape:{name} not found"); + } + + var dstPath = result.Integrated.IntegratedRenderer.transform.RelativePathFrom(_root.transform); + var binding = new BlendShapeBinding + { + RelativePath = dstPath, + Index = newIndex, + Weight = val.Weight, + }; + if (used.Contains(binding)) + { + Debug.LogWarning($"duplicated: {binding}"); + } + else + { +#if VRM_DEVELOP + Debug.Log($"{val} >> {binding}"); +#endif + used.Add(binding); + yield return binding; + } + } + } + else + { + // skip + Debug.LogWarning($"SkinnedMeshRenderer not found: {val.RelativePath}"); + } + } + } + + public static List FollowBlendshapeRendererChange(GameObject root, + List results, + string assetFolder) + { + var clips = new List(); + var proxy = root.GetComponent(); + if (proxy == null || proxy.BlendShapeAvatar == null) + { + return clips; + } + + var util = new VrmBlendShapeUpdater(root, results); + + // create modified BlendShapeClip + var clipAssetPathList = new List(); + foreach (var src in proxy.BlendShapeAvatar.Clips.Where(x => x != null)) + { + var copy = util.RecreateBlendShapeClip(src, assetFolder); + var assetPath = $"{assetFolder}/{copy.name}.asset"; + AssetDatabase.CreateAsset(copy, assetPath); + clipAssetPathList.Add(assetPath); + clips.Add(copy); + } + + // create BlendShapeAvatar + proxy.BlendShapeAvatar = RecreateBlendShapeAvatar(clips, assetFolder); + + return clips; + } + + BlendShapeClip RecreateBlendShapeClip(BlendShapeClip src, string assetFolder) + { + if (src == null) + { + throw new ArgumentNullException(); + } + + // copy + var copy = ScriptableObject.CreateInstance(); + copy.CopyFrom(src); + copy.Prefab = null; + copy.Values = ReplaceBlendShapeBinding(copy.Values).ToArray(); + return copy; + } + + static BlendShapeAvatar RecreateBlendShapeAvatar(IReadOnlyCollection clips, string assetFolder) + { + var copy = ScriptableObject.CreateInstance(); + copy.Clips.AddRange(clips); + var assetPath = $"{assetFolder}/blendshape.asset"; + AssetDatabase.CreateAsset(copy, assetPath); + return copy; + } + } +} \ No newline at end of file diff --git a/Assets/VRM/Editor/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs.meta b/Assets/VRM/Editor/SkinnedMeshUtility/VrmBlendShapeUpdater.cs.meta similarity index 83% rename from Assets/VRM/Editor/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs.meta rename to Assets/VRM/Editor/SkinnedMeshUtility/VrmBlendShapeUpdater.cs.meta index 84182f709..697660578 100644 --- a/Assets/VRM/Editor/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs.meta +++ b/Assets/VRM/Editor/SkinnedMeshUtility/VrmBlendShapeUpdater.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: fb47e24fc1463584fa0b6b685d75f25e +guid: 488693244cf1ec548a9eb4d81164706f MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs b/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs index a059ac207..41e1c0fbe 100644 --- a/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs +++ b/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs @@ -54,7 +54,7 @@ namespace VRM protected override void WriteAssets(string assetFolder, GameObject target, List results) { // 統合した結果を反映した BlendShapeClip を作成して置き換える - _clips = VRMMeshIntegratorUtility.FollowBlendshapeRendererChange(results, target, assetFolder); + _clips = VrmBlendShapeUpdater.FollowBlendshapeRendererChange(target, results, assetFolder); // write mesh & prefab base.WriteAssets(assetFolder, target, results); From f31b2f8e694afed83158333d14884338711562a4 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Wed, 6 Dec 2023 18:20:43 +0900 Subject: [PATCH 23/25] implement vrm-1.0 integration --- .../VrmBlendShapeUpdater.cs | 6 +- .../VrmMeshIntegratorWizard.cs | 22 ++-- .../MeshUtility/Vrm10ExpressionUpdater.cs | 119 ++++++++++++++++++ .../Vrm10ExpressionUpdater.cs.meta | 11 ++ .../MeshUtility/Vrm10MeshUtilityDialog.cs | 32 +++++ .../Runtime/MeshUtility/Vrm10MeshUtility.cs | 16 +-- 6 files changed, 188 insertions(+), 18 deletions(-) create mode 100644 Assets/VRM10/Editor/MeshUtility/Vrm10ExpressionUpdater.cs create mode 100644 Assets/VRM10/Editor/MeshUtility/Vrm10ExpressionUpdater.cs.meta diff --git a/Assets/VRM/Editor/SkinnedMeshUtility/VrmBlendShapeUpdater.cs b/Assets/VRM/Editor/SkinnedMeshUtility/VrmBlendShapeUpdater.cs index c550a0c9b..99a7162bc 100644 --- a/Assets/VRM/Editor/SkinnedMeshUtility/VrmBlendShapeUpdater.cs +++ b/Assets/VRM/Editor/SkinnedMeshUtility/VrmBlendShapeUpdater.cs @@ -91,9 +91,9 @@ namespace VRM } } - public static List FollowBlendshapeRendererChange(GameObject root, - List results, - string assetFolder) + public static List FollowBlendshapeRendererChange(string assetFolder, + GameObject root, + List results) { var clips = new List(); var proxy = root.GetComponent(); diff --git a/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs b/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs index 41e1c0fbe..d6fe6949a 100644 --- a/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs +++ b/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs @@ -4,7 +4,6 @@ using UnityEngine; using UniGLTF.M17N; using UniGLTF; using System.Collections.Generic; -using UniGLTF.MeshUtility; namespace VRM @@ -51,34 +50,40 @@ namespace VRM } List _clips; - protected override void WriteAssets(string assetFolder, GameObject target, List results) + protected override void WriteAssets(string assetFolder, + GameObject instance, List results) { // 統合した結果を反映した BlendShapeClip を作成して置き換える - _clips = VrmBlendShapeUpdater.FollowBlendshapeRendererChange(target, results, assetFolder); + _clips = VrmBlendShapeUpdater.FollowBlendshapeRendererChange(assetFolder, instance, results); - // write mesh & prefab - base.WriteAssets(assetFolder, target, results); + // write mesh + base.WriteAssets(assetFolder, instance, results); // reset firstPerson - if (target.GetComponent() is VRMFirstPerson firstPerson) + if (instance.GetComponent() is VRMFirstPerson firstPerson) { + // TODO: firstPerson.Reset(); } } - protected override string WritePrefab(string assetFolder, GameObject instance) + protected override string WritePrefab(string assetFolder, + GameObject instance) { var prefabPath = base.WritePrefab(assetFolder, instance); + + // PostProcess + // update prefab reference of BlendShapeClip var prefabReference = AssetDatabase.LoadAssetAtPath(prefabPath); foreach (var clip in _clips) { var so = new SerializedObject(clip); so.Update(); - // clip.Prefab = copy; var prop = so.FindProperty("m_prefab"); prop.objectReferenceValue = prefabReference; so.ApplyModifiedProperties(); } + return prefabPath; } @@ -86,6 +91,7 @@ namespace VRM { EditorGUILayout.HelpBox(Message.MESH_UTILITY.Msg(), MessageType.Info); } + enum Message { [LangMsg(Languages.ja, @"(VRM-0.x専用) 凍結 > 統合 > 分割 という一連の処理を実行します。 diff --git a/Assets/VRM10/Editor/MeshUtility/Vrm10ExpressionUpdater.cs b/Assets/VRM10/Editor/MeshUtility/Vrm10ExpressionUpdater.cs new file mode 100644 index 000000000..04f86a4ff --- /dev/null +++ b/Assets/VRM10/Editor/MeshUtility/Vrm10ExpressionUpdater.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UniGLTF.MeshUtility; +using UnityEditor; +using UnityEngine; + + +namespace UniVRM10 +{ + public class Vrm10ExpressionUpdater + { + // BlendShapeBinding.RelativePath からの逆引き + Dictionary> _rendererPathMap = new(); + GameObject _root; + + Vrm10ExpressionUpdater(GameObject root, List results) + { + _root = root; + foreach (var result in results) + { + foreach (var x in result.SourceSkinnedMeshRenderers) + { + var srcPath = x.transform.RelativePathFrom(root.transform); + if (_rendererPathMap.TryGetValue(srcPath, out var value)) + { + value.Add(result); + } + else + { + value = new List(); + value.Add(result); + _rendererPathMap.Add(srcPath, value); + } + } + } + } + + // 分割されて増える => 増えない BlendShape のある方にいく + // 統合されて減る => 名前が同じものが統合される + IEnumerable ReplaceBlendShapeBinding(IEnumerable values) + { + var used = new HashSet(); + foreach (var val in values) + { + if (_rendererPathMap.TryGetValue(val.RelativePath, out var results)) + { + foreach (var result in results) + { + if (result.Integrated == null) + { + continue; + } + var name = result.Integrated.Mesh.GetBlendShapeName(val.Index); + var newIndex = result.Integrated.Mesh.GetBlendShapeIndex(name); + if (newIndex == -1) + { + throw new KeyNotFoundException($"blendshape:{name} not found"); + } + + var dstPath = result.Integrated.IntegratedRenderer.transform.RelativePathFrom(_root.transform); + var binding = new MorphTargetBinding + { + RelativePath = dstPath, + Index = newIndex, + Weight = val.Weight, + }; + if (used.Contains(binding)) + { + Debug.LogWarning($"duplicated: {binding}"); + } + else + { +#if VRM_DEVELOP + Debug.Log($"{val} >> {binding}"); +#endif + used.Add(binding); + yield return binding; + } + } + } + else + { + // skip + Debug.LogWarning($"SkinnedMeshRenderer not found: {val.RelativePath}"); + } + } + } + + public static Dictionary Update(string assetFolder, GameObject instance, + List results) + { + var vrm = instance.GetComponent(); + var util = new Vrm10ExpressionUpdater(instance, results); + + // write Vrm10Expressions + var copyMap = new Dictionary(); + foreach (var (preset, clip) in vrm.Vrm.Expression.Clips) + { + var copy = ScriptableObject.Instantiate(clip); + copy.MorphTargetBindings = util.ReplaceBlendShapeBinding(clip.MorphTargetBindings).ToArray(); + var assetPath = $"{assetFolder}/{copy.name}.asset"; + AssetDatabase.CreateAsset(copy, assetPath); + copyMap.Add(clip, copy); + } + + // write Vrm10Object + { + var copy = ScriptableObject.Instantiate(vrm.Vrm); + var assetPath = $"{assetFolder}/{copy.name}.asset"; + copy.Expression.Replace(copyMap); + AssetDatabase.CreateAsset(copy, assetPath); + vrm.Vrm = copy; + } + + return copyMap; + } + } +} \ No newline at end of file diff --git a/Assets/VRM10/Editor/MeshUtility/Vrm10ExpressionUpdater.cs.meta b/Assets/VRM10/Editor/MeshUtility/Vrm10ExpressionUpdater.cs.meta new file mode 100644 index 000000000..4f97c265e --- /dev/null +++ b/Assets/VRM10/Editor/MeshUtility/Vrm10ExpressionUpdater.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d74b29fa7bb59ae4a9f641bf16468848 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM10/Editor/MeshUtility/Vrm10MeshUtilityDialog.cs b/Assets/VRM10/Editor/MeshUtility/Vrm10MeshUtilityDialog.cs index eb4afcbdd..e96caf019 100644 --- a/Assets/VRM10/Editor/MeshUtility/Vrm10MeshUtilityDialog.cs +++ b/Assets/VRM10/Editor/MeshUtility/Vrm10MeshUtilityDialog.cs @@ -2,6 +2,8 @@ using UnityEngine; using UnityEditor; using UniGLTF; using UniGLTF.M17N; +using System.Collections.Generic; +using System.Linq; namespace UniVRM10 @@ -60,6 +62,36 @@ namespace UniVRM10 return firstPerson || mod; } + List _clips; + protected override void WriteAssets(string assetFolder, GameObject instance, + List results) + { + _clips = Vrm10ExpressionUpdater.Update(assetFolder, instance, results).Values.ToList(); + + // write mesh + base.WriteAssets(assetFolder, instance, results); + } + + protected override string WritePrefab(string assetFolder, + GameObject instance) + { + var prefabPath = base.WritePrefab(assetFolder, instance); + + // PostProcess + // update prefab reference of BlendShapeClip + var prefabReference = AssetDatabase.LoadAssetAtPath(prefabPath); + foreach (var clip in _clips) + { + var so = new SerializedObject(clip); + so.Update(); + var prop = so.FindProperty("m_prefab"); + prop.objectReferenceValue = prefabReference; + so.ApplyModifiedProperties(); + } + + return prefabPath; + } + protected override void DialogMessage() { EditorGUILayout.HelpBox(Message.MESH_UTILITY.Msg(), MessageType.Info); diff --git a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs index 7c4330a98..1bae527f2 100644 --- a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs +++ b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs @@ -12,30 +12,32 @@ namespace UniVRM10 bool _generateFirstPerson = false; public override IEnumerable CopyInstantiate(GameObject go, GameObject instance) { - var copy = new List(); + var copy = base.CopyInstantiate(go, instance); _generateFirstPerson = false; if (GenerateMeshForFirstPersonAuto) { - foreach (var g in MeshIntegrationGroups) + foreach (var g in copy) { if (g.Name == "auto") { _generateFirstPerson = true; // 元のメッシュを三人称に変更 - copy.Add(new UniGLTF.MeshUtility.MeshIntegrationGroup + yield return new UniGLTF.MeshUtility.MeshIntegrationGroup { Name = UniGLTF.Extensions.VRMC_vrm.FirstPersonType.thirdPersonOnly.ToString(), Renderers = g.Renderers.ToList(), - }); + }; } - copy.Add(g); + yield return g; } } else { - copy.AddRange(MeshIntegrationGroups); + foreach (var g in copy) + { + yield return g; + } } - return copy; } protected override From 0e1dc414e6110a133cef5639b5bb3769579e55dd Mon Sep 17 00:00:00 2001 From: ousttrue Date: Wed, 6 Dec 2023 18:30:41 +0900 Subject: [PATCH 24/25] remove unused MaterialKey --- .../UniGLTF/Editor/MeshUtility/MaterialKey.cs | 82 ------------------- 1 file changed, 82 deletions(-) delete mode 100644 Assets/UniGLTF/Editor/MeshUtility/MaterialKey.cs diff --git a/Assets/UniGLTF/Editor/MeshUtility/MaterialKey.cs b/Assets/UniGLTF/Editor/MeshUtility/MaterialKey.cs deleted file mode 100644 index f7f2832d3..000000000 --- a/Assets/UniGLTF/Editor/MeshUtility/MaterialKey.cs +++ /dev/null @@ -1,82 +0,0 @@ -// namespace UniGLTF.MeshUtility -// { -// [Serializable] -// struct MaterialKey -// { -// public string Shader; -// public KeyValuePair[] Properties; - -// public override bool Equals(object obj) -// { -// if (!(obj is MaterialKey)) -// { -// return base.Equals(obj); -// } - -// var key = (MaterialKey)obj; - -// return Shader == key.Shader -// && Properties.SequenceEqual(key.Properties) -// ; -// } - -// public override int GetHashCode() -// { -// return base.GetHashCode(); -// } -// } - -// [Serializable] -// struct MaterialList -// { -// public Material[] Materials; - -// public MaterialList(Material[] list) -// { -// Materials = list; -// } -// } - -// static object GetPropertyValue(Shader shader, int i, Material m) -// { -// var propType = ShaderUtil.GetPropertyType(shader, i); -// switch (propType) -// { -// case ShaderUtil.ShaderPropertyType.Color: -// return m.GetColor(ShaderUtil.GetPropertyName(shader, i)); - -// case ShaderUtil.ShaderPropertyType.Range: -// case ShaderUtil.ShaderPropertyType.Float: -// return m.GetFloat(ShaderUtil.GetPropertyName(shader, i)); - -// case ShaderUtil.ShaderPropertyType.Vector: -// return m.GetVector(ShaderUtil.GetPropertyName(shader, i)); - -// case ShaderUtil.ShaderPropertyType.TexEnv: -// return m.GetTexture(ShaderUtil.GetPropertyName(shader, i)); - -// default: -// throw new NotImplementedException(propType.ToString()); -// } -// } - -// static MaterialKey GetMaterialKey(Material m) -// { -// var key = new MaterialKey -// { -// Shader = m.shader.name, -// }; - -// key.Properties = Enumerable.Range(0, ShaderUtil.GetPropertyCount(m.shader)) -// .Select(x => new KeyValuePair( -// ShaderUtil.GetPropertyName(m.shader, x), -// GetPropertyValue(m.shader, x, m)) -// ) -// .OrderBy(x => x.Key) -// .ToArray() -// ; - -// return key; -// } - -// } \ No newline at end of file From 28d55421ca0d69bbde309849de2d891bb87be730 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Wed, 6 Dec 2023 18:53:53 +0900 Subject: [PATCH 25/25] =?UTF-8?q?WriteAndReload=20to=20Reload.=20VRMShader?= =?UTF-8?q?s.Symbols.VRM=5FDEVELOP.=20meta=20=E6=B6=88=E3=81=97=E5=BF=98?= =?UTF-8?q?=E3=82=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/UniGLTF/Editor/MeshUtility/MaterialKey.cs.meta | 11 ----------- .../UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs | 6 ++++-- .../Runtime/MeshUtility/MeshIntegrationResult.cs | 9 ++------- .../Editor/MeshUtility/Vrm10ExpressionUpdater.cs | 7 ++++--- 4 files changed, 10 insertions(+), 23 deletions(-) delete mode 100644 Assets/UniGLTF/Editor/MeshUtility/MaterialKey.cs.meta diff --git a/Assets/UniGLTF/Editor/MeshUtility/MaterialKey.cs.meta b/Assets/UniGLTF/Editor/MeshUtility/MaterialKey.cs.meta deleted file mode 100644 index e6645775a..000000000 --- a/Assets/UniGLTF/Editor/MeshUtility/MaterialKey.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 91c86a6f42c50c9438c124f0dbd048a7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs b/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs index 1c10a6eab..3ef6ff0de 100644 --- a/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs +++ b/Assets/UniGLTF/Editor/MeshUtility/MeshUtilityDialog.cs @@ -249,13 +249,15 @@ namespace UniGLTF.MeshUtility { var childAssetPath = $"{assetFolder}/{result.Integrated.IntegratedRenderer.gameObject.name}{ASSET_SUFFIX}"; Debug.LogFormat("CreateAsset: {0}", childAssetPath); - result.Integrated.WriteAndReload(childAssetPath); + AssetDatabase.CreateAsset(result.Integrated.IntegratedRenderer.sharedMesh, childAssetPath); + result.Integrated.Reload(childAssetPath); } if (result.IntegratedNoBlendShape != null) { var childAssetPath = $"{assetFolder}/{result.IntegratedNoBlendShape.IntegratedRenderer.gameObject.name}{ASSET_SUFFIX}"; Debug.LogFormat("CreateAsset: {0}", childAssetPath); - result.IntegratedNoBlendShape.WriteAndReload(childAssetPath); + AssetDatabase.CreateAsset(result.Integrated.IntegratedRenderer.sharedMesh, childAssetPath); + result.IntegratedNoBlendShape.Reload(childAssetPath); } } diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationResult.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationResult.cs index 20103d21d..a87c8ad31 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationResult.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationResult.cs @@ -2,9 +2,7 @@ using System.Collections.Generic; using System.Linq; using UnityEngine; -#if UNITY_EDITOR -using UnityEditor; -#endif + namespace UniGLTF.MeshUtility { @@ -33,17 +31,14 @@ namespace UniGLTF.MeshUtility IntegratedRenderer = smr; } -#if UNITY_EDITOR - public void WriteAndReload(string assetPath) + public void Reload(string assetPath) { - AssetDatabase.CreateAsset(IntegratedRenderer.sharedMesh, assetPath); var unityPath = UnityPath.FromUnityPath(assetPath); unityPath.ImportAsset(); var mesh = unityPath.LoadAsset(); // replace reloaded IntegratedRenderer.sharedMesh = mesh; } -#endif } public class MeshIntegrationResult diff --git a/Assets/VRM10/Editor/MeshUtility/Vrm10ExpressionUpdater.cs b/Assets/VRM10/Editor/MeshUtility/Vrm10ExpressionUpdater.cs index 04f86a4ff..e4c1c6ff2 100644 --- a/Assets/VRM10/Editor/MeshUtility/Vrm10ExpressionUpdater.cs +++ b/Assets/VRM10/Editor/MeshUtility/Vrm10ExpressionUpdater.cs @@ -71,9 +71,10 @@ namespace UniVRM10 } else { -#if VRM_DEVELOP - Debug.Log($"{val} >> {binding}"); -#endif + if (VRMShaders.Symbols.VRM_DEVELOP) + { + Debug.Log($"{val} >> {binding}"); + } used.Add(binding); yield return binding; }