diff --git a/Assets/UniGLTF/Editor/MeshUtility/MeshIntegrationTab.cs b/Assets/UniGLTF/Editor/MeshUtility/MeshIntegrationTab.cs index 6c9c6ec93..85ceb93a9 100644 --- a/Assets/UniGLTF/Editor/MeshUtility/MeshIntegrationTab.cs +++ b/Assets/UniGLTF/Editor/MeshUtility/MeshIntegrationTab.cs @@ -45,8 +45,18 @@ namespace UniGLTF.MeshUtility }; _groupList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) => { + // Flag / Name var group = _meshUtil.MeshIntegrationGroups[index]; - EditorGUI.TextField(rect, group.Name); + + const float LEFT_WIDTH = 92.0f; + var left = rect; + left.width = LEFT_WIDTH; + var right = rect; + right.width -= LEFT_WIDTH; + right.x += LEFT_WIDTH; + + group.IntegrationType = (MeshIntegrationGroup.MeshIntegrationTypes)EditorGUI.EnumPopup(left, group.IntegrationType); + group.Name = EditorGUI.TextField(right, group.Name); }; _groupList.onSelectCallback = rl => { @@ -63,6 +73,12 @@ namespace UniGLTF.MeshUtility var r = _renderers[index]; EditorGUI.ObjectField(rect, r, typeof(Renderer), true); }; + + // +ボタンが押された時のコールバック + _rendererList.onAddCallback = list => Debug.Log("+ clicked."); + + // -ボタンが押された時のコールバック + _rendererList.onRemoveCallback = list => Debug.Log("- clicked : " + list.index + "."); } public void UpdateMeshIntegrationList(GameObject root) diff --git a/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs b/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs index a5f6891cd..637abf24e 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, bool freezeRotation) + private static MeshAttachInfo CreateMeshInfo(Transform src) { // SkinnedMeshRenderer var smr = src.GetComponent(); @@ -29,7 +29,7 @@ namespace UniGLTF.MeshUtility var mr = src.GetComponent(); if (mr != null) { - var dstMesh = MeshFreezer.NormalizeNoneSkinnedMesh(mr, freezeRotation); + var dstMesh = MeshFreezer.NormalizeNoneSkinnedMesh(mr, true); if (dstMesh != null) { return new MeshAttachInfo @@ -51,10 +51,15 @@ namespace UniGLTF.MeshUtility public static Dictionary NormalizeHierarchyFreezeMesh( GameObject go, bool freezeRotation) { + if (!freezeRotation) + { + throw new NotImplementedException("WIP"); + } + var result = new Dictionary(); foreach (var src in go.transform.Traverse()) { - var info = CreateMeshInfo(src, freezeRotation); + var info = CreateMeshInfo(src); if (info != null) { result.Add(src, info); @@ -63,7 +68,7 @@ namespace UniGLTF.MeshUtility return result; } - public static void Replace(GameObject go, Dictionary newMesh, + public static void Replace(GameObject go, Dictionary meshMap, bool FreezeRotation, bool FreezeScaling) { var boneMap = go.transform.Traverse().ToDictionary(x => x, x => new EuclideanTransform(x.rotation, x.position)); @@ -96,7 +101,7 @@ namespace UniGLTF.MeshUtility // second, replace mesh foreach (var (src, tr) in boneMap) { - if (newMesh.TryGetValue(src, out var info)) + if (meshMap.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 0ce1cad6e..8c1323655 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/GltfMeshUtility.cs @@ -53,7 +53,25 @@ namespace UniGLTF.MeshUtility /// public bool SplitByBlendShape = false; - protected UniGLTF.MeshUtility.MeshIntegrationGroup _GetOrCreateGroup(string name) + static MeshIntegrationGroup.MeshIntegrationTypes TypeFromName(string name) + { + var key = name.ToLower(); + if (key.Contains("first")) + { + return MeshIntegrationGroup.MeshIntegrationTypes.FirstPersonOnly; + } + if (key.Contains("third")) + { + return MeshIntegrationGroup.MeshIntegrationTypes.ThirdPersonOnly; + } + if (key.Contains("auto")) + { + return MeshIntegrationGroup.MeshIntegrationTypes.Auto; + } + return MeshIntegrationGroup.MeshIntegrationTypes.Both; + } + + protected MeshIntegrationGroup _GetOrCreateGroup(string name) { foreach (var g in MeshIntegrationGroups) { @@ -62,13 +80,29 @@ namespace UniGLTF.MeshUtility return g; } } - MeshIntegrationGroups.Add(new UniGLTF.MeshUtility.MeshIntegrationGroup + MeshIntegrationGroups.Add(new MeshIntegrationGroup { Name = name, + IntegrationType = TypeFromName(name), }); return MeshIntegrationGroups.Last(); } + protected bool _HasRenderer(Renderer r) + { + foreach (var g in MeshIntegrationGroups) + { + foreach (var x in g.Renderers) + { + if (x == r) + { + return true; + } + } + } + return false; + } + public virtual void UpdateMeshIntegrationGroups(GameObject root) { MeshIntegrationGroups.Clear(); @@ -88,7 +122,8 @@ namespace UniGLTF.MeshUtility } MeshIntegrationGroups.Add(new MeshIntegrationGroup { - Name = "ALL", + Name = "All", + IntegrationType = MeshIntegrationGroup.MeshIntegrationTypes.Both, Renderers = root.GetComponentsInChildren().ToList(), }); } @@ -140,12 +175,12 @@ namespace UniGLTF.MeshUtility if (FreezeBlendShape || FreezeRotation || FreezeScaling) { // MeshをBakeする - var newMesh = BoneNormalizer.NormalizeHierarchyFreezeMesh(target, FreezeRotation); + var meshMap = BoneNormalizer.NormalizeHierarchyFreezeMesh(target, FreezeRotation); // - ヒエラルキーから回転・拡縮を除去する // - BakeされたMeshで置き換える // - bindPoses を再計算する - BoneNormalizer.Replace(target, newMesh, FreezeRotation, FreezeScaling); + BoneNormalizer.Replace(target, meshMap, FreezeRotation, FreezeScaling); } var newList = new List(); diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshExtensions.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshExtensions.cs index f4a37a4bb..736a63645 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/MeshExtensions.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshExtensions.cs @@ -76,9 +76,19 @@ namespace UniGLTF.MeshUtility return dst; } - public static void ApplyRotationAndScale(this Mesh src, Matrix4x4 m) + public static void ApplyRotationAndScale(this Mesh src, Matrix4x4 m, bool removeTranslation = true) { - m.SetColumn(3, new Vector4(0, 0, 0, 1)); // remove translation + if (removeTranslation) + { + m.SetColumn(3, new Vector4(0, 0, 0, 1)); // remove translation + } + src.ApplyMatrix(m); + } + + public static void ApplyTranslation(this Mesh src, Vector3 p) + { + var m = Matrix4x4.identity; + m.SetColumn(3, new Vector4(p.x, p.y, p.z, 1)); src.ApplyMatrix(m); } diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs index fcd185a04..7cd84a92a 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshFreezer.cs @@ -147,9 +147,10 @@ namespace UniGLTF.MeshUtility if (!hasBoneWeight) { // Before bake, bind no weight bones - //Debug.LogFormat("no weight: {0}", srcMesh.name); srcMesh = srcMesh.Copy(true); + srcMesh.ApplyRotationAndScale(src.transform.localToWorldMatrix, false); + var bw = new BoneWeight { boneIndex0 = 0, @@ -162,8 +163,9 @@ namespace UniGLTF.MeshUtility weight3 = 0.0f, }; srcMesh.boneWeights = Enumerable.Range(0, srcMesh.vertexCount).Select(x => bw).ToArray(); - src.rootBone = src.transform; - src.bones = new[] { src.transform }; + src.bones = new[] { src.rootBone ?? src.transform }; + srcMesh.bindposes = src.bones.Select(x => x.worldToLocalMatrix).ToArray(); + src.sharedMesh = srcMesh; } @@ -174,21 +176,19 @@ namespace UniGLTF.MeshUtility mesh.boneWeights = srcMesh.boneWeights; - //var m = src.localToWorldMatrix; // include scaling - var m = default(Matrix4x4); - m.SetTRS(Vector3.zero, src.transform.rotation, Vector3.one); // rotation only - mesh.ApplyMatrix(m); + { + // apply SkinnedMesh.transform rotation + var m = Matrix4x4.TRS(Vector3.zero, src.transform.rotation, Vector3.one); + mesh.ApplyMatrix(m); + } // // BlendShapes // - CopyBlendShapes(src, srcMesh, mesh, m); - - if (!hasBoneWeight) { - // restore bones - src.bones = new Transform[] { }; - src.sharedMesh = originalSrcMesh; + var m = src.localToWorldMatrix; // include scaling + m.SetColumn(3, new Vector4(0, 0, 0, 1)); // no translation + CopyBlendShapes(src, srcMesh, mesh, m); } return mesh; diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationGroup.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationGroup.cs index bf0b969e4..301e1aa72 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationGroup.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationGroup.cs @@ -6,6 +6,16 @@ namespace UniGLTF.MeshUtility public class MeshIntegrationGroup { public string Name; + + public enum MeshIntegrationTypes + { + Both, + FirstPersonOnly, + ThirdPersonOnly, + Auto, + } + + public MeshIntegrationTypes IntegrationType = default; public List Renderers = new List(); public MeshIntegrationGroup CopyInstantiate(GameObject go, GameObject instance) diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrator.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrator.cs index 1f9c1c89e..5bc4ebdb3 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrator.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrator.cs @@ -337,8 +337,14 @@ namespace UniGLTF.MeshUtility mesh.vertices = Positions.ToArray(); mesh.normals = Normals.ToArray(); mesh.uv = UV.ToArray(); - mesh.tangents = Tangents.ToArray(); - mesh.boneWeights = BoneWeights.ToArray(); + if (Tangents != null && Tangents.Count == Positions.Count) + { + mesh.tangents = Tangents.ToArray(); + } + if (BoneWeights != null && BoneWeights.Count == Positions.Count) + { + mesh.boneWeights = BoneWeights.ToArray(); + } int subMeshCount = 0; foreach (var submesh in SubMeshes) diff --git a/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs b/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs index 21d9bdd4f..e559f453b 100644 --- a/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs +++ b/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using UniHumanoid; using UnityEngine; +using UnityEngine.XR; namespace VRM @@ -26,6 +27,7 @@ namespace VRM yield return new UniGLTF.MeshUtility.MeshIntegrationGroup { Name = FirstPersonFlag.ThirdPersonOnly.ToString(), + IntegrationType = UniGLTF.MeshUtility.MeshIntegrationGroup.MeshIntegrationTypes.ThirdPersonOnly, Renderers = g.Renderers.ToList(), }; } @@ -130,6 +132,7 @@ namespace VRM public override void UpdateMeshIntegrationGroups(GameObject root) { + MeshIntegrationGroups.Clear(); if (root == null) { return; @@ -144,6 +147,13 @@ namespace VRM var g = _GetOrCreateGroup(a.FirstPersonFlag.ToString()); g.Renderers.Add(a.Renderer); } + + var orphan = root.GetComponentsInChildren().Where(x => !_HasRenderer(x)).ToArray(); + if (orphan.Length > 0) + { + var g = _GetOrCreateGroup("both"); + g.Renderers.AddRange(orphan); + } } } } \ No newline at end of file diff --git a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs index 1bae527f2..2fb0a2748 100644 --- a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs +++ b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs @@ -9,6 +9,11 @@ namespace UniVRM10 { public class Vrm10MeshUtility : UniGLTF.MeshUtility.GltfMeshUtility { + public Vrm10MeshUtility() + { + FreezeRotation = true; + } + bool _generateFirstPerson = false; public override IEnumerable CopyInstantiate(GameObject go, GameObject instance) { @@ -25,6 +30,7 @@ namespace UniVRM10 yield return new UniGLTF.MeshUtility.MeshIntegrationGroup { Name = UniGLTF.Extensions.VRMC_vrm.FirstPersonType.thirdPersonOnly.ToString(), + IntegrationType = UniGLTF.MeshUtility.MeshIntegrationGroup.MeshIntegrationTypes.ThirdPersonOnly, Renderers = g.Renderers.ToList(), }; } @@ -113,6 +119,8 @@ namespace UniVRM10 { var animator = target.GetComponent(); var newAvatar = AvatarDescription.RecreateAvatar(animator); + GameObject.DestroyImmediate(animator); + animator = target.AddComponent(); animator.avatar = newAvatar; } @@ -121,6 +129,7 @@ namespace UniVRM10 public override void UpdateMeshIntegrationGroups(GameObject root) { + MeshIntegrationGroups.Clear(); if (root == null) { return; @@ -145,6 +154,13 @@ namespace UniVRM10 var g = _GetOrCreateGroup(a.FirstPersonFlag.ToString()); g.Renderers.Add(a.GetRenderer(root.transform)); } + + var orphan = root.GetComponentsInChildren().Where(x => !_HasRenderer(x)).ToArray(); + if (orphan.Length > 0) + { + var g = _GetOrCreateGroup("both"); + g.Renderers.AddRange(orphan); + } } } } \ No newline at end of file