diff --git a/Assets/UniGLTF/Editor/MeshUtility/TabMeshIntegrator.cs b/Assets/UniGLTF/Editor/MeshUtility/TabMeshIntegrator.cs index 847773adb5..923980b263 100644 --- a/Assets/UniGLTF/Editor/MeshUtility/TabMeshIntegrator.cs +++ b/Assets/UniGLTF/Editor/MeshUtility/TabMeshIntegrator.cs @@ -90,7 +90,7 @@ public static bool Execute(GameObject src, bool onlyBlendShapeRenderers) // write mesh asset. foreach (var result in results) { - var mesh = result.IntegratedRenderer.sharedMesh; + var mesh = result.MeshMap.Integrated; var assetPath = GetMeshWritePath(mesh); Debug.LogFormat("CreateAsset: {0}", assetPath); AssetDatabase.CreateAsset(mesh, assetPath); diff --git a/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs b/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs index bde593ee67..40981e773e 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/BoneNormalizer.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using UnityEngine; @@ -144,5 +145,33 @@ public static (GameObject, Dictionary) NormalizeHierarchyF return (normalized, boneMap); } + + public static void WriteBackResult(GameObject go, GameObject normalized, Dictionary boneMap) + { + Func getSrc = dst => + { + foreach (var (k, v) in boneMap) + { + if (v == dst) + { + return k; + } + } + 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) + { + srcR.sharedMesh = dstR.sharedMesh; + srcR.bones = dstR.bones.Select(x => getSrc(x)).ToArray(); + } + } + } } } diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationGroup.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationGroup.cs new file mode 100644 index 0000000000..e71a31c607 --- /dev/null +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationGroup.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace UniGLTF.MeshUtility +{ + public class MeshIntegrationGroup + { + /// + /// FirstPerson flag + /// TODO: enum + /// + public string Name; + public List Renderers = new List(); + } +} \ No newline at end of file diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationGroup.cs.meta b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationGroup.cs.meta new file mode 100644 index 0000000000..b456cf0856 --- /dev/null +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationGroup.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ae366b97d8d020245bbdb5d25df09314 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationResult.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationResult.cs index 50e0d3679e..e5f8652c5a 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationResult.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrationResult.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using UnityEngine; namespace UniGLTF.MeshUtility @@ -8,14 +9,32 @@ public class MeshMap { public List Sources = new List(); public Mesh Integrated; + public Material[] SharedMaterials; + public Transform[] Bones; } public class MeshIntegrationResult { public List SourceSkinnedMeshRenderers = new List(); public List SourceMeshRenderers = new List(); + public MeshMap MeshMap = new MeshMap(); public SkinnedMeshRenderer IntegratedRenderer; - public MeshMap MeshMap = new MeshMap(); + public void AddIntegratedRendererTo(GameObject parent) + { + var go = new GameObject(MeshMap.Integrated.name); + go.transform.SetParent(parent.transform, false); + var smr = go.AddComponent(); + smr.sharedMesh = MeshMap.Integrated; + smr.sharedMaterials = MeshMap.SharedMaterials; + smr.bones = MeshMap.Bones; + + IntegratedRenderer = smr; + } + + public void DestroySourceRenderer() + { + throw new NotImplementedException(); + } } } diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrator.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrator.cs index a2c37dd2e1..8bd4e75148 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrator.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrator.cs @@ -6,9 +6,10 @@ namespace UniGLTF.MeshUtility { public class MeshIntegrator { - 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)"; + private MeshIntegrator() + { + + } struct SubMesh { @@ -81,7 +82,7 @@ static BoneWeight AddBoneIndexOffset(BoneWeight bw, int boneIndexOffset) return bw; } - public void Push(MeshRenderer renderer) + void Push(MeshRenderer renderer) { var meshFilter = renderer.GetComponent(); if (meshFilter == null) @@ -232,7 +233,24 @@ public void Push(SkinnedMeshRenderer renderer) } } - public MeshIntegrationResult Integrate(MeshEnumerateOption onlyBlendShapeRenderers) + public static MeshIntegrationResult Integrate(MeshIntegrationGroup group, bool useBlendShape) + { + var integrator = new MeshUtility.MeshIntegrator(); + foreach (var x in group.Renderers) + { + if (x is SkinnedMeshRenderer smr) + { + integrator.Push(smr); + } + else if (x is MeshRenderer mr) + { + integrator.Push(mr); + } + } + return integrator.Integrate(group.Name, useBlendShape); + } + + public MeshIntegrationResult Integrate(string name, bool useBlendShape) { var mesh = new Mesh(); @@ -253,57 +271,14 @@ public MeshIntegrationResult Integrate(MeshEnumerateOption onlyBlendShapeRendere mesh.SetIndices(SubMeshes[i].Indices.ToArray(), MeshTopology.Triangles, i); } mesh.bindposes = BindPoses.ToArray(); - - // blendshape - switch (onlyBlendShapeRenderers) - { - case MeshEnumerateOption.OnlyWithBlendShape: - { - AddBlendShapesToMesh(mesh); - mesh.name = INTEGRATED_MESH_WITH_BLENDSHAPE_NAME; - break; - } - - case MeshEnumerateOption.All: - { - AddBlendShapesToMesh(mesh); - mesh.name = INTEGRATED_MESH_ALL_NAME; - break; - } - - case MeshEnumerateOption.OnlyWithoutBlendShape: - { - mesh.name = INTEGRATED_MESH_WITHOUT_BLENDSHAPE_NAME; - break; - } - } - - // meshName - var meshNode = new GameObject(); - switch (onlyBlendShapeRenderers) + if (useBlendShape) { - case MeshEnumerateOption.OnlyWithBlendShape: - { - meshNode.name = INTEGRATED_MESH_WITH_BLENDSHAPE_NAME; - break; - } - case MeshEnumerateOption.OnlyWithoutBlendShape: - { - meshNode.name = INTEGRATED_MESH_WITHOUT_BLENDSHAPE_NAME; - break; - } - case MeshEnumerateOption.All: - { - meshNode.name = INTEGRATED_MESH_ALL_NAME; - break; - } + AddBlendShapesToMesh(mesh); } + mesh.name = name; - var integrated = meshNode.AddComponent(); - integrated.sharedMesh = mesh; - integrated.sharedMaterials = SubMeshes.Select(x => x.Material).ToArray(); - integrated.bones = Bones.ToArray(); - Result.IntegratedRenderer = integrated; + Result.MeshMap.SharedMaterials = SubMeshes.Select(x => x.Material).ToArray(); + Result.MeshMap.Bones = Bones.ToArray(); Result.MeshMap.Integrated = mesh; return Result; } diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegratorUtility.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegratorUtility.cs index 7050bcb998..1478c8494d 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegratorUtility.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegratorUtility.cs @@ -1,11 +1,14 @@ using System.Collections.Generic; -using System.IO; 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 作成する /// @@ -22,32 +25,39 @@ public static MeshIntegrationResult Integrate(GameObject go, MeshEnumerateOption { var exclude = new MeshExclude(excludes); - var integrator = new MeshUtility.MeshIntegrator(); + 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; } - integrator.Push(x); + 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; } - integrator.Push(x); + group.Renderers.Add(x); } foreach (var x in EnumerateMeshRenderer(go.transform)) @@ -56,7 +66,7 @@ public static MeshIntegrationResult Integrate(GameObject go, MeshEnumerateOption { continue; } - integrator.Push(x); + group.Renderers.Add(x); } break; @@ -64,13 +74,16 @@ public static MeshIntegrationResult Integrate(GameObject go, MeshEnumerateOption case MeshEnumerateOption.All: { + group.Name = INTEGRATED_MESH_ALL_NAME; + useBlendShape = true; + foreach (var x in EnumerateSkinnedMeshRenderer(go.transform, onlyBlendShapeRenderers)) { if (exclude.IsExcluded(x)) { continue; } - integrator.Push(x); + group.Renderers.Add(x); } foreach (var x in EnumerateMeshRenderer(go.transform)) @@ -79,14 +92,14 @@ public static MeshIntegrationResult Integrate(GameObject go, MeshEnumerateOption { continue; } - integrator.Push(x); + group.Renderers.Add(x); } break; } } - return integrator.Integrate(onlyBlendShapeRenderers); + return MeshIntegrator.Integrate(group, useBlendShape); } public static IEnumerable EnumerateSkinnedMeshRenderer(Transform root, MeshEnumerateOption hasBlendShape) @@ -177,7 +190,7 @@ public static void ReplaceMeshWithResults(GameObject copy, List() + .Where(x => x != HumanBodyBones.LastBone) + .Select(x => new { Key = x, Value = src.GetBoneTransform(x) }) + .Where(x => x.Value != null) + ; + + var map = + srcHumanBones + .ToDictionary(x => x.Key, x => x.Value) + ; + + var avatarDescription = UniHumanoid.AvatarDescription.Create(); + avatarDescription.SetHumanBones(map); + var avatar = avatarDescription.CreateAvatar(src.transform); + avatar.name = "created"; + return avatar; + } } } \ No newline at end of file diff --git a/Assets/VRM/Editor/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs b/Assets/VRM/Editor/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs index af74ab1bd2..480f8b04c1 100644 --- a/Assets/VRM/Editor/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs +++ b/Assets/VRM/Editor/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs @@ -21,7 +21,7 @@ public static List FollowBlendshapeRendererChange(List x.IntegratedRenderer.sharedMesh.blendShapeCount > 0); + var result = results.FirstOrDefault(x => x.MeshMap.Integrated.blendShapeCount > 0); if (result == null) { return clips; diff --git a/Assets/VRM10/Editor/MeshUtility/MeshIntegrationTab.cs b/Assets/VRM10/Editor/MeshUtility/MeshIntegrationTab.cs index 3812e04134..de85038000 100644 --- a/Assets/VRM10/Editor/MeshUtility/MeshIntegrationTab.cs +++ b/Assets/VRM10/Editor/MeshUtility/MeshIntegrationTab.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using UniGLTF.MeshUtility; using UnityEditor; using UnityEditorInternal; using UnityEngine; @@ -38,7 +39,7 @@ public MeshIntegrationTab(EditorWindow editor, Vrm10MeshUtility meshUtility) _meshUti = meshUtility; _splitter = new VerticalSplitter(editor, 50, 50); - _groupList = new ReorderableList(_meshUti.MeshIntegrationGroups, typeof(Vrm10MeshUtility.MeshIntegrationGroup)); + _groupList = new ReorderableList(_meshUti.MeshIntegrationGroups, typeof(MeshIntegrationGroup)); _groupList.drawHeaderCallback = (Rect rect) => { GUI.Label(rect, "Integration group"); diff --git a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs index 9369b1f584..021bdc8a35 100644 --- a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs +++ b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs @@ -48,16 +48,6 @@ public class Vrm10MeshUtility /// public bool FreezeRotation = false; - public class MeshIntegrationGroup - { - /// - /// FirstPerson flag - /// TODO: enum - /// - public string Name; - public List Renderers = new List(); - } - public List MeshIntegrationGroups = new List(); /// @@ -145,23 +135,39 @@ public void Process(GameObject go) // TODO: update: spring // TODO: update: constraint // TODO: update: firstPoint offset + // write back normalized transform to boneMap + BoneNormalizer.WriteBackResult(go, normalized, boneMap); + if (Application.isPlaying) + { + GameObject.Destroy(normalized); + } + else + { + GameObject.DestroyImmediate(normalized); + } - var newAvatar = AvatarDescription.CreateAvatarForCopyHierarchy(go.GetComponent(), normalized, boneMap); - var newAnimator = normalized.GetOrAddComponent(); - newAnimator.avatar = newAvatar; - - // TODO: write back normalized transform to boneMap + var animator = go.GetComponent(); + var newAvatar = AvatarDescription.RecreateAvatar(animator); + animator.avatar = newAvatar; // TODO: integration foreach (var group in MeshIntegrationGroups) { - foreach (var renderer in group.Renderers) - { + var result = MeshIntegrator.Integrate(group, true); + // TODO: firstperson + // TODO: split + if (SplitByBlendShape) + { + // var withBlendShape, withoutBlendShape + } + else + { } - } - // TODO: split + // TODO: remove old renderer + result.AddIntegratedRendererTo(go); + } } } }