diff --git a/Assets/MeshUtility/Runtime/MeshIntegrationResult.cs b/Assets/MeshUtility/Runtime/MeshIntegrationResult.cs new file mode 100644 index 000000000..91742fc8b --- /dev/null +++ b/Assets/MeshUtility/Runtime/MeshIntegrationResult.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace MeshUtility +{ + [System.Serializable] + public class MeshIntegrationResult + { + public List SourceSkinnedMeshRenderers = new List(); + public List SourceMeshRenderers = new List(); + public SkinnedMeshRenderer IntegratedRenderer; + } +} diff --git a/Assets/MeshUtility/Runtime/MeshIntegrationResult.cs.meta b/Assets/MeshUtility/Runtime/MeshIntegrationResult.cs.meta new file mode 100644 index 000000000..5f32450bc --- /dev/null +++ b/Assets/MeshUtility/Runtime/MeshIntegrationResult.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e1c66a21d479b3e4a92eedd622d27f4f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/MeshUtility/Runtime/MeshIntegratorUtility.cs b/Assets/MeshUtility/Runtime/MeshIntegratorUtility.cs index cf53efec5..cfb1742e8 100644 --- a/Assets/MeshUtility/Runtime/MeshIntegratorUtility.cs +++ b/Assets/MeshUtility/Runtime/MeshIntegratorUtility.cs @@ -6,14 +6,6 @@ namespace MeshUtility { public static class MeshIntegratorUtility { - [System.Serializable] - public class MeshIntegrationResult - { - public List SourceSkinnedMeshRenderers = new List(); - public List SourceMeshRenderers = new List(); - public SkinnedMeshRenderer IntegratedRenderer; - } - /// /// go を root としたヒエラルキーから Renderer を集めて、統合された Mesh 作成する /// diff --git a/Assets/VRM/UniVRM/Editor/SkinnedMeshUtility/MeshIntegratorEditor.cs b/Assets/VRM/UniVRM/Editor/SkinnedMeshUtility/MeshIntegratorEditor.cs index 23518027b..28664bd01 100644 --- a/Assets/VRM/UniVRM/Editor/SkinnedMeshUtility/MeshIntegratorEditor.cs +++ b/Assets/VRM/UniVRM/Editor/SkinnedMeshUtility/MeshIntegratorEditor.cs @@ -11,7 +11,7 @@ using Object = UnityEngine.Object; namespace VRM { /// - /// 複数のメッシュをまとめる + /// 複数のメッシュをまとめて、BlendShapeClipに変更を反映する /// [DisallowMultipleComponent] public static class MeshIntegratorEditor @@ -39,12 +39,12 @@ namespace VRM private static void Foo() { var go = Selection.activeObject as GameObject; - + Debug.Log(SkinnedMeshUtility.IsPrefab(go)); } - public static List Integrate(GameObject prefab) + public static List Integrate(GameObject prefab) { Undo.RecordObject(prefab, "Mesh Integration"); var instance = SkinnedMeshUtility.InstantiatePrefab(prefab); @@ -63,18 +63,18 @@ namespace VRM // Backup Exists BackupVrmPrefab(prefab); - + // Execute - var results = MeshIntegratorUtility.Integrate(instance, clips); + var results = VRMMeshIntegratorUtility.Integrate(instance, clips); foreach (var res in results) { if (res.IntegratedRenderer == null) continue; - + SaveMeshAsset(res.IntegratedRenderer.sharedMesh, instance, res.IntegratedRenderer.gameObject.name); Undo.RegisterCreatedObjectUndo(res.IntegratedRenderer.gameObject, "Integrate Renderers"); } - + // destroy source renderers foreach (var res in results) { @@ -90,31 +90,31 @@ namespace VRM renderer.gameObject.SetActive(false); } } - + // Apply to Prefab SkinnedMeshUtility.ApplyChangesToPrefab(instance); Object.DestroyImmediate(instance); - + return results; } private static void BackupVrmPrefab(GameObject rootPrefab) { var proxy = rootPrefab.GetComponent(); - - var srcAvatar = proxy.BlendShapeAvatar; - var dstAvatar = (BlendShapeAvatar) BackupAsset(srcAvatar, rootPrefab); - var clipMapper = srcAvatar.Clips.ToDictionary(x => x, x => (BlendShapeClip) BackupAsset(x, rootPrefab)); + var srcAvatar = proxy.BlendShapeAvatar; + var dstAvatar = (BlendShapeAvatar)BackupAsset(srcAvatar, rootPrefab); + + var clipMapper = srcAvatar.Clips.ToDictionary(x => x, x => (BlendShapeClip)BackupAsset(x, rootPrefab)); dstAvatar.Clips = clipMapper.Values.ToList(); - + var dstPrefab = BackupAsset(rootPrefab, rootPrefab); var dstInstance = SkinnedMeshUtility.InstantiatePrefab(dstPrefab); dstInstance.GetComponent().BlendShapeAvatar = dstAvatar; SkinnedMeshUtility.ApplyChangesToPrefab(dstInstance); Object.DestroyImmediate(dstInstance); } - + private static T BackupAsset(T asset, GameObject rootPrefab) where T : UnityEngine.Object { var srcAssetPath = UnityPath.FromAsset(asset); @@ -124,7 +124,7 @@ namespace VRM var backupPath = UnityPath.FromAsset(rootPrefab).Parent.Child(backupDir); backupPath.EnsureFolder(); var dstAssetPath = backupPath.Child(assetName); - + AssetDatabase.CopyAsset(srcAssetPath.Value, dstAssetPath.Value); return dstAssetPath.LoadAsset(); } diff --git a/Assets/VRM/UniVRM/Editor/SkinnedMeshUtility/MeshIntegratorWizard.cs b/Assets/VRM/UniVRM/Editor/SkinnedMeshUtility/MeshIntegratorWizard.cs index cd93e3237..f931b281e 100644 --- a/Assets/VRM/UniVRM/Editor/SkinnedMeshUtility/MeshIntegratorWizard.cs +++ b/Assets/VRM/UniVRM/Editor/SkinnedMeshUtility/MeshIntegratorWizard.cs @@ -58,7 +58,7 @@ namespace VRM MaterialList[] m_duplicateMaterials; [Header("Result")] - public MeshIntegratorUtility.MeshIntegrationResult[] integrationResults; + public MeshUtility.MeshIntegrationResult[] integrationResults; [MenuItem(MENU_KEY)] static void CreateWizard() @@ -124,7 +124,7 @@ namespace VRM return; } - m_uniqueMaterials = MeshIntegratorUtility.EnumerateSkinnedMeshRenderer(m_root.transform, false) + m_uniqueMaterials = MeshUtility.MeshIntegratorUtility.EnumerateSkinnedMeshRenderer(m_root.transform, false) .SelectMany(x => x.sharedMaterials) .Distinct() .ToArray(); diff --git a/Assets/VRM/UniVRM/Editor/UniVRM.Editor.asmdef b/Assets/VRM/UniVRM/Editor/UniVRM.Editor.asmdef index b0fde8cc9..af853f37e 100644 --- a/Assets/VRM/UniVRM/Editor/UniVRM.Editor.asmdef +++ b/Assets/VRM/UniVRM/Editor/UniVRM.Editor.asmdef @@ -3,7 +3,8 @@ "references": [ "VRM", "UniJSON", - "UniHumanoid" + "UniHumanoid", + "MeshUtility" ], "optionalUnityReferences": [], "includePlatforms": [ diff --git a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/MeshIntegratorUtility.cs b/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/MeshIntegratorUtility.cs deleted file mode 100644 index 6b42d3125..000000000 --- a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/MeshIntegratorUtility.cs +++ /dev/null @@ -1,222 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using UniGLTF; -using UnityEngine; - -namespace VRM -{ - public static class MeshIntegratorUtility - { - [System.Serializable] - public class MeshIntegrationResult - { - public List SourceSkinnedMeshRenderers = new List(); - public List SourceMeshRenderers = new List(); - public SkinnedMeshRenderer IntegratedRenderer; - } - - public static bool IntegrateRuntime(GameObject vrmRootObject) - { - if (vrmRootObject == null) return false; - var proxy = vrmRootObject.GetComponent(); - if (proxy == null) return false; - var avatar = proxy.BlendShapeAvatar; - if (avatar == null) return false; - var clips = avatar.Clips; - - var results = Integrate(vrmRootObject, clips); - if (results.Any(x => x.IntegratedRenderer == null)) return false; - - foreach (var result in results) - { - foreach (var renderer in result.SourceSkinnedMeshRenderers) - { - Object.Destroy(renderer); - } - - foreach (var renderer in result.SourceMeshRenderers) - { - Object.Destroy(renderer); - } - } - - return true; - } - - public static List Integrate(GameObject root, List blendshapeClips) - { - var result = new List(); - - var withoutBlendShape = IntegrateInternal(root, onlyBlendShapeRenderers: false); - if (withoutBlendShape.IntegratedRenderer != null) - { - result.Add(withoutBlendShape); - } - - var onlyBlendShape = IntegrateInternal(root, onlyBlendShapeRenderers: true); - if (onlyBlendShape.IntegratedRenderer != null) - { - result.Add(onlyBlendShape); - FollowBlendshapeRendererChange(blendshapeClips, onlyBlendShape, root); - } - - return result; - } - - private static void FollowBlendshapeRendererChange(List clips, MeshIntegrationResult result, GameObject root) - { - if (clips == null || result == null || result.IntegratedRenderer == null || root == null) return; - - var rendererDict = result.SourceSkinnedMeshRenderers - .ToDictionary(x => x.transform.RelativePathFrom(root.transform), x => x); - - var dstPath = result.IntegratedRenderer.transform.RelativePathFrom(root.transform); - - foreach (var clip in clips) - { - if (clip == null) continue; - - for (var i = 0; i < clip.Values.Length; ++i) - { - var val = clip.Values[i]; - if (rendererDict.ContainsKey(val.RelativePath)) - { - var srcRenderer = rendererDict[val.RelativePath]; - var name = srcRenderer.sharedMesh.GetBlendShapeName(val.Index); - var newIndex = result.IntegratedRenderer.sharedMesh.GetBlendShapeIndex(name); - - val.RelativePath = dstPath; - val.Index = newIndex; - } - - clip.Values[i] = val; - } - } - } - - private static MeshIntegrationResult IntegrateInternal(GameObject go, bool onlyBlendShapeRenderers) - { - var result = new MeshIntegrationResult(); - - var meshNode = new GameObject(); - if (onlyBlendShapeRenderers) - { - meshNode.name = "MeshIntegrator(BlendShape)"; - } - else - { - meshNode.name = "MeshIntegrator"; - } - meshNode.transform.SetParent(go.transform, false); - - // レンダラから情報を集める - var integrator = new MeshUtility.MeshIntegrator(); - - if (onlyBlendShapeRenderers) - { - foreach (var x in EnumerateSkinnedMeshRenderer(go.transform, true)) - { - integrator.Push(x); - result.SourceSkinnedMeshRenderers.Add(x); - } - } - else - { - foreach (var x in EnumerateSkinnedMeshRenderer(go.transform, false)) - { - integrator.Push(x); - result.SourceSkinnedMeshRenderers.Add(x); - } - - foreach (var x in EnumerateMeshRenderer(go.transform)) - { - integrator.Push(x); - result.SourceMeshRenderers.Add(x); - } - } - - var mesh = new Mesh(); - mesh.name = "integrated"; - - if (integrator.Positions.Count > ushort.MaxValue) - { - Debug.LogFormat("exceed 65535 vertices: {0}", integrator.Positions.Count); - mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; - } - - mesh.vertices = integrator.Positions.ToArray(); - mesh.normals = integrator.Normals.ToArray(); - mesh.uv = integrator.UV.ToArray(); - mesh.tangents = integrator.Tangents.ToArray(); - mesh.boneWeights = integrator.BoneWeights.ToArray(); - mesh.subMeshCount = integrator.SubMeshes.Count; - for (var i = 0; i < integrator.SubMeshes.Count; ++i) - { - mesh.SetIndices(integrator.SubMeshes[i].Indices.ToArray(), MeshTopology.Triangles, i); - } - mesh.bindposes = integrator.BindPoses.ToArray(); - - if (onlyBlendShapeRenderers) - { - integrator.AddBlendShapesToMesh(mesh); - } - - var integrated = meshNode.AddComponent(); - integrated.sharedMesh = mesh; - integrated.sharedMaterials = integrator.SubMeshes.Select(x => x.Material).ToArray(); - integrated.bones = integrator.Bones.ToArray(); - result.IntegratedRenderer = integrated; - - return result; - } - - public static IEnumerable EnumerateSkinnedMeshRenderer(Transform root, bool hasBlendShape) - { - foreach (var x in Traverse(root)) - { - var renderer = x.GetComponent(); - if (renderer != null && - renderer.gameObject.activeInHierarchy && - renderer.sharedMesh != null && - renderer.enabled && - renderer.sharedMesh.blendShapeCount > 0 == hasBlendShape) - { - yield return renderer; - } - } - } - - 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; - } - } - } - } - } -} \ No newline at end of file diff --git a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/MeshIntegratorUtility.cs.meta b/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/MeshIntegratorUtility.cs.meta deleted file mode 100644 index b9075e71b..000000000 --- a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/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/UniVRM/Scripts/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs b/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs new file mode 100644 index 000000000..1dbbc7ea1 --- /dev/null +++ b/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs @@ -0,0 +1,92 @@ +using System.Collections.Generic; +using System.Linq; +using UniGLTF; +using UnityEngine; + +namespace VRM +{ + /// + /// Meshを統合し、統合後のMeshのBlendShapeの変化をVRMのBlendShapeClipに反映する + /// + public static class VRMMeshIntegratorUtility + { + public static bool IntegrateRuntime(GameObject vrmRootObject) + { + if (vrmRootObject == null) return false; + var proxy = vrmRootObject.GetComponent(); + if (proxy == null) return false; + var avatar = proxy.BlendShapeAvatar; + if (avatar == null) return false; + var clips = avatar.Clips; + + var results = Integrate(vrmRootObject, clips); + if (results.Any(x => x.IntegratedRenderer == null)) return false; + + foreach (var result in results) + { + foreach (var renderer in result.SourceSkinnedMeshRenderers) + { + Object.Destroy(renderer); + } + + foreach (var renderer in result.SourceMeshRenderers) + { + Object.Destroy(renderer); + } + } + + return true; + } + + public static List Integrate(GameObject root, List blendshapeClips) + { + var result = new List(); + + var withoutBlendShape = MeshUtility.MeshIntegratorUtility.Integrate(root, onlyBlendShapeRenderers: false); + if (withoutBlendShape.IntegratedRenderer != null) + { + result.Add(withoutBlendShape); + } + + var onlyBlendShape = MeshUtility.MeshIntegratorUtility.Integrate(root, onlyBlendShapeRenderers: true); + if (onlyBlendShape.IntegratedRenderer != null) + { + result.Add(onlyBlendShape); + FollowBlendshapeRendererChange(blendshapeClips, onlyBlendShape, root); + } + + return result; + } + + private static void FollowBlendshapeRendererChange(List clips, MeshUtility.MeshIntegrationResult result, GameObject root) + { + if (clips == null || result == null || result.IntegratedRenderer == null || root == null) return; + + var rendererDict = result.SourceSkinnedMeshRenderers + .ToDictionary(x => x.transform.RelativePathFrom(root.transform), x => x); + + var dstPath = result.IntegratedRenderer.transform.RelativePathFrom(root.transform); + + foreach (var clip in clips) + { + if (clip == null) continue; + + for (var i = 0; i < clip.Values.Length; ++i) + { + var val = clip.Values[i]; + if (rendererDict.ContainsKey(val.RelativePath)) + { + var srcRenderer = rendererDict[val.RelativePath]; + var name = srcRenderer.sharedMesh.GetBlendShapeName(val.Index); + var newIndex = result.IntegratedRenderer.sharedMesh.GetBlendShapeIndex(name); + + val.RelativePath = dstPath; + val.Index = newIndex; + } + + clip.Values[i] = val; + } + } + } + } +} \ No newline at end of file diff --git a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs.meta b/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs.meta new file mode 100644 index 000000000..49f2e8d74 --- /dev/null +++ b/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8eebeb093136b7f429c0e9e7295816b3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: