From 579baefd89d0916d36899d85c69a9deb466f9173 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Tue, 25 Aug 2020 18:13:27 +0900 Subject: [PATCH 01/13] move MesuUtility/MeshUtility.asmdef to MeshUtility/Editor/MeshUtilityEditor.asmdef --- .../{MeshUtility.asmdef => Editor/MeshUtility.Editor.asmdef} | 2 +- .../MeshUtility.Editor.asmdef.meta} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename Assets/MeshUtility/{MeshUtility.asmdef => Editor/MeshUtility.Editor.asmdef} (89%) rename Assets/MeshUtility/{MeshUtility.asmdef.meta => Editor/MeshUtility.Editor.asmdef.meta} (100%) diff --git a/Assets/MeshUtility/MeshUtility.asmdef b/Assets/MeshUtility/Editor/MeshUtility.Editor.asmdef similarity index 89% rename from Assets/MeshUtility/MeshUtility.asmdef rename to Assets/MeshUtility/Editor/MeshUtility.Editor.asmdef index e7afd82d1f..18e72ffa76 100644 --- a/Assets/MeshUtility/MeshUtility.asmdef +++ b/Assets/MeshUtility/Editor/MeshUtility.Editor.asmdef @@ -1,5 +1,5 @@ { - "name": "MeshUtility", + "name": "MeshUtility.Editor", "references": [], "optionalUnityReferences": [], "includePlatforms": [ diff --git a/Assets/MeshUtility/MeshUtility.asmdef.meta b/Assets/MeshUtility/Editor/MeshUtility.Editor.asmdef.meta similarity index 100% rename from Assets/MeshUtility/MeshUtility.asmdef.meta rename to Assets/MeshUtility/Editor/MeshUtility.Editor.asmdef.meta From 51d6bd23dbb63ffb43b95ae245666c8db7c9f59a Mon Sep 17 00:00:00 2001 From: ousttrue Date: Tue, 25 Aug 2020 18:13:53 +0900 Subject: [PATCH 02/13] remove MonoBehaviour --- Assets/MeshUtility/Editor/MeshUtility.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Assets/MeshUtility/Editor/MeshUtility.cs b/Assets/MeshUtility/Editor/MeshUtility.cs index 9a824220a6..3a5fcdad05 100644 --- a/Assets/MeshUtility/Editor/MeshUtility.cs +++ b/Assets/MeshUtility/Editor/MeshUtility.cs @@ -6,7 +6,7 @@ namespace MeshUtility { - public class MeshUtility : MonoBehaviour + public class MeshUtility { private const string ASSET_SUFFIX = ".mesh.asset"; private const string MENU_NAME = "Mesh Utility/Separate Skinned Meshes Contained BlendShape"; @@ -51,7 +51,7 @@ public static void LinkToMeshSeparatorDocs() private static void SeparationProcessing(GameObject go) { - var outputObject = Instantiate(go); + var outputObject = GameObject.Instantiate(go); var skinnedMeshRenderers = outputObject.GetComponentsInChildren(); foreach (var skinnedMeshRenderer in skinnedMeshRenderers) { @@ -127,7 +127,7 @@ private static void SeparatePolyWithBlendShape(SkinnedMeshRenderer skinnedMeshRe // put the mesh without BlendShape in a new SkinnedMeshRenderer var srcGameObject = skinnedMeshRendererInput.gameObject; var srcTransform = skinnedMeshRendererInput.transform.parent; - var targetObjectForMeshWithoutBS = Instantiate(srcGameObject); + var targetObjectForMeshWithoutBS = GameObject.Instantiate(srcGameObject); targetObjectForMeshWithoutBS.name = srcGameObject.name + "_WithoutBlendShape"; targetObjectForMeshWithoutBS.transform.SetParent(srcTransform); var skinnedMeshRendererWithoutBS = targetObjectForMeshWithoutBS.GetComponent(); From c90c98e443dff61d8400c39852ef0cdaf509a093 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Tue, 25 Aug 2020 18:49:50 +0900 Subject: [PATCH 03/13] BindposeGizmo.cs --- Assets/MeshUtility/Runtime.meta | 8 + .../Runtime/BindposeGizmo.cs} | 6 +- .../Runtime/BindposeGizmo.cs.meta} | 0 Assets/MeshUtility/Runtime/MeshUtility.asmdef | 3 + .../Runtime/MeshUtility.asmdef.meta | 7 + Assets/MeshUtility/Runtime/UnityExtensions.cs | 319 ++++++++++++++++++ .../Runtime/UnityExtensions.cs.meta | 11 + .../Extensions/UnityExtensions.cs.meta | 4 +- ProjectSettings/ProjectVersion.txt | 2 +- 9 files changed, 353 insertions(+), 7 deletions(-) create mode 100644 Assets/MeshUtility/Runtime.meta rename Assets/{VRM/UniVRM/Scripts/SkinnedMeshUtility/VRMBindposeGizmo.cs => MeshUtility/Runtime/BindposeGizmo.cs} (98%) rename Assets/{VRM/UniVRM/Scripts/SkinnedMeshUtility/VRMBindposeGizmo.cs.meta => MeshUtility/Runtime/BindposeGizmo.cs.meta} (100%) create mode 100644 Assets/MeshUtility/Runtime/MeshUtility.asmdef create mode 100644 Assets/MeshUtility/Runtime/MeshUtility.asmdef.meta create mode 100644 Assets/MeshUtility/Runtime/UnityExtensions.cs create mode 100644 Assets/MeshUtility/Runtime/UnityExtensions.cs.meta diff --git a/Assets/MeshUtility/Runtime.meta b/Assets/MeshUtility/Runtime.meta new file mode 100644 index 0000000000..3b08e9593f --- /dev/null +++ b/Assets/MeshUtility/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fc6ddf08077eac64fb9e33738e1c314d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/VRMBindposeGizmo.cs b/Assets/MeshUtility/Runtime/BindposeGizmo.cs similarity index 98% rename from Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/VRMBindposeGizmo.cs rename to Assets/MeshUtility/Runtime/BindposeGizmo.cs index e882d73b96..23e233e5e6 100644 --- a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/VRMBindposeGizmo.cs +++ b/Assets/MeshUtility/Runtime/BindposeGizmo.cs @@ -1,16 +1,16 @@ using System.Collections.Generic; using System.Linq; using UnityEngine; -using UniGLTF; +// using UniGLTF; #if UNITY_EDITOR using UnityEditor; #endif -namespace VRM +namespace MeshUtility { [DisallowMultipleComponent] - public class VRMBindposeGizmo : MonoBehaviour + public class BindposeGizmo : MonoBehaviour { [SerializeField] Mesh m_target; diff --git a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/VRMBindposeGizmo.cs.meta b/Assets/MeshUtility/Runtime/BindposeGizmo.cs.meta similarity index 100% rename from Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/VRMBindposeGizmo.cs.meta rename to Assets/MeshUtility/Runtime/BindposeGizmo.cs.meta diff --git a/Assets/MeshUtility/Runtime/MeshUtility.asmdef b/Assets/MeshUtility/Runtime/MeshUtility.asmdef new file mode 100644 index 0000000000..f161fcafe4 --- /dev/null +++ b/Assets/MeshUtility/Runtime/MeshUtility.asmdef @@ -0,0 +1,3 @@ +{ + "name": "MeshUtility" +} diff --git a/Assets/MeshUtility/Runtime/MeshUtility.asmdef.meta b/Assets/MeshUtility/Runtime/MeshUtility.asmdef.meta new file mode 100644 index 0000000000..4085faa92a --- /dev/null +++ b/Assets/MeshUtility/Runtime/MeshUtility.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 71ab1919192903d44971eedbc26b24d1 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/MeshUtility/Runtime/UnityExtensions.cs b/Assets/MeshUtility/Runtime/UnityExtensions.cs new file mode 100644 index 0000000000..a772980d3d --- /dev/null +++ b/Assets/MeshUtility/Runtime/UnityExtensions.cs @@ -0,0 +1,319 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +#if UNITY_EDITOR +using UnityEditor; +#endif + + +namespace MeshUtility +{ + public struct PosRot + { + public Vector3 Position; + public Quaternion Rotation; + + public static PosRot FromGlobalTransform(Transform t) + { + return new PosRot + { + Position = t.position, + Rotation = t.rotation, + }; + } + } + + public class BlendShape + { + public string Name; + + public BlendShape(string name) + { + Name = name; + } + + public List Positions = new List(); + public List Normals = new List(); + public List Tangents = new List(); + } + + public static class UnityExtensions + { + public static Vector4 ReverseZ(this Vector4 v) + { + return new Vector4(v.x, v.y, -v.z, v.w); + } + + public static Vector3 ReverseZ(this Vector3 v) + { + return new Vector3(v.x, v.y, -v.z); + } + + [Obsolete] + public static Vector2 ReverseY(this Vector2 v) + { + return new Vector2(v.x, -v.y); + } + + public static Vector2 ReverseUV(this Vector2 v) + { + return new Vector2(v.x, 1.0f - v.y); + } + + public static Quaternion ReverseZ(this Quaternion q) + { + float angle; + Vector3 axis; + q.ToAngleAxis(out angle, out axis); + return Quaternion.AngleAxis(-angle, ReverseZ(axis)); + } + + public static Matrix4x4 Matrix4x4FromColumns(Vector4 c0, Vector4 c1, Vector4 c2, Vector4 c3) + { +#if UNITY_2017_1_OR_NEWER + return new Matrix4x4(c0, c1, c2, c3); +#else + var m = default(Matrix4x4); + m.SetColumn(0, c0); + m.SetColumn(1, c1); + m.SetColumn(2, c2); + m.SetColumn(3, c3); + return m; +#endif + } + + public static Matrix4x4 Matrix4x4FromRotation(Quaternion q) + { +#if UNITY_2017_1_OR_NEWER + return Matrix4x4.Rotate(q); +#else + var m = default(Matrix4x4); + m.SetTRS(Vector3.zero, q, Vector3.one); + return m; +#endif + } + + public static Matrix4x4 ReverseZ(this Matrix4x4 m) + { + m.SetTRS(m.ExtractPosition().ReverseZ(), m.ExtractRotation().ReverseZ(), m.ExtractScale()); + return m; + } + + public static Matrix4x4 MatrixFromArray(float[] values) + { + var m = new Matrix4x4(); + m.m00 = values[0]; + m.m10 = values[1]; + m.m20 = values[2]; + m.m30 = values[3]; + m.m01 = values[4]; + m.m11 = values[5]; + m.m21 = values[6]; + m.m31 = values[7]; + m.m02 = values[8]; + m.m12 = values[9]; + m.m22 = values[10]; + m.m32 = values[11]; + m.m03 = values[12]; + m.m13 = values[13]; + m.m23 = values[14]; + m.m33 = values[15]; + return m; + } + + // https://forum.unity.com/threads/how-to-assign-matrix4x4-to-transform.121966/ + public static Quaternion ExtractRotation(this Matrix4x4 matrix) + { + Vector3 forward; + forward.x = matrix.m02; + forward.y = matrix.m12; + forward.z = matrix.m22; + + Vector3 upwards; + upwards.x = matrix.m01; + upwards.y = matrix.m11; + upwards.z = matrix.m21; + + return Quaternion.LookRotation(forward, upwards); + } + + public static Vector3 ExtractPosition(this Matrix4x4 matrix) + { + Vector3 position; + position.x = matrix.m03; + position.y = matrix.m13; + position.z = matrix.m23; + return position; + } + + public static Vector3 ExtractScale(this Matrix4x4 matrix) + { + Vector3 scale; + scale.x = new Vector4(matrix.m00, matrix.m10, matrix.m20, matrix.m30).magnitude; + scale.y = new Vector4(matrix.m01, matrix.m11, matrix.m21, matrix.m31).magnitude; + scale.z = new Vector4(matrix.m02, matrix.m12, matrix.m22, matrix.m32).magnitude; + return scale; + } + + public static string RelativePathFrom(this Transform self, Transform root) + { + var path = new List(); + for (var current = self; current != null; current = current.parent) + { + if (current == root) + { + return String.Join("/", path.ToArray()); + } + + path.Insert(0, current.name); + } + + throw new Exception("no RelativePath"); + } + + public static Transform GetChildByName(this Transform self, string childName) + { + foreach (Transform child in self) + { + if (child.name == childName) + { + return child; + } + } + + throw new KeyNotFoundException(); + } + + public static Transform GetFromPath(this Transform self, string path) + { + var current = self; + + var split = path.Split('/'); + + foreach (var childName in split) + { + current = current.GetChildByName(childName); + } + + return current; + } + + public static IEnumerable GetChildren(this Transform self) + { + foreach (Transform child in self) + { + yield return child; + } + } + + public static IEnumerable Traverse(this Transform t) + { + yield return t; + foreach (Transform x in t) + { + foreach (Transform y in x.Traverse()) + { + yield return y; + } + } + } + + [Obsolete("Use FindDescendant(name)")] + public static Transform FindDescenedant(this Transform t, string name) + { + return FindDescendant(t, name); + } + + public static Transform FindDescendant(this Transform t, string name) + { + return t.Traverse().First(x => x.name == name); + } + + public static IEnumerable Ancestors(this Transform t) + { + yield return t; + if (t.parent != null) + { + foreach (Transform x in t.parent.Ancestors()) + { + yield return x; + } + } + } + + public static float[] ToArray(this Quaternion q) + { + return new float[] { q.x, q.y, q.z, q.w }; + } + + public static float[] ToArray(this Vector3 v) + { + return new float[] { v.x, v.y, v.z }; + } + + public static float[] ToArray(this Vector4 v) + { + return new float[] { v.x, v.y, v.z, v.w }; + } + + public static float[] ToArray(this Color c) + { + return new float[] { c.r, c.g, c.b, c.a }; + } + + public static void ReverseZRecursive(this Transform root) + { + var globalMap = root.Traverse().ToDictionary(x => x, x => PosRot.FromGlobalTransform(x)); + + foreach (var x in root.Traverse()) + { + x.position = globalMap[x].Position.ReverseZ(); + x.rotation = globalMap[x].Rotation.ReverseZ(); + } + } + + public static Mesh GetSharedMesh(this Transform t) + { + var meshFilter = t.GetComponent(); + if (meshFilter != null) + { + return meshFilter.sharedMesh; + } + + var skinnedMeshRenderer = t.GetComponent(); + if (skinnedMeshRenderer != null) + { + return skinnedMeshRenderer.sharedMesh; + } + + return null; + } + + public static Material[] GetSharedMaterials(this Transform t) + { + var renderer = t.GetComponent(); + if (renderer != null) + { + return renderer.sharedMaterials; + } + + return new Material[] { }; + } + + public static bool Has(this Transform transform, T t) where T : Component + { + return transform.GetComponent() == t; + } + + public static T GetOrAddComponent(this GameObject go) where T : Component + { + var c = go.GetComponent(); + if (c != null) + { + return c; + } + return go.AddComponent(); + } + } +} diff --git a/Assets/MeshUtility/Runtime/UnityExtensions.cs.meta b/Assets/MeshUtility/Runtime/UnityExtensions.cs.meta new file mode 100644 index 0000000000..07785c58f6 --- /dev/null +++ b/Assets/MeshUtility/Runtime/UnityExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5294813527b3278458026afc820dd63d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM/UniGLTF/Scripts/Extensions/UnityExtensions.cs.meta b/Assets/VRM/UniGLTF/Scripts/Extensions/UnityExtensions.cs.meta index 062aed4659..0421f42464 100644 --- a/Assets/VRM/UniGLTF/Scripts/Extensions/UnityExtensions.cs.meta +++ b/Assets/VRM/UniGLTF/Scripts/Extensions/UnityExtensions.cs.meta @@ -1,7 +1,5 @@ fileFormatVersion: 2 -guid: 5294813527b3278458026afc820dd63d -timeCreated: 1515606586 -licenseType: Free +guid: bbcda9130f35803408b216dbc6be05b7 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/ProjectSettings/ProjectVersion.txt b/ProjectSettings/ProjectVersion.txt index 886d7e558b..44c6f16be5 100644 --- a/ProjectSettings/ProjectVersion.txt +++ b/ProjectSettings/ProjectVersion.txt @@ -1 +1 @@ -m_EditorVersion: 2018.4.23f1 +m_EditorVersion: 2018.4.25f1 From 22eb7749f9827b1f59184c7b606c533b64198103 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Tue, 25 Aug 2020 19:03:06 +0900 Subject: [PATCH 04/13] move BoneMeshEraser to MeshUtility --- .../Editor}/BoneMeshEraserWizard.cs | 8 ++++---- .../Editor}/BoneMeshEraserWizard.cs.meta | 0 .../MeshUtility/Editor/MeshUtility.Editor.asmdef | 4 +++- Assets/MeshUtility/Editor/MeshUtility.cs | 14 +++++++++++++- .../Runtime}/BoneMeshEraser.cs | 15 +-------------- .../Runtime}/BoneMeshEraser.cs.meta | 0 .../VRM/UniVRM/Editor/Format/VRMExporterWizard.cs | 2 +- .../UniVRM/Scripts/FirstPerson/VRMFirstPerson.cs | 4 ++-- .../Scripts/SkinnedMeshUtility/BoneNormalizer.cs | 2 +- Assets/VRM/VRM.asmdef | 9 +++++++-- 10 files changed, 32 insertions(+), 26 deletions(-) rename Assets/{VRM/UniVRM/Editor/SkinnedMeshUtility => MeshUtility/Editor}/BoneMeshEraserWizard.cs (95%) rename Assets/{VRM/UniVRM/Editor/SkinnedMeshUtility => MeshUtility/Editor}/BoneMeshEraserWizard.cs.meta (100%) rename Assets/{VRM/UniVRM/Scripts/SkinnedMeshUtility => MeshUtility/Runtime}/BoneMeshEraser.cs (94%) rename Assets/{VRM/UniVRM/Scripts/SkinnedMeshUtility => MeshUtility/Runtime}/BoneMeshEraser.cs.meta (100%) diff --git a/Assets/VRM/UniVRM/Editor/SkinnedMeshUtility/BoneMeshEraserWizard.cs b/Assets/MeshUtility/Editor/BoneMeshEraserWizard.cs similarity index 95% rename from Assets/VRM/UniVRM/Editor/SkinnedMeshUtility/BoneMeshEraserWizard.cs rename to Assets/MeshUtility/Editor/BoneMeshEraserWizard.cs index 081118cbc7..6df4a7aa97 100644 --- a/Assets/VRM/UniVRM/Editor/SkinnedMeshUtility/BoneMeshEraserWizard.cs +++ b/Assets/MeshUtility/Editor/BoneMeshEraserWizard.cs @@ -6,7 +6,7 @@ using UnityEngine; -namespace VRM +namespace MeshUtility { [CustomPropertyDrawer(typeof(BoneMeshEraser.EraseBone))] public class EraseBoneDrawer : PropertyDrawer @@ -51,7 +51,7 @@ public class BoneMeshEraserWizard : ScriptableWizard [SerializeField] BoneMeshEraser.EraseBone[] m_eraseBones; - [MenuItem(SkinnedMeshUtility.MENU_KEY + "BoneMeshEraser Wizard", priority = SkinnedMeshUtility.MENU_PRIORITY)] + [MenuItem(MeshUtility.MENU_PARENT + "BoneMeshEraser Wizard", priority = MeshUtility.MENU_PRIORITY)] static void CreateWizard() { ScriptableWizard.DisplayWizard("BoneMeshEraser", "Erase triangles by bone", "Erase"); @@ -143,7 +143,7 @@ SkinnedMeshRenderer _Erase(GameObject go) var bones = m_skinnedMesh.bones; var eraseBones = m_eraseBones .Where(x => x.Erase) - .Select(x => bones.IndexOf(x.Bone)) + .Select(x => Array.IndexOf(bones, x.Bone)) .ToArray(); var meshNode = new GameObject("BoneMeshEraser"); @@ -168,7 +168,7 @@ void Erase() // save mesh to Assets var assetPath = string.Format("{0}{1}", go.name, ASSET_SUFFIX); - var prefab = SkinnedMeshUtility.GetPrefab(go); + var prefab = MeshUtility.GetPrefab(go); if (prefab != null) { var prefabPath = AssetDatabase.GetAssetPath(prefab); diff --git a/Assets/VRM/UniVRM/Editor/SkinnedMeshUtility/BoneMeshEraserWizard.cs.meta b/Assets/MeshUtility/Editor/BoneMeshEraserWizard.cs.meta similarity index 100% rename from Assets/VRM/UniVRM/Editor/SkinnedMeshUtility/BoneMeshEraserWizard.cs.meta rename to Assets/MeshUtility/Editor/BoneMeshEraserWizard.cs.meta diff --git a/Assets/MeshUtility/Editor/MeshUtility.Editor.asmdef b/Assets/MeshUtility/Editor/MeshUtility.Editor.asmdef index 18e72ffa76..9854cd8f64 100644 --- a/Assets/MeshUtility/Editor/MeshUtility.Editor.asmdef +++ b/Assets/MeshUtility/Editor/MeshUtility.Editor.asmdef @@ -1,6 +1,8 @@ { "name": "MeshUtility.Editor", - "references": [], + "references": [ + "MeshUtility" + ], "optionalUnityReferences": [], "includePlatforms": [ "Editor" diff --git a/Assets/MeshUtility/Editor/MeshUtility.cs b/Assets/MeshUtility/Editor/MeshUtility.cs index 3a5fcdad05..3fe5356af3 100644 --- a/Assets/MeshUtility/Editor/MeshUtility.cs +++ b/Assets/MeshUtility/Editor/MeshUtility.cs @@ -8,10 +8,22 @@ namespace MeshUtility { public class MeshUtility { + public const string MENU_PARENT = "Mesh Utility/"; + public const int MENU_PRIORITY = 11; + private const string ASSET_SUFFIX = ".mesh.asset"; - private const string MENU_NAME = "Mesh Utility/Separate Skinned Meshes Contained BlendShape"; + private const string MENU_NAME = MENU_PARENT + "Separate Skinned Meshes Contained BlendShape"; private static readonly Vector3 ZERO_MOVEMENT = Vector3.zero; + public static Object GetPrefab(GameObject instance) + { +#if UNITY_2018_2_OR_NEWER + return PrefabUtility.GetCorrespondingObjectFromSource(instance); +#else + return PrefabUtility.GetPrefabParent(go); +#endif + } + private enum BlendShapeLogic { WithBlendShape, diff --git a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/BoneMeshEraser.cs b/Assets/MeshUtility/Runtime/BoneMeshEraser.cs similarity index 94% rename from Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/BoneMeshEraser.cs rename to Assets/MeshUtility/Runtime/BoneMeshEraser.cs index 556c9f6c51..64ee850d04 100644 --- a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/BoneMeshEraser.cs +++ b/Assets/MeshUtility/Runtime/BoneMeshEraser.cs @@ -1,10 +1,9 @@ using System; using System.Collections.Generic; -using System.Linq; using UnityEngine; -namespace VRM +namespace MeshUtility { public static class BoneMeshEraser { @@ -151,18 +150,6 @@ public static Mesh CreateErasedMesh(Mesh src, int[] eraseBoneIndices) return mesh; } - public static int IndexOf(this Transform[] list, Transform target) - { - for (int i = 0; i < list.Length; ++i) - { - if (list[i] == target) - { - return i; - } - } - return -1; - } - public static IEnumerable Ancestor(this Transform t) { yield return t; diff --git a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/BoneMeshEraser.cs.meta b/Assets/MeshUtility/Runtime/BoneMeshEraser.cs.meta similarity index 100% rename from Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/BoneMeshEraser.cs.meta rename to Assets/MeshUtility/Runtime/BoneMeshEraser.cs.meta diff --git a/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizard.cs b/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizard.cs index b498f9463b..9820deb65c 100644 --- a/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizard.cs +++ b/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizard.cs @@ -141,7 +141,7 @@ static Vector3 GetForward(Transform l, Transform r) static bool EnableRenderer(Renderer renderer) { - if (renderer.transform.Ancestor().Any(x => !x.gameObject.activeSelf)) + if (renderer.transform.GetComponentsInParent().Any(x => !x.gameObject.activeSelf)) { // 自分か祖先に !activeSelf がいる return false; diff --git a/Assets/VRM/UniVRM/Scripts/FirstPerson/VRMFirstPerson.cs b/Assets/VRM/UniVRM/Scripts/FirstPerson/VRMFirstPerson.cs index d9d46c89ae..7777830494 100644 --- a/Assets/VRM/UniVRM/Scripts/FirstPerson/VRMFirstPerson.cs +++ b/Assets/VRM/UniVRM/Scripts/FirstPerson/VRMFirstPerson.cs @@ -208,7 +208,7 @@ private static Mesh CreateHeadlessModelForSkinnedMeshRenderer(SkinnedMeshRendere var eraseBones = bones.Select((x, i) => { // 祖先に削除対象が存在するか - bool erase = x.Ancestor().Any(y => y == eraseRoot); + bool erase = x.GetComponentsInParent().Any(y => y == eraseRoot); return new { i, @@ -229,7 +229,7 @@ private static Mesh CreateHeadlessModelForSkinnedMeshRenderer(SkinnedMeshRendere renderer.gameObject.layer = THIRDPERSON_ONLY_LAYER; // 削除対象のボーンに対するウェイトを保持する三角形を除外して、一人称用のモデルを複製する - var headlessMesh = BoneMeshEraser.CreateErasedMesh(renderer.sharedMesh, eraseBones); + var headlessMesh = MeshUtility.BoneMeshEraser.CreateErasedMesh(renderer.sharedMesh, eraseBones); if (headlessMesh.triangles.Length == 0) { // 一人称用のmeshには描画すべき部分が無い(全部削除された) diff --git a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/BoneNormalizer.cs b/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/BoneNormalizer.cs index b4b51ee25e..03097f0ecc 100644 --- a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/BoneNormalizer.cs +++ b/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/BoneNormalizer.cs @@ -233,7 +233,7 @@ Transform[] dstBones if (boneMap.TryGetValue(srcBone, out Transform dstBone)) { // 対応するボーンが存在する - var dstIndex = dstBones.IndexOf(dstBone); + var dstIndex = Array.IndexOf(dstBones, dstBone); if (dstIndex == -1) { // ありえない。バグ diff --git a/Assets/VRM/VRM.asmdef b/Assets/VRM/VRM.asmdef index 661c2b1381..02098b76fb 100644 --- a/Assets/VRM/VRM.asmdef +++ b/Assets/VRM/VRM.asmdef @@ -6,10 +6,15 @@ "UniUnlit", "UniHumanoid", "UniJSON", - "ShaderProperty.Runtime" + "ShaderProperty.Runtime", + "MeshUtility" ], "optionalUnityReferences": [], "includePlatforms": [], "excludePlatforms": [], - "allowUnsafeCode": false + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [] } \ No newline at end of file From 747933666c1324406d0b1f4121c0f6328ded10d0 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Tue, 25 Aug 2020 19:08:47 +0900 Subject: [PATCH 05/13] MeshIntegrator.cs --- .../Runtime}/MeshIntegrator.cs | 2 +- .../Runtime}/MeshIntegrator.cs.meta | 0 .../UniVRM/Scripts/SkinnedMeshUtility/MeshIntegratorUtility.cs | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename Assets/{VRM/UniVRM/Scripts/SkinnedMeshUtility => MeshUtility/Runtime}/MeshIntegrator.cs (99%) rename Assets/{VRM/UniVRM/Scripts/SkinnedMeshUtility => MeshUtility/Runtime}/MeshIntegrator.cs.meta (100%) diff --git a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/MeshIntegrator.cs b/Assets/MeshUtility/Runtime/MeshIntegrator.cs similarity index 99% rename from Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/MeshIntegrator.cs rename to Assets/MeshUtility/Runtime/MeshIntegrator.cs index 8c0dd6f726..34ba70052d 100644 --- a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/MeshIntegrator.cs +++ b/Assets/MeshUtility/Runtime/MeshIntegrator.cs @@ -2,7 +2,7 @@ using System.Linq; using UnityEngine; -namespace VRM +namespace MeshUtility { public class MeshIntegrator { diff --git a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/MeshIntegrator.cs.meta b/Assets/MeshUtility/Runtime/MeshIntegrator.cs.meta similarity index 100% rename from Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/MeshIntegrator.cs.meta rename to Assets/MeshUtility/Runtime/MeshIntegrator.cs.meta diff --git a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/MeshIntegratorUtility.cs b/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/MeshIntegratorUtility.cs index e9ab1dc38d..379d69529b 100644 --- a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/MeshIntegratorUtility.cs +++ b/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/MeshIntegratorUtility.cs @@ -115,7 +115,7 @@ private static MeshIntegrationResult IntegrateInternal(GameObject go, bool onlyB meshNode.transform.SetParent(go.transform, false); // レンダラから情報を集める - var integrator = new MeshIntegrator(); + var integrator = new MeshUtility.MeshIntegrator(); if (onlyBlendShapeRenderers) { From dd29d909b50a8218ed727f3f1255c769b7b142ab Mon Sep 17 00:00:00 2001 From: ousttrue Date: Tue, 25 Aug 2020 19:27:13 +0900 Subject: [PATCH 06/13] only 2018.4 or later --- .../MeshIntegratorUtility.cs | 29 +++++++------------ 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/MeshIntegratorUtility.cs b/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/MeshIntegratorUtility.cs index 379d69529b..6b42d3125f 100644 --- a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/MeshIntegratorUtility.cs +++ b/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/MeshIntegratorUtility.cs @@ -14,7 +14,7 @@ public class MeshIntegrationResult public List SourceMeshRenderers = new List(); public SkinnedMeshRenderer IntegratedRenderer; } - + public static bool IntegrateRuntime(GameObject vrmRootObject) { if (vrmRootObject == null) return false; @@ -46,7 +46,7 @@ public static bool IntegrateRuntime(GameObject vrmRootObject) public static List Integrate(GameObject root, List blendshapeClips) { var result = new List(); - + var withoutBlendShape = IntegrateInternal(root, onlyBlendShapeRenderers: false); if (withoutBlendShape.IntegratedRenderer != null) { @@ -66,7 +66,7 @@ public static List Integrate(GameObject root, 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); @@ -75,7 +75,7 @@ private static void FollowBlendshapeRendererChange(List clips, M foreach (var clip in clips) { if (clip == null) continue; - + for (var i = 0; i < clip.Values.Length; ++i) { var val = clip.Values[i]; @@ -84,7 +84,7 @@ private static void FollowBlendshapeRendererChange(List clips, M 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; } @@ -93,16 +93,11 @@ private static void FollowBlendshapeRendererChange(List clips, M } } } - + private static MeshIntegrationResult IntegrateInternal(GameObject go, bool onlyBlendShapeRenderers) { var result = new MeshIntegrationResult(); - -#if UNITY_2017_3_OR_NEWER -#else - return result; -#endif - + var meshNode = new GameObject(); if (onlyBlendShapeRenderers) { @@ -145,12 +140,8 @@ private static MeshIntegrationResult IntegrateInternal(GameObject go, bool onlyB if (integrator.Positions.Count > ushort.MaxValue) { -#if UNITY_2017_3_OR_NEWER Debug.LogFormat("exceed 65535 vertices: {0}", integrator.Positions.Count); mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; -#else - throw new NotImplementedException(String.Format("exceed 65535 vertices: {0}", integrator.Positions.Count.ToString())); -#endif } mesh.vertices = integrator.Positions.ToArray(); @@ -175,10 +166,10 @@ private static MeshIntegrationResult IntegrateInternal(GameObject go, bool onlyB 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)) @@ -201,7 +192,7 @@ public static IEnumerable EnumerateMeshRenderer(Transform root) { var renderer = x.GetComponent(); var filter = x.GetComponent(); - + if (renderer != null && filter != null && renderer.gameObject.activeInHierarchy && From 6bb0bc2cb58510e4f241eb0e755f152f1563d456 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Tue, 25 Aug 2020 19:37:49 +0900 Subject: [PATCH 07/13] MeshIntegratorUtility --- .../Runtime/MeshIntegratorUtility.cs | 148 ++++++++++++++++++ .../Runtime/MeshIntegratorUtility.cs.meta | 3 + 2 files changed, 151 insertions(+) create mode 100644 Assets/MeshUtility/Runtime/MeshIntegratorUtility.cs create mode 100644 Assets/MeshUtility/Runtime/MeshIntegratorUtility.cs.meta diff --git a/Assets/MeshUtility/Runtime/MeshIntegratorUtility.cs b/Assets/MeshUtility/Runtime/MeshIntegratorUtility.cs new file mode 100644 index 0000000000..cf53efec54 --- /dev/null +++ b/Assets/MeshUtility/Runtime/MeshIntegratorUtility.cs @@ -0,0 +1,148 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +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 作成する + /// + /// + /// BlendShapeを保持するSkinnedMeshRendererのみ/BlendShapeを保持しないSkinnedMeshRenderer + MeshRenderer + /// + public static MeshIntegrationResult Integrate(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/MeshUtility/Runtime/MeshIntegratorUtility.cs.meta b/Assets/MeshUtility/Runtime/MeshIntegratorUtility.cs.meta new file mode 100644 index 0000000000..b9075e71ba --- /dev/null +++ b/Assets/MeshUtility/Runtime/MeshIntegratorUtility.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a982d9d30c0145038245b0214dc2f2e4 +timeCreated: 1560190306 \ No newline at end of file From a3ca5ff56354d45c230c47b144184d0716dbea29 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Tue, 25 Aug 2020 19:52:23 +0900 Subject: [PATCH 08/13] =?UTF-8?q?MeshIntegrator=E3=81=AE=E9=9D=9EVRM?= =?UTF-8?q?=E9=83=A8=E5=88=86=E3=82=92MeshUtility=E3=81=AB=E7=A7=BB?= =?UTF-8?q?=E5=8B=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Runtime/MeshIntegrationResult.cs | 13 + .../Runtime/MeshIntegrationResult.cs.meta | 11 + .../Runtime/MeshIntegratorUtility.cs | 8 - .../MeshIntegratorEditor.cs | 30 +-- .../MeshIntegratorWizard.cs | 4 +- Assets/VRM/UniVRM/Editor/UniVRM.Editor.asmdef | 3 +- .../MeshIntegratorUtility.cs | 222 ------------------ .../MeshIntegratorUtility.cs.meta | 3 - .../VRMMeshIntegratorUtility.cs | 92 ++++++++ .../VRMMeshIntegratorUtility.cs.meta | 11 + 10 files changed, 146 insertions(+), 251 deletions(-) create mode 100644 Assets/MeshUtility/Runtime/MeshIntegrationResult.cs create mode 100644 Assets/MeshUtility/Runtime/MeshIntegrationResult.cs.meta delete mode 100644 Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/MeshIntegratorUtility.cs delete mode 100644 Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/MeshIntegratorUtility.cs.meta create mode 100644 Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs create mode 100644 Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/VRMMeshIntegratorUtility.cs.meta diff --git a/Assets/MeshUtility/Runtime/MeshIntegrationResult.cs b/Assets/MeshUtility/Runtime/MeshIntegrationResult.cs new file mode 100644 index 0000000000..91742fc8b4 --- /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 0000000000..5f32450bcf --- /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 cf53efec54..cfb1742e8e 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 23518027b3..28664bd01c 100644 --- a/Assets/VRM/UniVRM/Editor/SkinnedMeshUtility/MeshIntegratorEditor.cs +++ b/Assets/VRM/UniVRM/Editor/SkinnedMeshUtility/MeshIntegratorEditor.cs @@ -11,7 +11,7 @@ namespace VRM { /// - /// 複数のメッシュをまとめる + /// 複数のメッシュをまとめて、BlendShapeClipに変更を反映する /// [DisallowMultipleComponent] public static class MeshIntegratorEditor @@ -39,12 +39,12 @@ private static void ExportFromMenu() 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 @@ private static void Foo() // 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 @@ private static void Foo() 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 dstAvatar = (BlendShapeAvatar)BackupAsset(srcAvatar, rootPrefab); - var clipMapper = srcAvatar.Clips.ToDictionary(x => x, x => (BlendShapeClip) BackupAsset(x, 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 @@ private static T BackupAsset(T asset, GameObject rootPrefab) where T : UnityE 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 cd93e32372..f931b281ec 100644 --- a/Assets/VRM/UniVRM/Editor/SkinnedMeshUtility/MeshIntegratorWizard.cs +++ b/Assets/VRM/UniVRM/Editor/SkinnedMeshUtility/MeshIntegratorWizard.cs @@ -58,7 +58,7 @@ public MaterialList(Material[] list) MaterialList[] m_duplicateMaterials; [Header("Result")] - public MeshIntegratorUtility.MeshIntegrationResult[] integrationResults; + public MeshUtility.MeshIntegrationResult[] integrationResults; [MenuItem(MENU_KEY)] static void CreateWizard() @@ -124,7 +124,7 @@ void OnValidate() 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 b0fde8cc95..af853f37e0 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 6b42d3125f..0000000000 --- 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 b9075e71ba..0000000000 --- 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 0000000000..1dbbc7ea17 --- /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 0000000000..49f2e8d748 --- /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: From a9d03bdae618ff8e775371d11620551d911b791c Mon Sep 17 00:00:00 2001 From: ousttrue Date: Tue, 25 Aug 2020 20:12:43 +0900 Subject: [PATCH 09/13] BoneNormalizer.cs --- .../Runtime}/BoneNormalizer.cs | 296 +++--------------- .../Runtime}/BoneNormalizer.cs.meta | 0 .../Runtime}/MeshExtensions.cs | 2 +- .../Runtime}/MeshExtensions.cs.meta | 0 .../Tests/VRM.Samples.Editor.Tests.asmdef | 9 +- .../Editor/Tests/VRMImportExportTests.cs | 2 +- .../UniVRM/Editor/Format/VRMEditorExporter.cs | 4 +- .../Format/VRMHumanoidNormalizerMenu.cs | 2 +- Assets/VRM/UniVRM/Editor/Tests/MeshTests.cs | 2 +- .../VRM/UniVRM/Editor/Tests/NormalizeTests.cs | 4 +- .../Editor/Tests/UniVRM.Editor.Tests.asmdef | 3 +- .../SkinnedMeshUtility/VRMBoneNormalizer.cs | 238 ++++++++++++++ .../VRMBoneNormalizer.cs.meta | 11 + 13 files changed, 302 insertions(+), 271 deletions(-) rename Assets/{VRM/UniVRM/Scripts/SkinnedMeshUtility => MeshUtility/Runtime}/BoneNormalizer.cs (66%) rename Assets/{VRM/UniVRM/Scripts/SkinnedMeshUtility => MeshUtility/Runtime}/BoneNormalizer.cs.meta (100%) rename Assets/{VRM/UniVRM/Scripts/SkinnedMeshUtility => MeshUtility/Runtime}/MeshExtensions.cs (99%) rename Assets/{VRM/UniVRM/Scripts/SkinnedMeshUtility => MeshUtility/Runtime}/MeshExtensions.cs.meta (100%) create mode 100644 Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/VRMBoneNormalizer.cs create mode 100644 Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/VRMBoneNormalizer.cs.meta diff --git a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/BoneNormalizer.cs b/Assets/MeshUtility/Runtime/BoneNormalizer.cs similarity index 66% rename from Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/BoneNormalizer.cs rename to Assets/MeshUtility/Runtime/BoneNormalizer.cs index 03097f0ecc..b5f5231cd0 100644 --- a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/BoneNormalizer.cs +++ b/Assets/MeshUtility/Runtime/BoneNormalizer.cs @@ -1,77 +1,19 @@ using System; using System.Collections.Generic; using System.Linq; -using UniHumanoid; using UnityEngine; -namespace VRM +namespace MeshUtility { public static class BoneNormalizer { - /// - /// 回転とスケールを除去したヒエラルキーをコピーする - /// - /// - /// - static void CopyAndBuild(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 position only + public delegate Avatar CreateAvatarFunc(GameObject original, GameObject normalized, Dictionary boneMap); - CopyAndBuild(child, dstChild.transform, boneMap); - } - } - } - - static IEnumerable Traverse(this Transform t) - { - yield return t; - foreach (Transform child in t) - { - foreach (var x in child.Traverse()) - { - yield return x; - } - } - } - - static void EnforceTPose(GameObject go) + static (GameObject, Dictionary) NormalizeHierarchy(GameObject go, CreateAvatarFunc createAvatar) { - var animator = go.GetComponent(); - if (animator == null) - { - throw new ArgumentException("Animator with avatar is required"); - } - - var avatar = animator.avatar; - if (avatar == null) - { - throw new ArgumentException("avatar is required"); - } - - if (!avatar.isValid) - { - throw new ArgumentException("invalid avatar"); - } + var boneMap = new Dictionary(); - if (!avatar.isHuman) - { - throw new ArgumentException("avatar is not human"); - } - - HumanPoseTransfer.SetTPose(avatar, go.transform); - } - - static GameObject NormalizeHierarchy(GameObject go, Dictionary boneMap) - { // // 回転・スケールの無いヒエラルキーをコピーする // @@ -83,46 +25,35 @@ static GameObject NormalizeHierarchy(GameObject go, Dictionary(); + var animator = normalized.AddComponent(); + var avatar = createAvatar(go, normalized, boneMap); + avatar.name = go.name + ".normalized"; + animator.avatar = avatar; + } - var srcHumanBones = Enum.GetValues(typeof(HumanBodyBones)) - .Cast() - .Where(x => x != HumanBodyBones.LastBone) - .Select(x => new { Key = x, Value = src.GetBoneTransform(x) }) - .Where(x => x.Value != null) - ; + return (normalized, boneMap); + } - var map = - srcHumanBones - .Where(x => boneMap.ContainsKey(x.Value)) - .ToDictionary(x => x.Key, x => boneMap[x.Value]) - ; + /// + /// 回転とスケールを除去したヒエラルキーをコピーする。 + /// + /// + /// + static void CopyAndBuild(Transform src, Transform dst, Dictionary boneMap) + { + boneMap[src] = dst; - var animator = normalized.AddComponent(); - var vrmHuman = go.GetComponent(); - var avatarDescription = AvatarDescription.Create(); - if (vrmHuman != null && vrmHuman.Description != null) + foreach (Transform child in src) + { + if (child.gameObject.activeSelf) { - 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; - } - avatarDescription.SetHumanBones(map); - var avatar = avatarDescription.CreateAvatar(normalized.transform); - - avatar.name = go.name + ".normalized"; - animator.avatar = avatar; + var dstChild = new GameObject(child.name); + dstChild.transform.SetParent(dst); + dstChild.transform.position = child.position; // copy position only - var humanPoseTransfer = normalized.AddComponent(); - humanPoseTransfer.Avatar = avatar; + CopyAndBuild(child, dstChild.transform, boneMap); + } } - - return normalized; } class BlendShapeReport @@ -539,45 +470,20 @@ static void NormalizeNoneSkinnedMesh(Transform src, Transform dst) dstRenderer.sharedMaterials = srcRenderer.sharedMaterials; } - public struct NormalizedResult - { - public GameObject Root; - public Dictionary BoneMap; - } - /// - /// モデルの正規化を実行する + /// 回転とスケールを除去したヒエラルキーのコピーを作成する(MeshをBakeする) /// - /// 対象モデルのルート - /// 強制的にT-Pose化するか - /// 正規化済みのモデル - public static GameObject Execute(GameObject go, bool forceTPose, bool clearBlendShapeBeforeNormalize) + /// 対象のヒエラルキーのルート + /// BlendShapeを0クリアするか否か。false の場合 BlendShape の現状を Bake する + /// Avatarを作る関数 + /// + public static (GameObject, Dictionary) Execute(GameObject go, + bool clearBlendShapeBeforeNormalize, CreateAvatarFunc createAvatar) { - Dictionary boneMap = new Dictionary(); - - // - // T-Poseにする - // - if (forceTPose) - { - var hips = go.GetComponent().GetBoneTransform(HumanBodyBones.Hips); - var hipsPosition = hips.position; - var hipsRotation = hips.rotation; - try - { - EnforceTPose(go); - } - finally - { - hips.position = hipsPosition; // restore hipsPosition - hips.rotation = hipsRotation; - } - } - // // 正規化されたヒエラルキーを作る // - var normalized = NormalizeHierarchy(go, boneMap); + var (normalized, boneMap) = NormalizeHierarchy(go, createAvatar); // // 各メッシュから回転・スケールを取り除いてBinding行列を再計算する @@ -595,137 +501,7 @@ public static GameObject Execute(GameObject go, bool forceTPose, bool clearBlend NormalizeNoneSkinnedMesh(src, dst); } - CopyVRMComponents(go, normalized, boneMap); - - // return new NormalizedResult - // { - // Root = normalized, - // BoneMap = boneMap - // }; - return normalized; - } - - /// - /// VRMを構成するコンポーネントをコピーする。 - /// - /// コピー元 - /// コピー先 - /// コピー元とコピー先の対応関係 - static void CopyVRMComponents(GameObject go, GameObject root, - Dictionary map) - { - { - // blendshape - var src = go.GetComponent(); - if (src != null) - { - var dst = root.AddComponent(); - dst.BlendShapeAvatar = src.BlendShapeAvatar; - } - } - - { - var secondary = go.transform.Find("secondary"); - if (secondary == null) - { - secondary = go.transform; - } - - var dstSecondary = root.transform.Find("secondary"); - if (dstSecondary == null) - { - dstSecondary = new GameObject("secondary").transform; - dstSecondary.SetParent(root.transform, false); - } - - // 揺れモノ - foreach (var src in go.transform.GetComponentsInChildren()) - { - var dst = map[src.transform]; - var dstColliderGroup = dst.gameObject.AddComponent(); - dstColliderGroup.Colliders = src.Colliders.Select(y => - { - var offset = dst.worldToLocalMatrix.MultiplyPoint(src.transform.localToWorldMatrix.MultiplyPoint(y.Offset)); - return new VRMSpringBoneColliderGroup.SphereCollider - { - Offset = offset, - Radius = y.Radius - }; - }).ToArray(); - } - - foreach (var src in go.transform.GetComponentsInChildren()) - { - // Copy VRMSpringBone - var dst = dstSecondary.gameObject.AddComponent(); - dst.m_comment = src.m_comment; - dst.m_stiffnessForce = src.m_stiffnessForce; - dst.m_gravityPower = src.m_gravityPower; - dst.m_gravityDir = src.m_gravityDir; - dst.m_dragForce = src.m_dragForce; - if (src.m_center != null) - { - dst.m_center = map[src.m_center]; - } - - dst.RootBones = src.RootBones.Select(x => map[x]).ToList(); - dst.m_hitRadius = src.m_hitRadius; - if (src.ColliderGroups != null) - { - dst.ColliderGroups = src.ColliderGroups - .Select(x => map[x.transform].GetComponent()).ToArray(); - } - } - } - -#pragma warning disable 0618 - { - // meta(obsolete) - var src = go.GetComponent(); - if (src != null) - { - src.CopyTo(root); - } - } -#pragma warning restore 0618 - - { - // meta - var src = go.GetComponent(); - if (src != null) - { - var dst = root.AddComponent(); - dst.Meta = src.Meta; - } - } - - { - // firstPerson - var src = go.GetComponent(); - if (src != null) - { - src.CopyTo(root, map); - } - } - - { - // humanoid - var dst = root.AddComponent(); - var src = go.GetComponent(); - if (src != null) - { - dst.Avatar = src.Avatar; - dst.Description = src.Description; - } - else - { - var animator = go.GetComponent(); - if (animator != null) - { - dst.Avatar = animator.avatar; - } - } - } + return (normalized, boneMap); } } } diff --git a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/BoneNormalizer.cs.meta b/Assets/MeshUtility/Runtime/BoneNormalizer.cs.meta similarity index 100% rename from Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/BoneNormalizer.cs.meta rename to Assets/MeshUtility/Runtime/BoneNormalizer.cs.meta diff --git a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/MeshExtensions.cs b/Assets/MeshUtility/Runtime/MeshExtensions.cs similarity index 99% rename from Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/MeshExtensions.cs rename to Assets/MeshUtility/Runtime/MeshExtensions.cs index d2f07911de..aa458d5241 100644 --- a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/MeshExtensions.cs +++ b/Assets/MeshUtility/Runtime/MeshExtensions.cs @@ -2,7 +2,7 @@ using System.Linq; -namespace VRM +namespace MeshUtility { public static class MeshExtensions { diff --git a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/MeshExtensions.cs.meta b/Assets/MeshUtility/Runtime/MeshExtensions.cs.meta similarity index 100% rename from Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/MeshExtensions.cs.meta rename to Assets/MeshUtility/Runtime/MeshExtensions.cs.meta diff --git a/Assets/VRM.Samples/Editor/Tests/VRM.Samples.Editor.Tests.asmdef b/Assets/VRM.Samples/Editor/Tests/VRM.Samples.Editor.Tests.asmdef index f80e8a0a66..aef7e873af 100644 --- a/Assets/VRM.Samples/Editor/Tests/VRM.Samples.Editor.Tests.asmdef +++ b/Assets/VRM.Samples/Editor/Tests/VRM.Samples.Editor.Tests.asmdef @@ -4,7 +4,8 @@ "VRM", "VRM.Samples", "UniVRM.Editor.Tests", - "UniJSON" + "UniJSON", + "MeshUtility" ], "optionalUnityReferences": [ "TestAssemblies" @@ -13,5 +14,9 @@ "Editor" ], "excludePlatforms": [], - "allowUnsafeCode": false + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [] } \ No newline at end of file diff --git a/Assets/VRM.Samples/Editor/Tests/VRMImportExportTests.cs b/Assets/VRM.Samples/Editor/Tests/VRMImportExportTests.cs index cf25c4252f..6f3ec57215 100644 --- a/Assets/VRM.Samples/Editor/Tests/VRMImportExportTests.cs +++ b/Assets/VRM.Samples/Editor/Tests/VRMImportExportTests.cs @@ -3,7 +3,7 @@ using UniGLTF; using UniJSON; using UnityEngine; - +using MeshUtility; namespace VRM.Samples { diff --git a/Assets/VRM/UniVRM/Editor/Format/VRMEditorExporter.cs b/Assets/VRM/UniVRM/Editor/Format/VRMEditorExporter.cs index c9f88f170c..cf3b144d17 100644 --- a/Assets/VRM/UniVRM/Editor/Format/VRMEditorExporter.cs +++ b/Assets/VRM/UniVRM/Editor/Format/VRMEditorExporter.cs @@ -77,7 +77,7 @@ static void ReplaceMesh(GameObject target, SkinnedMeshRenderer smr, BlendShapeAv .Distinct() .ToArray(); - var copyMesh = mesh.Copy(copyBlendShape: false); + var copyMesh = MeshUtility.MeshExtensions.Copy(mesh, copyBlendShape: false); // 使われている BlendShape だけをコピーする foreach (var i in usedBlendshapeIndexArray) { @@ -182,7 +182,7 @@ static void Export(string path, GameObject exportRoot, VRMExportSettings setting if (settings.PoseFreeze) { // BoneNormalizer.Execute は Copy を作って正規化する。UNDO無用 - target = BoneNormalizer.Execute(target, settings.ForceTPose, false); + target = VRMBoneNormalizer.Execute(target, settings.ForceTPose, false); destroy.Add(target); } diff --git a/Assets/VRM/UniVRM/Editor/Format/VRMHumanoidNormalizerMenu.cs b/Assets/VRM/UniVRM/Editor/Format/VRMHumanoidNormalizerMenu.cs index b02b6ce4ee..6dbb8bc295 100644 --- a/Assets/VRM/UniVRM/Editor/Format/VRMHumanoidNormalizerMenu.cs +++ b/Assets/VRM/UniVRM/Editor/Format/VRMHumanoidNormalizerMenu.cs @@ -49,7 +49,7 @@ private static void ExportFromMenu() var go = Selection.activeObject as GameObject; // BoneNormalizer.Execute はコピーを正規化する。UNDO無用 - Selection.activeGameObject = BoneNormalizer.Execute(go, true, false); + Selection.activeGameObject = VRMBoneNormalizer.Execute(go, true, false); } } } diff --git a/Assets/VRM/UniVRM/Editor/Tests/MeshTests.cs b/Assets/VRM/UniVRM/Editor/Tests/MeshTests.cs index c1e36c22e4..6be712b09c 100644 --- a/Assets/VRM/UniVRM/Editor/Tests/MeshTests.cs +++ b/Assets/VRM/UniVRM/Editor/Tests/MeshTests.cs @@ -55,7 +55,7 @@ public void MeshCopyTest() var src = new Mesh(); src.AddBlendShapeFrame("blendShape", 100.0f, null, null, null); - var dst = src.Copy(true); + var dst = MeshUtility.MeshExtensions.Copy(src, true); MeshEquals(src, dst); } diff --git a/Assets/VRM/UniVRM/Editor/Tests/NormalizeTests.cs b/Assets/VRM/UniVRM/Editor/Tests/NormalizeTests.cs index 51510cfb73..1126b647aa 100644 --- a/Assets/VRM/UniVRM/Editor/Tests/NormalizeTests.cs +++ b/Assets/VRM/UniVRM/Editor/Tests/NormalizeTests.cs @@ -58,7 +58,7 @@ public void MapBoneWeightTest() map.Add(null, new GameObject("null")); // map.Add(new GameObject("c"), null); // ありえないので Exception にしてある var boneWeights = map.CreateBoneWeight(64).ToArray(); - var newBoneWeight = BoneNormalizer.MapBoneWeight(boneWeights, map.Map, + var newBoneWeight = MeshUtility.BoneNormalizer.MapBoneWeight(boneWeights, map.Map, map.SrcBones.ToArray(), map.DstBones.ToArray()); // 正常系 @@ -74,7 +74,7 @@ public void MapBoneWeightTest() map.Add(null, new GameObject("null")); // map.Add(new GameObject("c"), null); // ありえないので Exception にしてある var boneWeights = map.CreateBoneWeight(64).ToArray(); - var newBoneWeight = BoneNormalizer.MapBoneWeight(boneWeights, map.Map, + var newBoneWeight = MeshUtility.BoneNormalizer.MapBoneWeight(boneWeights, map.Map, map.SrcBones.ToArray(), map.DstBones.ToArray()); // 4 つめが 0 になる diff --git a/Assets/VRM/UniVRM/Editor/Tests/UniVRM.Editor.Tests.asmdef b/Assets/VRM/UniVRM/Editor/Tests/UniVRM.Editor.Tests.asmdef index 0aa9a540b2..d10983bcb7 100644 --- a/Assets/VRM/UniVRM/Editor/Tests/UniVRM.Editor.Tests.asmdef +++ b/Assets/VRM/UniVRM/Editor/Tests/UniVRM.Editor.Tests.asmdef @@ -3,7 +3,8 @@ "references": [ "VRM", "UniJSON", - "UniVRM.Editor" + "UniVRM.Editor", + "MeshUtility" ], "optionalUnityReferences": [ "TestAssemblies" diff --git a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/VRMBoneNormalizer.cs b/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/VRMBoneNormalizer.cs new file mode 100644 index 0000000000..cc6b6cdd96 --- /dev/null +++ b/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/VRMBoneNormalizer.cs @@ -0,0 +1,238 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UniHumanoid; +using UnityEngine; + + +namespace VRM +{ + public static class VRMBoneNormalizer + { + static void EnforceTPose(GameObject go) + { + var animator = go.GetComponent(); + if (animator == null) + { + throw new ArgumentException("Animator with avatar is required"); + } + + var avatar = animator.avatar; + if (avatar == null) + { + throw new ArgumentException("avatar is required"); + } + + if (!avatar.isValid) + { + throw new ArgumentException("invalid avatar"); + } + + if (!avatar.isHuman) + { + throw new ArgumentException("avatar is not human"); + } + + HumanPoseTransfer.SetTPose(avatar, go.transform); + } + + /// + /// モデルの正規化を実行する + /// + /// 対象モデルのルート + /// 強制的にT-Pose化するか + /// 正規化済みのモデル + public static GameObject Execute(GameObject go, bool forceTPose, bool clearBlendShapeBeforeNormalize) + { + // + // T-Poseにする + // + if (forceTPose) + { + var hips = go.GetComponent().GetBoneTransform(HumanBodyBones.Hips); + var hipsPosition = hips.position; + var hipsRotation = hips.rotation; + try + { + EnforceTPose(go); + } + finally + { + hips.position = hipsPosition; // restore hipsPosition + hips.rotation = hipsRotation; + } + } + + // + // 正規化されたヒエラルキーを作る + // + var (normalized, bMap) = MeshUtility.BoneNormalizer.Execute(go, clearBlendShapeBeforeNormalize, (_src, dst, boneMap) => + { + var src = _src.GetComponent(); + + var srcHumanBones = Enum.GetValues(typeof(HumanBodyBones)) + .Cast() + .Where(x => x != HumanBodyBones.LastBone) + .Select(x => new { Key = x, Value = src.GetBoneTransform(x) }) + .Where(x => x.Value != null) + ; + + var map = + srcHumanBones + .Where(x => boneMap.ContainsKey(x.Value)) + .ToDictionary(x => x.Key, x => boneMap[x.Value]) + ; + + var animator = dst.AddComponent(); + var vrmHuman = go.GetComponent(); + var avatarDescription = AvatarDescription.Create(); + 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; + } + avatarDescription.SetHumanBones(map); + var avatar = avatarDescription.CreateAvatar(dst.transform); + return avatar; + }); + + // humanPoseTransfer + // var animator = normalized.GetComponent(); + // var humanPoseTransfer = normalized.AddComponent(); + // humanPoseTransfer.Avatar = animator.avatar; + + CopyVRMComponents(go, normalized, bMap); + + return normalized; + } + + /// + /// VRMを構成するコンポーネントをコピーする。 + /// + /// コピー元 + /// コピー先 + /// コピー元とコピー先の対応関係 + static void CopyVRMComponents(GameObject go, GameObject root, + Dictionary map) + { + { + // blendshape + var src = go.GetComponent(); + if (src != null) + { + var dst = root.AddComponent(); + dst.BlendShapeAvatar = src.BlendShapeAvatar; + } + } + + { + var secondary = go.transform.Find("secondary"); + if (secondary == null) + { + secondary = go.transform; + } + + var dstSecondary = root.transform.Find("secondary"); + if (dstSecondary == null) + { + dstSecondary = new GameObject("secondary").transform; + dstSecondary.SetParent(root.transform, false); + } + + // 揺れモノ + foreach (var src in go.transform.GetComponentsInChildren()) + { + var dst = map[src.transform]; + var dstColliderGroup = dst.gameObject.AddComponent(); + dstColliderGroup.Colliders = src.Colliders.Select(y => + { + var offset = dst.worldToLocalMatrix.MultiplyPoint(src.transform.localToWorldMatrix.MultiplyPoint(y.Offset)); + return new VRMSpringBoneColliderGroup.SphereCollider + { + Offset = offset, + Radius = y.Radius + }; + }).ToArray(); + } + + foreach (var src in go.transform.GetComponentsInChildren()) + { + // Copy VRMSpringBone + var dst = dstSecondary.gameObject.AddComponent(); + dst.m_comment = src.m_comment; + dst.m_stiffnessForce = src.m_stiffnessForce; + dst.m_gravityPower = src.m_gravityPower; + dst.m_gravityDir = src.m_gravityDir; + dst.m_dragForce = src.m_dragForce; + if (src.m_center != null) + { + dst.m_center = map[src.m_center]; + } + + dst.RootBones = src.RootBones.Select(x => map[x]).ToList(); + dst.m_hitRadius = src.m_hitRadius; + if (src.ColliderGroups != null) + { + dst.ColliderGroups = src.ColliderGroups + .Select(x => map[x.transform].GetComponent()).ToArray(); + } + } + } + +#pragma warning disable 0618 + { + // meta(obsolete) + var src = go.GetComponent(); + if (src != null) + { + src.CopyTo(root); + } + } +#pragma warning restore 0618 + + { + // meta + var src = go.GetComponent(); + if (src != null) + { + var dst = root.AddComponent(); + dst.Meta = src.Meta; + } + } + + { + // firstPerson + var src = go.GetComponent(); + if (src != null) + { + src.CopyTo(root, map); + } + } + + { + // humanoid + var dst = root.AddComponent(); + var src = go.GetComponent(); + if (src != null) + { + dst.Avatar = src.Avatar; + dst.Description = src.Description; + } + else + { + var animator = go.GetComponent(); + if (animator != null) + { + dst.Avatar = animator.avatar; + } + } + } + } + } +} diff --git a/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/VRMBoneNormalizer.cs.meta b/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/VRMBoneNormalizer.cs.meta new file mode 100644 index 0000000000..64a247ec44 --- /dev/null +++ b/Assets/VRM/UniVRM/Scripts/SkinnedMeshUtility/VRMBoneNormalizer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7c0aa7232aa52244aa546dcabf17fadd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 7b9d604810fa0b16f85befff5d282985b975ad62 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Tue, 25 Aug 2020 20:54:53 +0900 Subject: [PATCH 10/13] README.md --- Assets/MeshUtility/README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Assets/MeshUtility/README.md b/Assets/MeshUtility/README.md index fa403cc9b3..dadbfcd4a6 100644 --- a/Assets/MeshUtility/README.md +++ b/Assets/MeshUtility/README.md @@ -2,7 +2,9 @@ Mesh processing tool in Unity platform. -## MeshSeparator +## Utilities + +### MeshSeparator Separate the target mesh into different categories based on given conditions. @@ -10,6 +12,15 @@ Currently support BlendShape mesh separation. See [documentation](Documentation/ +### MeshIntegrator + +Integrate all mesh in hierarchy. + +### MeshNormalizer + +Bake hierarchy. This is VRM normalize backend. +MeshNormalizer can do blendShape bake. + ## Import MeshUtility There are two ways to import MeshUtility into a Unity project. From 09a46eb2d76fc405d55c99397b2ddecd524e5289 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Tue, 25 Aug 2020 20:57:52 +0900 Subject: [PATCH 11/13] UPM package --- Assets/MeshUtility/package.json | 2 +- Assets/VRM/package.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Assets/MeshUtility/package.json b/Assets/MeshUtility/package.json index f7ed33c4ea..0fe3b9b868 100644 --- a/Assets/MeshUtility/package.json +++ b/Assets/MeshUtility/package.json @@ -1,7 +1,7 @@ { "name" : "com.vrmc.meshutility", "displayName" : "MeshUtility", - "version" : "0.0.1", + "version" : "0.58.1", "unity" : "2018.4", "description" : "MeshUtility is a package for mesh separation, etc. \n\nCheck out the latest information here: ", "keywords" : [ "mesh" ], diff --git a/Assets/VRM/package.json b/Assets/VRM/package.json index 35cc618764..4eebbfcedf 100644 --- a/Assets/VRM/package.json +++ b/Assets/VRM/package.json @@ -14,6 +14,7 @@ "name": "VRM Consortium" }, "dependencies": { - "com.vrmc.vrmshaders": "0.58.1" + "com.vrmc.vrmshaders": "0.58.1", + "com.vrmc.meshutility": "0.58.1" } } From d005a7f5fd4156eb03b33cdea0e21936419a632b Mon Sep 17 00:00:00 2001 From: ousttrue Date: Tue, 25 Aug 2020 21:04:27 +0900 Subject: [PATCH 12/13] Bump version to 0.59.0 --- Assets/MeshUtility/package.json | 21 ++++++++++------ .../UniVRM/Editor/Format/VRMVersionMenu.cs | 25 ++++++++++++++++++- .../VRM/UniVRM/Scripts/Format/VRMVersion.cs | 6 ++--- Assets/VRM/package.json | 6 ++--- Assets/VRMShaders/package.json | 2 +- 5 files changed, 44 insertions(+), 16 deletions(-) diff --git a/Assets/MeshUtility/package.json b/Assets/MeshUtility/package.json index 0fe3b9b868..bd217070ae 100644 --- a/Assets/MeshUtility/package.json +++ b/Assets/MeshUtility/package.json @@ -1,9 +1,14 @@ { - "name" : "com.vrmc.meshutility", - "displayName" : "MeshUtility", - "version" : "0.58.1", - "unity" : "2018.4", - "description" : "MeshUtility is a package for mesh separation, etc. \n\nCheck out the latest information here: ", - "keywords" : [ "mesh" ], - "author" : { "name": "VRM Consortium" } -} \ No newline at end of file +{ + "name": "com.vrmc.meshutility", + "version": "0.59.0", + "displayName": "MeshUtility", + "unity": "2018.4", + "description": "MeshUtility is a package for mesh separation, etc. \n\nCheck out the latest information here: ", + "keywords": [ + "mesh" + ], + "author": { + "name": "VRM Consortium" + } +} diff --git a/Assets/VRM/UniVRM/Editor/Format/VRMVersionMenu.cs b/Assets/VRM/UniVRM/Editor/Format/VRMVersionMenu.cs index b0956d809b..95e3b51cf2 100644 --- a/Assets/VRM/UniVRM/Editor/Format/VRMVersionMenu.cs +++ b/Assets/VRM/UniVRM/Editor/Format/VRMVersionMenu.cs @@ -37,6 +37,24 @@ public static partial class VRMVersion }} }} "; + + const string MeshUtilityPath = "Assets/MeshUtility/package.json"; + const string MeshUtilityTemplate = @"{{ +{{ + ""name"": ""com.vrmc.meshutility"", + ""version"": ""{0}.{1}.{2}"", + ""displayName"": ""MeshUtility"", + ""unity"": ""2018.4"", + ""description"": ""MeshUtility is a package for mesh separation, etc. \n\nCheck out the latest information here: "", + ""keywords"": [ + ""mesh"" + ], + ""author"": {{ + ""name"": ""VRM Consortium"" + }} +}} +"; + const string VRMPackagePath = "Assets/VRM/package.json"; const string VRMPackageTemplate = @"{{ ""name"": ""com.vrmc.univrm"", @@ -54,7 +72,8 @@ public static partial class VRMVersion ""name"": ""VRM Consortium"" }}, ""dependencies"": {{ - ""com.vrmc.vrmshaders"": ""{0}.{1}.{2}"" + ""com.vrmc.vrmshaders"": ""{0}.{1}.{2}"", + ""com.vrmc.meshutility"": ""{0}.{1}.{2}"" }} }} "; @@ -96,6 +115,10 @@ void OnGUI() values[0], values[1], values[2]), utf8); + File.WriteAllText(MeshUtilityPath, string.Format(MeshUtilityTemplate, + values[0], + values[1], + values[2]), utf8); File.WriteAllText(VRMPackagePath, string.Format(VRMPackageTemplate, values[0], values[1], diff --git a/Assets/VRM/UniVRM/Scripts/Format/VRMVersion.cs b/Assets/VRM/UniVRM/Scripts/Format/VRMVersion.cs index 01b2e60f44..77872c4f47 100644 --- a/Assets/VRM/UniVRM/Scripts/Format/VRMVersion.cs +++ b/Assets/VRM/UniVRM/Scripts/Format/VRMVersion.cs @@ -4,8 +4,8 @@ namespace VRM public static partial class VRMVersion { public const int MAJOR = 0; - public const int MINOR = 58; - public const int PATCH = 1; - public const string VERSION = "0.58.1"; + public const int MINOR = 59; + public const int PATCH = 0; + public const string VERSION = "0.59.0"; } } diff --git a/Assets/VRM/package.json b/Assets/VRM/package.json index 4eebbfcedf..67b4e71d2f 100644 --- a/Assets/VRM/package.json +++ b/Assets/VRM/package.json @@ -1,6 +1,6 @@ { "name": "com.vrmc.univrm", - "version": "0.58.1", + "version": "0.59.0", "displayName": "VRM", "description": "VRM importer", "unity": "2018.4", @@ -14,7 +14,7 @@ "name": "VRM Consortium" }, "dependencies": { - "com.vrmc.vrmshaders": "0.58.1", - "com.vrmc.meshutility": "0.58.1" + "com.vrmc.vrmshaders": "0.59.0", + "com.vrmc.meshutility": "0.59.0" } } diff --git a/Assets/VRMShaders/package.json b/Assets/VRMShaders/package.json index d46fc49834..c8a10224e9 100644 --- a/Assets/VRMShaders/package.json +++ b/Assets/VRMShaders/package.json @@ -1,6 +1,6 @@ { "name": "com.vrmc.vrmshaders", - "version": "0.58.1", + "version": "0.59.0", "displayName": "VRM Shaders", "description": "VRM Shaders", "unity": "2018.4", From a7684178b76a1da256f69d3072a9adc803681d46 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Wed, 26 Aug 2020 11:41:16 +0900 Subject: [PATCH 13/13] =?UTF-8?q?unitypackage=20=E3=81=AB=20MeshUtility=20?= =?UTF-8?q?=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UniVRM/DevOnly/Editor/VRMExportUnityPackage.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Assets/VRM/UniVRM/DevOnly/Editor/VRMExportUnityPackage.cs b/Assets/VRM/UniVRM/DevOnly/Editor/VRMExportUnityPackage.cs index 77386bdbdc..c124904cde 100644 --- a/Assets/VRM/UniVRM/DevOnly/Editor/VRMExportUnityPackage.cs +++ b/Assets/VRM/UniVRM/DevOnly/Editor/VRMExportUnityPackage.cs @@ -131,9 +131,18 @@ static IEnumerable GlobFiles(string path) } [MenuItem(VRMVersion.MENU + "/Export unitypackage")] + static void CreateUnityPackageWithoutBuild() + { + var folder = GetProjectRoot(); + if (!Directory.Exists(folder)) + { + Directory.CreateDirectory(folder); + } + CreateUnityPackages(folder); + } + public static void CreateUnityPackageWithBuild() { - //var folder = GetDesktop(); var folder = GetProjectRoot(); if (!Directory.Exists(folder)) { @@ -194,6 +203,7 @@ public static void CreateUnityPackages(string outputDir) List = new []{ new GlobList("Assets/VRM"), new GlobList("Assets/VRMShaders"), + new GlobList("Assets/MeshUtility"), } }, new PackageInfo("UniVRM-samples")