summaryrefslogtreecommitdiff
path: root/Assets/ThirdParty/VRM/MeshUtility/Runtime
diff options
context:
space:
mode:
Diffstat (limited to 'Assets/ThirdParty/VRM/MeshUtility/Runtime')
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/BindposeGizmo.cs158
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/BindposeGizmo.cs.meta13
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneMeshEraser.cs166
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneMeshEraser.cs.meta13
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneNormalizer.cs507
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneNormalizer.cs.meta13
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/Humanoid.cs441
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/Humanoid.cs.meta11
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/HumanoidLoader.cs60
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/HumanoidLoader.cs.meta11
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshExtensions.cs85
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshExtensions.cs.meta12
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrationResult.cs13
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrationResult.cs.meta11
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrator.cs253
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrator.cs.meta3
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegratorUtility.cs140
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegratorUtility.cs.meta3
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshUtility.asmdef3
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshUtility.asmdef.meta7
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityExtensions.cs319
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityExtensions.cs.meta11
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityPath.cs435
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityPath.cs.meta12
24 files changed, 2700 insertions, 0 deletions
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/BindposeGizmo.cs b/Assets/ThirdParty/VRM/MeshUtility/Runtime/BindposeGizmo.cs
new file mode 100644
index 00000000..23e233e5
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/BindposeGizmo.cs
@@ -0,0 +1,158 @@
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+// using UniGLTF;
+#if UNITY_EDITOR
+using UnityEditor;
+#endif
+
+
+namespace MeshUtility
+{
+ [DisallowMultipleComponent]
+ public class BindposeGizmo : MonoBehaviour
+ {
+ [SerializeField]
+ Mesh m_target;
+
+ [SerializeField]
+ float[] m_boneWeights;
+
+ [SerializeField, Range(0.1f, 1.0f)]
+ float m_gizmoSize = 0.02f;
+
+ [SerializeField]
+ Color m_meshGizmoColor = Color.yellow;
+
+ [SerializeField]
+ Color m_bindGizmoColor = Color.red;
+
+ private void Reset()
+ {
+ var renderer = GetComponent<SkinnedMeshRenderer>();
+ if (renderer == null) return;
+ m_target = renderer.sharedMesh;
+ }
+
+#if UNITY_EDITOR
+ #region ToBindpose
+ [ContextMenu("ToBindpose")]
+ void ToBindpose()
+ {
+ var renderer = GetComponent<SkinnedMeshRenderer>();
+
+ var root =
+ renderer.bones
+ .Select(x => Ancestors(x).Reverse().ToArray())
+ .Aggregate((a, b) =>
+ {
+ int i = 0;
+ for (; i < a.Length && i < b.Length; ++i)
+ {
+ if (a[i] != b[i])
+ {
+ break;
+ }
+ }
+ return a.Take(i).ToArray();
+ })
+ .Last()
+ ;
+
+ var map = new Dictionary<Transform, Matrix4x4>();
+ for (int i = 0; i < renderer.bones.Length; ++i)
+ {
+ map[renderer.bones[i]] = m_target.bindposes[i];
+ }
+
+ {
+ var bones = Traverse(root);
+ Undo.RecordObjects(bones.ToArray(), "toBindpose");
+
+ foreach (var x in bones)
+ {
+ var bind = default(Matrix4x4);
+ if (map.TryGetValue(x, out bind))
+ {
+ var toWorld = renderer.transform.localToWorldMatrix * bind.inverse;
+ x.position = toWorld.GetColumn(3);
+ x.rotation = toWorld.ExtractRotation();
+ }
+ }
+
+ //EditorUtility.SetDirty(transform);
+ }
+ }
+
+ IEnumerable<Transform> Traverse(Transform self)
+ {
+ yield return self;
+
+ foreach (Transform child in self)
+ {
+ foreach (var x in Traverse(child))
+ {
+ yield return x;
+ }
+ }
+ }
+
+ IEnumerable<Transform> Ancestors(Transform self)
+ {
+ yield return self;
+
+ if (self.parent != null)
+ {
+ foreach (var x in Ancestors(self.parent))
+ {
+ yield return x;
+ }
+ }
+ }
+ #endregion
+#endif
+
+ private void OnDrawGizmos()
+ {
+ if (m_target == null)
+ {
+ return;
+ }
+
+ Gizmos.matrix = transform.localToWorldMatrix;
+
+ if (m_target.bindposes != null && m_target.bindposes.Length > 0)
+ {
+ if (m_boneWeights == null || m_boneWeights.Length != m_target.bindposes.Length)
+ {
+ m_boneWeights = new float[m_target.bindposes.Length];
+ foreach (var bw in m_target.boneWeights)
+ {
+ if (bw.weight0 > 0) m_boneWeights[bw.boneIndex0] += bw.weight0;
+ if (bw.weight1 > 0) m_boneWeights[bw.boneIndex1] += bw.weight1;
+ if (bw.weight2 > 0) m_boneWeights[bw.boneIndex2] += bw.weight2;
+ if (bw.weight3 > 0) m_boneWeights[bw.boneIndex3] += bw.weight3;
+ }
+ }
+
+ Gizmos.color = m_meshGizmoColor;
+ Gizmos.DrawWireMesh(m_target);
+
+ for (var i = 0; i < m_target.bindposes.Length; ++i)
+ {
+ var color = m_bindGizmoColor * m_boneWeights[i];
+ color.a = 1.0f;
+ Gizmos.color = color;
+
+ Gizmos.matrix = transform.localToWorldMatrix * m_target.bindposes[i].inverse;
+ Gizmos.DrawWireCube(Vector3.zero, Vector3.one * m_gizmoSize);
+ }
+ }
+ else
+ {
+ Gizmos.color = Color.gray;
+ Gizmos.DrawWireMesh(m_target);
+ }
+ }
+ }
+}
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/BindposeGizmo.cs.meta b/Assets/ThirdParty/VRM/MeshUtility/Runtime/BindposeGizmo.cs.meta
new file mode 100644
index 00000000..1567b1e4
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/BindposeGizmo.cs.meta
@@ -0,0 +1,13 @@
+fileFormatVersion: 2
+guid: 3ada4f7077a352343aed57e71a58885d
+timeCreated: 1518245944
+licenseType: Free
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneMeshEraser.cs b/Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneMeshEraser.cs
new file mode 100644
index 00000000..64ee850d
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneMeshEraser.cs
@@ -0,0 +1,166 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+
+
+namespace MeshUtility
+{
+ public static class BoneMeshEraser
+ {
+ private struct ExcludeBoneIndex
+ {
+ public readonly bool Bone0;
+ public readonly bool Bone1;
+ public readonly bool Bone2;
+ public readonly bool Bone3;
+
+ public ExcludeBoneIndex(bool bone0, bool bone1, bool bone2, bool bone3)
+ {
+ Bone0 = bone0;
+ Bone1 = bone1;
+ Bone2 = bone2;
+ Bone3 = bone3;
+ }
+ }
+
+ [Serializable]
+ public struct EraseBone
+ {
+ public Transform Bone;
+ public bool Erase;
+
+ public override string ToString()
+ {
+ return Bone.name + ":" + Erase;
+ }
+ }
+
+ static int ExcludeTriangles(int[] triangles, BoneWeight[] bws, int[] exclude)
+ {
+ int count = 0;
+ if (bws != null && bws.Length > 0)
+ {
+ for (int i = 0; i < triangles.Length; i += 3)
+ {
+ var a = triangles[i];
+ var b = triangles[i + 1];
+ var c = triangles[i + 2];
+
+ {
+ var bw = bws[a];
+ var eb = AreBoneContains(ref exclude, bw.boneIndex0, bw.boneIndex1, bw.boneIndex2, bw.boneIndex3);
+ if (bw.weight0 > 0 && eb.Bone0) continue;
+ if (bw.weight1 > 0 && eb.Bone1) continue;
+ if (bw.weight2 > 0 && eb.Bone2) continue;
+ if (bw.weight3 > 0 && eb.Bone3) continue;
+ }
+ {
+ var bw = bws[b];
+ var eb = AreBoneContains(ref exclude, bw.boneIndex0, bw.boneIndex1, bw.boneIndex2, bw.boneIndex3);
+ if (bw.weight0 > 0 && eb.Bone0) continue;
+ if (bw.weight1 > 0 && eb.Bone1) continue;
+ if (bw.weight2 > 0 && eb.Bone2) continue;
+ if (bw.weight3 > 0 && eb.Bone3) continue;
+ }
+ {
+ var bw = bws[c];
+ var eb = AreBoneContains(ref exclude, bw.boneIndex0, bw.boneIndex1, bw.boneIndex2, bw.boneIndex3);
+ if (bw.weight0 > 0 && eb.Bone0) continue;
+ if (bw.weight1 > 0 && eb.Bone1) continue;
+ if (bw.weight2 > 0 && eb.Bone2) continue;
+ if (bw.weight3 > 0 && eb.Bone3) continue;
+ }
+
+ triangles[count++] = a;
+ triangles[count++] = b;
+ triangles[count++] = c;
+ }
+ }
+
+ return count;
+ }
+
+ private static ExcludeBoneIndex AreBoneContains(ref int[] exclude, int boneIndex0, int boneIndex1,
+ int boneIndex2, int boneIndex3)
+ {
+ var b0 = false;
+ var b1 = false;
+ var b2 = false;
+ var b3 = false;
+ for (int i = 0; i < exclude.Length; i++)
+ {
+ if (exclude[i] == boneIndex0)
+ {
+ b0 = true;
+ continue;
+ }
+
+ if (exclude[i] == boneIndex1)
+ {
+ b1 = true;
+ continue;
+ }
+
+ if (exclude[i] == boneIndex2)
+ {
+ b2 = true;
+ continue;
+ }
+
+ if (exclude[i] == boneIndex3)
+ {
+ b3 = true;
+ }
+ }
+
+ return new ExcludeBoneIndex(b0, b1, b2, b3);
+ }
+
+ public static Mesh CreateErasedMesh(Mesh src, int[] eraseBoneIndices)
+ {
+ /*
+ Debug.LogFormat("{0} exclude: {1}",
+ src.name,
+ String.Join(", ", eraseBoneIndices.Select(x => x.ToString()).ToArray())
+ );
+ */
+ var mesh = new Mesh();
+ mesh.name = src.name + "(erased)";
+
+#if UNITY_2017_3_OR_NEWER
+ mesh.indexFormat = src.indexFormat;
+#endif
+
+ mesh.vertices = src.vertices;
+ mesh.normals = src.normals;
+ mesh.uv = src.uv;
+ mesh.tangents = src.tangents;
+ mesh.boneWeights = src.boneWeights;
+ mesh.bindposes = src.bindposes;
+ mesh.subMeshCount = src.subMeshCount;
+ for (int i = 0; i < src.subMeshCount; ++i)
+ {
+ var indices = src.GetIndices(i);
+ var count = ExcludeTriangles(indices, mesh.boneWeights, eraseBoneIndices);
+ var dst = new int[count];
+ Array.Copy(indices, 0, dst, 0, count);
+ mesh.SetIndices(dst, MeshTopology.Triangles, i);
+ }
+
+ return mesh;
+ }
+
+ public static IEnumerable<Transform> Ancestor(this Transform t)
+ {
+ yield return t;
+
+ if (t.parent != null)
+ {
+ foreach (var x in Ancestor(t.parent))
+ {
+ yield return x;
+ }
+ }
+ }
+ }
+}
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneMeshEraser.cs.meta b/Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneMeshEraser.cs.meta
new file mode 100644
index 00000000..db633e87
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneMeshEraser.cs.meta
@@ -0,0 +1,13 @@
+fileFormatVersion: 2
+guid: 270bf7461f6f8d546ae540cb7d5fc6f3
+timeCreated: 1519018975
+licenseType: Free
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneNormalizer.cs b/Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneNormalizer.cs
new file mode 100644
index 00000000..b5f5231c
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneNormalizer.cs
@@ -0,0 +1,507 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+
+
+namespace MeshUtility
+{
+ public static class BoneNormalizer
+ {
+ public delegate Avatar CreateAvatarFunc(GameObject original, GameObject normalized, Dictionary<Transform, Transform> boneMap);
+
+ static (GameObject, Dictionary<Transform, Transform>) NormalizeHierarchy(GameObject go, CreateAvatarFunc createAvatar)
+ {
+ var boneMap = new Dictionary<Transform, Transform>();
+
+ //
+ // 回転・スケールの無いヒエラルキーをコピーする
+ //
+ var normalized = new GameObject(go.name + "(normalized)");
+ normalized.transform.position = go.transform.position;
+ CopyAndBuild(go.transform, normalized.transform, boneMap);
+
+ //
+ // 新しいヒエラルキーからAvatarを作る
+ //
+ {
+ var animator = normalized.AddComponent<Animator>();
+ var avatar = createAvatar(go, normalized, boneMap);
+ avatar.name = go.name + ".normalized";
+ animator.avatar = avatar;
+ }
+
+ return (normalized, boneMap);
+ }
+
+ /// <summary>
+ /// 回転とスケールを除去したヒエラルキーをコピーする。
+ /// </summary>
+ /// <param name="src"></param>
+ /// <param name="dst"></param>
+ static void CopyAndBuild(Transform src, Transform dst, Dictionary<Transform, Transform> 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
+
+ CopyAndBuild(child, dstChild.transform, boneMap);
+ }
+ }
+ }
+
+ class BlendShapeReport
+ {
+ string m_name;
+ int m_count;
+ struct BlendShapeStat
+ {
+ public int Index;
+ public string Name;
+ public int VertexCount;
+ public int NormalCount;
+ public int TangentCount;
+
+ public override string ToString()
+ {
+ return string.Format("[{0}]{1}: {2}, {3}, {4}\n", Index, Name, VertexCount, NormalCount, TangentCount);
+ }
+ }
+ List<BlendShapeStat> m_stats = new List<BlendShapeStat>();
+ public int Count
+ {
+ get { return m_stats.Count; }
+ }
+ public BlendShapeReport(Mesh mesh)
+ {
+ m_name = mesh.name;
+ m_count = mesh.vertexCount;
+ }
+ public void SetCount(int index, string name, int v, int n, int t)
+ {
+ m_stats.Add(new BlendShapeStat
+ {
+ Index = index,
+ Name = name,
+ VertexCount = v,
+ NormalCount = n,
+ TangentCount = t,
+ });
+ }
+ public override string ToString()
+ {
+ return String.Format("NormalizeSkinnedMesh: {0}({1}verts)\n{2}",
+ m_name,
+ m_count,
+ String.Join("", m_stats.Select(x => x.ToString()).ToArray()));
+ }
+ }
+
+ /// <summary>
+ /// index が 有効であれば、setter に weight を渡す。無効であれば setter に 0 を渡す。
+ /// </summary>
+ /// <param name="indexMap"></param>
+ /// <param name="srcIndex"></param>
+ /// <param name="weight"></param>
+ /// <param name="setter"></param>
+ static bool CopyOrDropWeight(int[] indexMap, int srcIndex, float weight, Action<int, float> setter)
+ {
+ if (srcIndex < 0 || srcIndex >= indexMap.Length)
+ {
+ // ありえるかどうかわからないが BoneWeight.boneIndexN に変な値が入っている.
+ setter(0, 0);
+ return false;
+ }
+
+ var dstIndex = indexMap[srcIndex];
+ if (dstIndex != -1)
+ {
+ // 有効なindex。weightをコピーする
+ setter(dstIndex, weight);
+ return true;
+ }
+ else
+ {
+ // 無効なindex。0でクリアする
+ setter(0, 0);
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// BoneWeight[] src から新しいボーンウェイトを作成する。
+ /// </summary>
+ /// <param name="src">変更前のBoneWeight[]</param>
+ /// <param name="boneMap">新旧のボーンの対応表。新しい方は無効なボーンが除去されてnullの部分がある</param>
+ /// <param name="srcBones">変更前のボーン配列</param>
+ /// <param name="dstBones">変更後のボーン配列。除去されたボーンがある場合、変更前より短い</param>
+ /// <returns></returns>
+ public static BoneWeight[] MapBoneWeight(BoneWeight[] src,
+ Dictionary<Transform, Transform> boneMap,
+ Transform[] srcBones,
+ Transform[] dstBones
+ )
+ {
+ // 処理前後の index の対応表を作成する
+ var indexMap = new int[srcBones.Length];
+ for (int i = 0; i < srcBones.Length; ++i)
+ {
+ var srcBone = srcBones[i];
+ if (srcBone == null)
+ {
+ // 元のボーンが無い
+ indexMap[i] = -1;
+ Debug.LogWarningFormat("bones[{0}] is null", i);
+ }
+ else
+ {
+ if (boneMap.TryGetValue(srcBone, out Transform dstBone))
+ {
+ // 対応するボーンが存在する
+ var dstIndex = Array.IndexOf(dstBones, dstBone);
+ if (dstIndex == -1)
+ {
+ // ありえない。バグ
+ throw new Exception();
+ }
+ indexMap[i] = dstIndex;
+ }
+ else
+ {
+ // 先のボーンが無い
+ indexMap[i] = -1;
+ Debug.LogWarningFormat("{0} is removed", srcBone.name);
+ }
+ }
+ }
+
+ // 新しいBoneWeightを作成する
+ var newBoneWeights = new BoneWeight[src.Length];
+ for (int i = 0; i < src.Length; ++i)
+ {
+ BoneWeight srcBoneWeight = src[i];
+
+ // 0
+ CopyOrDropWeight(indexMap, srcBoneWeight.boneIndex0, srcBoneWeight.weight0, (newIndex, newWeight) =>
+ {
+ newBoneWeights[i].boneIndex0 = newIndex;
+ newBoneWeights[i].weight0 = newWeight;
+ });
+ // 1
+ CopyOrDropWeight(indexMap, srcBoneWeight.boneIndex1, srcBoneWeight.weight1, (newIndex, newWeight) =>
+ {
+ newBoneWeights[i].boneIndex1 = newIndex;
+ newBoneWeights[i].weight1 = newWeight;
+ });
+ // 2
+ CopyOrDropWeight(indexMap, srcBoneWeight.boneIndex2, srcBoneWeight.weight2, (newIndex, newWeight) =>
+ {
+ newBoneWeights[i].boneIndex2 = newIndex;
+ newBoneWeights[i].weight2 = newWeight;
+ });
+ // 3
+ CopyOrDropWeight(indexMap, srcBoneWeight.boneIndex3, srcBoneWeight.weight3, (newIndex, newWeight) =>
+ {
+ newBoneWeights[i].boneIndex3 = newIndex;
+ newBoneWeights[i].weight3 = newWeight;
+ });
+ }
+
+ return newBoneWeights;
+ }
+
+ /// <summary>
+ /// srcのSkinnedMeshRendererを正規化して、dstにアタッチする
+ /// </summary>
+ /// <param name="src">正規化前のSkinnedMeshRendererのTransform</param>
+ /// <param name="dst">正規化後のSkinnedMeshRendererのTransform</param>
+ /// <param name="boneMap">正規化前のボーンから正規化後のボーンを得る</param>
+ static void NormalizeSkinnedMesh(Transform src, Transform dst, Dictionary<Transform, Transform> boneMap, bool clearBlendShape)
+ {
+ var srcRenderer = src.GetComponent<SkinnedMeshRenderer>();
+ if (srcRenderer == null
+ || !srcRenderer.enabled
+ || srcRenderer.sharedMesh == null
+ || srcRenderer.sharedMesh.vertexCount == 0)
+ {
+ // 有効なSkinnedMeshRendererが無かった
+ return;
+ }
+
+ var srcMesh = srcRenderer.sharedMesh;
+ var originalSrcMesh = srcMesh;
+
+ // clear blendShape
+ if (clearBlendShape)
+ {
+ for (int i = 0; i < srcMesh.blendShapeCount; ++i)
+ {
+ srcRenderer.SetBlendShapeWeight(i, 0);
+ }
+ }
+
+ // 元の Transform[] bones から、無効なboneを取り除いて前に詰めた配列を作る
+ var dstBones = srcRenderer.bones
+ .Where(x => x != null && boneMap.ContainsKey(x))
+ .Select(x => boneMap[x])
+ .ToArray();
+
+ var hasBoneWeight = srcRenderer.bones != null && srcRenderer.bones.Length > 0;
+ if (!hasBoneWeight)
+ {
+ // Before bake, bind no weight bones
+ //Debug.LogFormat("no weight: {0}", srcMesh.name);
+
+ srcMesh = srcMesh.Copy(true);
+ var bw = new BoneWeight
+ {
+ boneIndex0 = 0,
+ boneIndex1 = 0,
+ boneIndex2 = 0,
+ boneIndex3 = 0,
+ weight0 = 1.0f,
+ weight1 = 0.0f,
+ weight2 = 0.0f,
+ weight3 = 0.0f,
+ };
+ srcMesh.boneWeights = Enumerable.Range(0, srcMesh.vertexCount).Select(x => bw).ToArray();
+ srcMesh.bindposes = new Matrix4x4[] { Matrix4x4.identity };
+
+ srcRenderer.rootBone = srcRenderer.transform;
+ dstBones = new[] { boneMap[srcRenderer.transform] };
+ srcRenderer.bones = new[] { srcRenderer.transform };
+ srcRenderer.sharedMesh = srcMesh;
+ }
+
+ // BakeMesh
+ var mesh = srcMesh.Copy(false);
+ mesh.name = srcMesh.name + ".baked";
+ srcRenderer.BakeMesh(mesh);
+
+ var blendShapeValues = new Dictionary<int, float>();
+ for (int i = 0; i < srcMesh.blendShapeCount; i++)
+ {
+ var val = srcRenderer.GetBlendShapeWeight(i);
+ if (val > 0) blendShapeValues.Add(i, val);
+ }
+
+ // 新しい骨格のボーンウェイトを作成する
+ mesh.boneWeights = MapBoneWeight(srcMesh.boneWeights, boneMap, srcRenderer.bones, dstBones);
+
+ // recalc bindposes
+ mesh.bindposes = dstBones.Select(x => x.worldToLocalMatrix * dst.transform.localToWorldMatrix).ToArray();
+
+ //var m = src.localToWorldMatrix; // include scaling
+ var m = default(Matrix4x4);
+ m.SetTRS(Vector3.zero, src.rotation, Vector3.one); // rotation only
+ mesh.ApplyMatrix(m);
+
+ //
+ // BlendShapes
+ //
+ var meshVertices = mesh.vertices;
+ var meshNormals = mesh.normals;
+#if VRM_NORMALIZE_BLENDSHAPE_TANGENT
+ var meshTangents = mesh.tangents.Select(x => (Vector3)x).ToArray();
+#endif
+
+ var originalBlendShapePositions = new Vector3[meshVertices.Length];
+ var originalBlendShapeNormals = new Vector3[meshVertices.Length];
+ var originalBlendShapeTangents = new Vector3[meshVertices.Length];
+
+ var report = new BlendShapeReport(srcMesh);
+ var blendShapeMesh = new Mesh();
+ for (int i = 0; i < srcMesh.blendShapeCount; ++i)
+ {
+ // check blendShape
+ srcRenderer.sharedMesh.GetBlendShapeFrameVertices(i, 0, originalBlendShapePositions, originalBlendShapeNormals, originalBlendShapeTangents);
+ var hasVertices = originalBlendShapePositions.Count(x => x != Vector3.zero);
+ var hasNormals = originalBlendShapeNormals.Count(x => x != Vector3.zero);
+#if VRM_NORMALIZE_BLENDSHAPE_TANGENT
+ var hasTangents = originalBlendShapeTangents.Count(x => x != Vector3.zero);
+#else
+ var hasTangents = 0;
+#endif
+ var name = srcMesh.GetBlendShapeName(i);
+ if (string.IsNullOrEmpty(name))
+ {
+ name = String.Format("{0}", i);
+ }
+
+ report.SetCount(i, name, hasVertices, hasNormals, hasTangents);
+
+ srcRenderer.SetBlendShapeWeight(i, 100.0f);
+ srcRenderer.BakeMesh(blendShapeMesh);
+ if (blendShapeMesh.vertices.Length != mesh.vertices.Length)
+ {
+ throw new Exception("different vertex count");
+ }
+
+ var value = blendShapeValues.ContainsKey(i) ? blendShapeValues[i] : 0;
+ srcRenderer.SetBlendShapeWeight(i, value);
+
+ Vector3[] vertices = blendShapeMesh.vertices;
+
+ for (int j = 0; j < vertices.Length; ++j)
+ {
+ if (originalBlendShapePositions[j] == Vector3.zero)
+ {
+ vertices[j] = Vector3.zero;
+ }
+ else
+ {
+ vertices[j] = m.MultiplyPoint(vertices[j]) - meshVertices[j];
+ }
+ }
+
+ Vector3[] normals = blendShapeMesh.normals;
+ for (int j = 0; j < normals.Length; ++j)
+ {
+ if (originalBlendShapeNormals[j] == Vector3.zero)
+ {
+ normals[j] = Vector3.zero;
+
+ }
+ else
+ {
+ normals[j] = m.MultiplyVector(normals[j]) - meshNormals[j];
+ }
+ }
+
+ Vector3[] tangents = blendShapeMesh.tangents.Select(x => (Vector3)x).ToArray();
+#if VRM_NORMALIZE_BLENDSHAPE_TANGENT
+ for (int j = 0; j < tangents.Length; ++j)
+ {
+ if (originalBlendShapeTangents[j] == Vector3.zero)
+ {
+ tangents[j] = Vector3.zero;
+ }
+ else
+ {
+ tangents[j] = m.MultiplyVector(tangents[j]) - meshTangents[j];
+ }
+ }
+#endif
+
+ var frameCount = srcMesh.GetBlendShapeFrameCount(i);
+ for (int f = 0; f < frameCount; f++)
+ {
+
+ var weight = srcMesh.GetBlendShapeFrameWeight(i, f);
+
+ try
+ {
+ mesh.AddBlendShapeFrame(name,
+ weight,
+ vertices,
+ hasNormals > 0 ? normals : null,
+ hasTangents > 0 ? tangents : null
+ );
+ }
+ catch (Exception)
+ {
+ Debug.LogErrorFormat("fail to mesh.AddBlendShapeFrame {0}.{1}",
+ mesh.name,
+ srcMesh.GetBlendShapeName(i)
+ );
+ throw;
+ }
+ }
+ }
+
+ if (report.Count > 0)
+ {
+ Debug.LogFormat("{0}", report.ToString());
+ }
+
+ var dstRenderer = dst.gameObject.AddComponent<SkinnedMeshRenderer>();
+ dstRenderer.sharedMaterials = srcRenderer.sharedMaterials;
+ if (srcRenderer.rootBone != null)
+ {
+ dstRenderer.rootBone = boneMap[srcRenderer.rootBone];
+ }
+ dstRenderer.bones = dstBones;
+ dstRenderer.sharedMesh = mesh;
+
+ if (!hasBoneWeight)
+ {
+ // restore bones
+ srcRenderer.bones = new Transform[] { };
+ srcRenderer.sharedMesh = originalSrcMesh;
+ }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="src"></param>
+ /// <param name="dst"></param>
+ static void NormalizeNoneSkinnedMesh(Transform src, Transform dst)
+ {
+ var srcFilter = src.GetComponent<MeshFilter>();
+ if (srcFilter == null
+ || srcFilter.sharedMesh == null
+ || srcFilter.sharedMesh.vertexCount == 0)
+ {
+ return;
+ }
+
+ var srcRenderer = src.GetComponent<MeshRenderer>();
+ if (srcRenderer == null || !srcRenderer.enabled)
+ {
+ return;
+ }
+
+ // Meshに乗っているボーンの姿勢を適用する
+ var dstFilter = dst.gameObject.AddComponent<MeshFilter>();
+
+ var dstMesh = srcFilter.sharedMesh.Copy(false);
+ dstMesh.ApplyRotationAndScale(src.localToWorldMatrix);
+ dstFilter.sharedMesh = dstMesh;
+
+ // Materialをコピー
+ var dstRenderer = dst.gameObject.AddComponent<MeshRenderer>();
+ dstRenderer.sharedMaterials = srcRenderer.sharedMaterials;
+ }
+
+ /// <summary>
+ /// 回転とスケールを除去したヒエラルキーのコピーを作成する(MeshをBakeする)
+ /// </summary>
+ /// <param name="go">対象のヒエラルキーのルート</param>
+ /// <param name="clearBlendShapeBeforeNormalize">BlendShapeを0クリアするか否か。false の場合 BlendShape の現状を Bake する</param>
+ /// <param name="createAvatar">Avatarを作る関数</param>
+ /// <returns></returns>
+ public static (GameObject, Dictionary<Transform, Transform>) Execute(GameObject go,
+ bool clearBlendShapeBeforeNormalize, CreateAvatarFunc createAvatar)
+ {
+ //
+ // 正規化されたヒエラルキーを作る
+ //
+ var (normalized, boneMap) = NormalizeHierarchy(go, createAvatar);
+
+ //
+ // 各メッシュから回転・スケールを取り除いてBinding行列を再計算する
+ //
+ foreach (var src in go.transform.Traverse())
+ {
+ Transform dst;
+ if (!boneMap.TryGetValue(src, out dst))
+ {
+ continue;
+ }
+
+ NormalizeSkinnedMesh(src, dst, boneMap, clearBlendShapeBeforeNormalize);
+
+ NormalizeNoneSkinnedMesh(src, dst);
+ }
+
+ return (normalized, boneMap);
+ }
+ }
+}
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneNormalizer.cs.meta b/Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneNormalizer.cs.meta
new file mode 100644
index 00000000..4663d268
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneNormalizer.cs.meta
@@ -0,0 +1,13 @@
+fileFormatVersion: 2
+guid: b330ec419f98af14687c302638922ab0
+timeCreated: 1519379418
+licenseType: Free
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/Humanoid.cs b/Assets/ThirdParty/VRM/MeshUtility/Runtime/Humanoid.cs
new file mode 100644
index 00000000..c6d61948
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/Humanoid.cs
@@ -0,0 +1,441 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+
+namespace MeshUtility
+{
+ /// <summary>
+ /// Bone割り当てを保持する。
+ /// ヒエラルキーのルート(おそらくHipsの親)にアタッチする
+ /// </summary>
+ [DisallowMultipleComponent]
+ public class Humanoid : MonoBehaviour
+ {
+ [SerializeField] private Transform m_Hips; public Transform Hips => m_Hips;
+
+ #region leg
+ [SerializeField] private Transform m_LeftUpperLeg; public Transform LeftUpperLeg => m_LeftUpperLeg;
+ [SerializeField] private Transform m_RightUpperLeg; public Transform RightUpperLeg => m_RightUpperLeg;
+ [SerializeField] private Transform m_LeftLowerLeg; public Transform LeftLowerLeg => m_LeftLowerLeg;
+ [SerializeField] private Transform m_RightLowerLeg; public Transform RightLowerLeg => m_RightLowerLeg;
+ [SerializeField] private Transform m_LeftFoot; public Transform LeftFoot => m_LeftFoot;
+ [SerializeField] private Transform m_RightFoot; public Transform RightFoot => m_RightFoot;
+ [SerializeField] private Transform m_LeftToes; public Transform LeftToes => m_LeftToes;
+ [SerializeField] private Transform m_RightToes; public Transform RightToes => m_RightToes;
+ #endregion
+
+ #region spine
+ [SerializeField] private Transform m_Spine; public Transform Spine => m_Spine;
+ [SerializeField] private Transform m_Chest; public Transform Chest => m_Chest;
+ [SerializeField] private Transform m_UpperChest; public Transform UpperChest => m_UpperChest;
+ [SerializeField] private Transform m_Neck; public Transform Neck => m_Neck;
+ [SerializeField] private Transform m_Head; public Transform Head => m_Head;
+ [SerializeField] private Transform m_LeftEye; public Transform LeftEye => m_LeftEye;
+ [SerializeField] private Transform m_RightEye; public Transform RightEye => m_RightEye;
+ [SerializeField] private Transform m_Jaw; public Transform Jaw => m_Jaw;
+ #endregion
+
+ #region arm
+ [SerializeField] private Transform m_LeftShoulder; public Transform LeftShoulder => m_LeftShoulder;
+ [SerializeField] private Transform m_RightShoulder; public Transform RightShoulder => m_RightShoulder;
+ [SerializeField] private Transform m_LeftUpperArm; public Transform LeftUpperArm => m_LeftUpperArm;
+ [SerializeField] private Transform m_RightUpperArm; public Transform RightUpperArm => m_RightUpperArm;
+ [SerializeField] private Transform m_LeftLowerArm; public Transform LeftLowerArm => m_LeftLowerArm;
+ [SerializeField] private Transform m_RightLowerArm; public Transform RightLowerArm => m_RightLowerArm;
+ [SerializeField] private Transform m_LeftHand; public Transform LeftHand => m_LeftHand;
+ [SerializeField] private Transform m_RightHand; public Transform RightHand => m_RightHand;
+ #endregion
+
+ #region fingers
+ [SerializeField] private Transform m_LeftThumbProximal; public Transform LeftThumbProximal => m_LeftThumbProximal;
+ [SerializeField] private Transform m_LeftThumbIntermediate; public Transform LeftThumbIntermediate => m_LeftThumbIntermediate;
+ [SerializeField] private Transform m_LeftThumbDistal; public Transform LeftThumbDistal => m_LeftThumbDistal;
+ [SerializeField] private Transform m_LeftIndexProximal; public Transform LeftIndexProximal => m_LeftIndexProximal;
+ [SerializeField] private Transform m_LeftIndexIntermediate; public Transform LeftIndexIntermediate => m_LeftIndexIntermediate;
+ [SerializeField] private Transform m_LeftIndexDistal; public Transform LeftIndexDistal => m_LeftIndexDistal;
+ [SerializeField] private Transform m_LeftMiddleProximal; public Transform LeftMiddleProximal => m_LeftMiddleProximal;
+ [SerializeField] private Transform m_LeftMiddleIntermediate; public Transform LeftMiddleIntermediate => m_LeftMiddleIntermediate;
+ [SerializeField] private Transform m_LeftMiddleDistal; public Transform LeftMiddleDistal => m_LeftMiddleDistal;
+ [SerializeField] private Transform m_LeftRingProximal; public Transform LeftRingProximal => m_LeftRingProximal;
+ [SerializeField] private Transform m_LeftRingIntermediate; public Transform LeftRingIntermediate => m_LeftRingIntermediate;
+ [SerializeField] private Transform m_LeftRingDistal; public Transform LeftRingDistal => m_LeftRingDistal;
+ [SerializeField] private Transform m_LeftLittleProximal; public Transform LeftLittleProximal => m_LeftLittleProximal;
+ [SerializeField] private Transform m_LeftLittleIntermediate; public Transform LeftLittleIntermediate => m_LeftLittleIntermediate;
+ [SerializeField] private Transform m_LeftLittleDistal; public Transform LeftLittleDistal => m_LeftLittleDistal;
+ [SerializeField] private Transform m_RightThumbProximal; public Transform RightThumbProximal => m_RightThumbProximal;
+ [SerializeField] private Transform m_RightThumbIntermediate; public Transform RightThumbIntermediate => m_RightThumbIntermediate;
+ [SerializeField] private Transform m_RightThumbDistal; public Transform RightThumbDistal => m_RightThumbDistal;
+ [SerializeField] private Transform m_RightIndexProximal; public Transform RightIndexProximal => m_RightIndexProximal;
+ [SerializeField] private Transform m_RightIndexIntermediate; public Transform RightIndexIntermediate => m_RightIndexIntermediate;
+ [SerializeField] private Transform m_RightIndexDistal; public Transform RightIndexDistal => m_RightIndexDistal;
+ [SerializeField] private Transform m_RightMiddleProximal; public Transform RightMiddleProximal => m_RightMiddleProximal;
+ [SerializeField] private Transform m_RightMiddleIntermediate; public Transform RightMiddleIntermediate => m_RightMiddleIntermediate;
+ [SerializeField] private Transform m_RightMiddleDistal; public Transform RightMiddleDistal => m_RightMiddleDistal;
+ [SerializeField] private Transform m_RightRingProximal; public Transform RightRingProximal => m_RightRingProximal;
+ [SerializeField] private Transform m_RightRingIntermediate; public Transform RightRingIntermediate => m_RightRingIntermediate;
+ [SerializeField] private Transform m_RightRingDistal; public Transform RightRingDistal => m_RightRingDistal;
+ [SerializeField] private Transform m_RightLittleProximal; public Transform RightLittleProximal => m_RightLittleProximal;
+ [SerializeField] private Transform m_RightLittleIntermediate; public Transform RightLittleIntermediate => m_RightLittleIntermediate;
+ [SerializeField] private Transform m_RightLittleDistal; public Transform RightLittleDistal => m_RightLittleDistal;
+ #endregion
+
+ void Reset()
+ {
+ AssignBonesFromAnimator();
+ }
+
+ public struct Validation
+ {
+ public readonly string Message;
+ public readonly bool IsError;
+
+ public Validation(string message, bool isError)
+ {
+ Message = message;
+ IsError = isError;
+ }
+ }
+
+ IEnumerable<Validation> Required(params (string, Transform)[] props)
+ {
+ foreach (var prop in props)
+ {
+ if (prop.Item2 == null)
+ {
+ var name = prop.Item1;
+ if (name.StartsWith("m_"))
+ {
+ name = name.Substring(2);
+ }
+ yield return new Validation($"{name} is Required", true);
+ }
+ }
+ }
+
+ static Vector3 GetForward(Transform l, Transform r)
+ {
+ if (l == null || r == null)
+ {
+ return Vector3.zero;
+ }
+ var lr = (r.position - l.position).normalized;
+ return Vector3.Cross(lr, Vector3.up);
+ }
+
+ public Vector3 GetForward()
+ {
+ return GetForward(m_LeftUpperLeg, m_RightUpperLeg);
+ }
+
+ public IEnumerable<Validation> Validate()
+ {
+ foreach (var validation in Required(
+ (nameof(m_Hips), m_Hips), (nameof(m_Spine), m_Spine), (nameof(m_Head), m_Head),
+ (nameof(m_LeftUpperLeg), m_LeftUpperLeg), (nameof(m_LeftLowerLeg), m_LeftLowerLeg), (nameof(m_LeftFoot), m_LeftFoot),
+ (nameof(m_RightUpperLeg), m_RightUpperLeg), (nameof(m_RightLowerLeg), m_RightLowerLeg), (nameof(m_RightFoot), m_RightFoot),
+ (nameof(m_LeftUpperArm), m_LeftUpperArm), (nameof(m_LeftLowerArm), m_LeftLowerArm), (nameof(m_LeftHand), m_LeftHand),
+ (nameof(m_RightUpperArm), m_RightUpperArm), (nameof(m_RightLowerArm), m_RightLowerArm), (nameof(m_RightHand), m_RightHand)
+ ))
+ {
+ yield return validation;
+ }
+
+ // var forward = GetForward();
+ // if (Vector3.Dot(Vector3.forward, forward) < 0.5f)
+ // {
+ // yield return new Validation("Not facing the Z-axis positive direction", true);
+ // }
+ }
+
+ /// <summary>
+ /// ボーン割り当てから UnityEngine.Avatar を生成する
+ /// </summary>
+ /// <returns></returns>
+ public Avatar CreateAvatar()
+ {
+ return HumanoidLoader.LoadHumanoidAvatar(transform, BoneMap);
+ }
+
+ public Transform GetBoneTransform(HumanBodyBones bone)
+ {
+ switch (bone)
+ {
+ case HumanBodyBones.Hips: return Hips;
+
+ #region leg
+ case HumanBodyBones.LeftUpperLeg: return LeftUpperLeg;
+ case HumanBodyBones.RightUpperLeg: return RightUpperLeg;
+ case HumanBodyBones.LeftLowerLeg: return LeftLowerLeg;
+ case HumanBodyBones.RightLowerLeg: return RightLowerLeg;
+ case HumanBodyBones.LeftFoot: return LeftFoot;
+ case HumanBodyBones.RightFoot: return RightFoot;
+ case HumanBodyBones.LeftToes: return LeftToes;
+ case HumanBodyBones.RightToes: return RightToes;
+ #endregion
+
+ #region spine
+ case HumanBodyBones.Spine: return Spine;
+ case HumanBodyBones.Chest: return Chest;
+ case HumanBodyBones.UpperChest: return UpperChest;
+ case HumanBodyBones.Neck: return Neck;
+ case HumanBodyBones.Head: return Head;
+ case HumanBodyBones.LeftEye: return LeftEye;
+ case HumanBodyBones.RightEye: return RightEye;
+ case HumanBodyBones.Jaw: return Jaw;
+ #endregion
+
+ #region arm
+ case HumanBodyBones.LeftShoulder: return LeftShoulder;
+ case HumanBodyBones.RightShoulder: return RightShoulder;
+ case HumanBodyBones.LeftUpperArm: return LeftUpperArm;
+ case HumanBodyBones.RightUpperArm: return RightUpperArm;
+ case HumanBodyBones.LeftLowerArm: return LeftLowerArm;
+ case HumanBodyBones.RightLowerArm: return RightLowerArm;
+ case HumanBodyBones.LeftHand: return LeftHand;
+ case HumanBodyBones.RightHand: return RightHand;
+ #endregion
+
+ #region fingers
+ case HumanBodyBones.LeftThumbProximal: return LeftThumbProximal;
+ case HumanBodyBones.LeftThumbIntermediate: return LeftThumbIntermediate;
+ case HumanBodyBones.LeftThumbDistal: return LeftThumbDistal;
+ case HumanBodyBones.LeftIndexProximal: return LeftIndexProximal;
+ case HumanBodyBones.LeftIndexIntermediate: return LeftIndexIntermediate;
+ case HumanBodyBones.LeftIndexDistal: return LeftIndexDistal;
+ case HumanBodyBones.LeftMiddleProximal: return LeftMiddleProximal;
+ case HumanBodyBones.LeftMiddleIntermediate: return LeftMiddleIntermediate;
+ case HumanBodyBones.LeftMiddleDistal: return LeftMiddleDistal;
+ case HumanBodyBones.LeftRingProximal: return LeftRingProximal;
+ case HumanBodyBones.LeftRingIntermediate: return LeftRingIntermediate;
+ case HumanBodyBones.LeftRingDistal: return LeftRingDistal;
+ case HumanBodyBones.LeftLittleProximal: return LeftLittleProximal;
+ case HumanBodyBones.LeftLittleIntermediate: return LeftLittleIntermediate;
+ case HumanBodyBones.LeftLittleDistal: return LeftLittleDistal;
+ case HumanBodyBones.RightThumbProximal: return RightThumbProximal;
+ case HumanBodyBones.RightThumbIntermediate: return RightThumbIntermediate;
+ case HumanBodyBones.RightThumbDistal: return RightThumbDistal;
+ case HumanBodyBones.RightIndexProximal: return RightIndexProximal;
+ case HumanBodyBones.RightIndexIntermediate: return RightIndexIntermediate;
+ case HumanBodyBones.RightIndexDistal: return RightIndexDistal;
+ case HumanBodyBones.RightMiddleProximal: return RightMiddleProximal;
+ case HumanBodyBones.RightMiddleIntermediate: return RightMiddleIntermediate;
+ case HumanBodyBones.RightMiddleDistal: return RightMiddleDistal;
+ case HumanBodyBones.RightRingProximal: return RightRingProximal;
+ case HumanBodyBones.RightRingIntermediate: return RightRingIntermediate;
+ case HumanBodyBones.RightRingDistal: return RightRingDistal;
+ case HumanBodyBones.RightLittleProximal: return RightLittleProximal;
+ case HumanBodyBones.RightLittleIntermediate: return RightLittleIntermediate;
+ case HumanBodyBones.RightLittleDistal: return RightLittleDistal;
+ #endregion
+
+ }
+
+ return null;
+ }
+
+ IEnumerable<(Transform, HumanBodyBones)> BoneMap
+ {
+ get
+ {
+ if (Hips != null) { yield return (Hips, HumanBodyBones.Hips); }
+
+ #region leg
+ if (LeftUpperLeg != null) { yield return (LeftUpperLeg, HumanBodyBones.LeftUpperLeg); }
+ if (RightUpperLeg != null) { yield return (RightUpperLeg, HumanBodyBones.RightUpperLeg); }
+ if (LeftLowerLeg != null) { yield return (LeftLowerLeg, HumanBodyBones.LeftLowerLeg); }
+ if (RightLowerLeg != null) { yield return (RightLowerLeg, HumanBodyBones.RightLowerLeg); }
+ if (LeftFoot != null) { yield return (LeftFoot, HumanBodyBones.LeftFoot); }
+ if (RightFoot != null) { yield return (RightFoot, HumanBodyBones.RightFoot); }
+ if (LeftToes != null) { yield return (LeftToes, HumanBodyBones.LeftToes); }
+ if (RightToes != null) { yield return (RightToes, HumanBodyBones.RightToes); }
+ #endregion
+
+ #region spine
+ if (Spine != null) { yield return (Spine, HumanBodyBones.Spine); }
+ if (Chest != null) { yield return (Chest, HumanBodyBones.Chest); }
+ if (UpperChest != null) { yield return (UpperChest, HumanBodyBones.UpperChest); }
+ if (Neck != null) { yield return (Neck, HumanBodyBones.Neck); }
+ if (Head != null) { yield return (Head, HumanBodyBones.Head); }
+ if (LeftEye != null) { yield return (LeftEye, HumanBodyBones.LeftEye); }
+ if (RightEye != null) { yield return (RightEye, HumanBodyBones.RightEye); }
+ if (Jaw != null) { yield return (Jaw, HumanBodyBones.Jaw); }
+ #endregion
+
+ #region arm
+ if (LeftShoulder != null) { yield return (LeftShoulder, HumanBodyBones.LeftShoulder); }
+ if (RightShoulder != null) { yield return (RightShoulder, HumanBodyBones.RightShoulder); }
+ if (LeftUpperArm != null) { yield return (LeftUpperArm, HumanBodyBones.LeftUpperArm); }
+ if (RightUpperArm != null) { yield return (RightUpperArm, HumanBodyBones.RightUpperArm); }
+ if (LeftLowerArm != null) { yield return (LeftLowerArm, HumanBodyBones.LeftLowerArm); }
+ if (RightLowerArm != null) { yield return (RightLowerArm, HumanBodyBones.RightLowerArm); }
+ if (LeftHand != null) { yield return (LeftHand, HumanBodyBones.LeftHand); }
+ if (RightHand != null) { yield return (RightHand, HumanBodyBones.RightHand); }
+ #endregion
+
+ #region fingers
+ if (LeftThumbProximal != null) { yield return (LeftThumbProximal, HumanBodyBones.LeftThumbProximal); }
+ if (LeftThumbIntermediate != null) { yield return (LeftThumbIntermediate, HumanBodyBones.LeftThumbIntermediate); }
+ if (LeftThumbDistal != null) { yield return (LeftThumbDistal, HumanBodyBones.LeftThumbDistal); }
+ if (LeftIndexProximal != null) { yield return (LeftIndexProximal, HumanBodyBones.LeftIndexProximal); }
+ if (LeftIndexIntermediate != null) { yield return (LeftIndexIntermediate, HumanBodyBones.LeftIndexIntermediate); }
+ if (LeftIndexDistal != null) { yield return (LeftIndexDistal, HumanBodyBones.LeftIndexDistal); }
+ if (LeftMiddleProximal != null) { yield return (LeftMiddleProximal, HumanBodyBones.LeftMiddleProximal); }
+ if (LeftMiddleIntermediate != null) { yield return (LeftMiddleIntermediate, HumanBodyBones.LeftMiddleIntermediate); }
+ if (LeftMiddleDistal != null) { yield return (LeftMiddleDistal, HumanBodyBones.LeftMiddleDistal); }
+ if (LeftRingProximal != null) { yield return (LeftRingProximal, HumanBodyBones.LeftRingProximal); }
+ if (LeftRingIntermediate != null) { yield return (LeftRingIntermediate, HumanBodyBones.LeftRingIntermediate); }
+ if (LeftRingDistal != null) { yield return (LeftRingDistal, HumanBodyBones.LeftRingDistal); }
+ if (LeftLittleProximal != null) { yield return (LeftLittleProximal, HumanBodyBones.LeftLittleProximal); }
+ if (LeftLittleIntermediate != null) { yield return (LeftLittleIntermediate, HumanBodyBones.LeftLittleIntermediate); }
+ if (LeftLittleDistal != null) { yield return (LeftLittleDistal, HumanBodyBones.LeftLittleDistal); }
+ if (RightThumbProximal != null) { yield return (RightThumbProximal, HumanBodyBones.RightThumbProximal); }
+ if (RightThumbIntermediate != null) { yield return (RightThumbIntermediate, HumanBodyBones.RightThumbIntermediate); }
+ if (RightThumbDistal != null) { yield return (RightThumbDistal, HumanBodyBones.RightThumbDistal); }
+ if (RightIndexProximal != null) { yield return (RightIndexProximal, HumanBodyBones.RightIndexProximal); }
+ if (RightIndexIntermediate != null) { yield return (RightIndexIntermediate, HumanBodyBones.RightIndexIntermediate); }
+ if (RightIndexDistal != null) { yield return (RightIndexDistal, HumanBodyBones.RightIndexDistal); }
+ if (RightMiddleProximal != null) { yield return (RightMiddleProximal, HumanBodyBones.RightMiddleProximal); }
+ if (RightMiddleIntermediate != null) { yield return (RightMiddleIntermediate, HumanBodyBones.RightMiddleIntermediate); }
+ if (RightMiddleDistal != null) { yield return (RightMiddleDistal, HumanBodyBones.RightMiddleDistal); }
+ if (RightRingProximal != null) { yield return (RightRingProximal, HumanBodyBones.RightRingProximal); }
+ if (RightRingIntermediate != null) { yield return (RightRingIntermediate, HumanBodyBones.RightRingIntermediate); }
+ if (RightRingDistal != null) { yield return (RightRingDistal, HumanBodyBones.RightRingDistal); }
+ if (RightLittleProximal != null) { yield return (RightLittleProximal, HumanBodyBones.RightLittleProximal); }
+ if (RightLittleIntermediate != null) { yield return (RightLittleIntermediate, HumanBodyBones.RightLittleIntermediate); }
+ if (RightLittleDistal != null) { yield return (RightLittleDistal, HumanBodyBones.RightLittleDistal); }
+ #endregion
+ }
+ }
+
+ /// <summary>
+ /// nodes からボーンを割り当てる
+ /// </summary>
+ /// <param name="nodes"></param>
+ public void AssignBones(IEnumerable<(HumanBodyBones, Transform)> nodes)
+ {
+ foreach (var (key, value) in nodes)
+ {
+ if (key == HumanBodyBones.LastBone)
+ {
+ continue;
+ }
+ if (value is null)
+ {
+ continue;
+ }
+
+ switch (key)
+ {
+ case HumanBodyBones.Hips: m_Hips = value; break;
+
+ #region leg
+ case HumanBodyBones.LeftUpperLeg: m_LeftUpperLeg = value; break;
+ case HumanBodyBones.RightUpperLeg: m_RightUpperLeg = value; break;
+ case HumanBodyBones.LeftLowerLeg: m_LeftLowerLeg = value; break;
+ case HumanBodyBones.RightLowerLeg: m_RightLowerLeg = value; break;
+ case HumanBodyBones.LeftFoot: m_LeftFoot = value; break;
+ case HumanBodyBones.RightFoot: m_RightFoot = value; break;
+ case HumanBodyBones.LeftToes: m_LeftToes = value; break;
+ case HumanBodyBones.RightToes: m_RightToes = value; break;
+ #endregion
+
+ #region spine
+ case HumanBodyBones.Spine: m_Spine = value; break;
+ case HumanBodyBones.Chest: m_Chest = value; break;
+ case HumanBodyBones.UpperChest: m_UpperChest = value; break;
+ case HumanBodyBones.Neck: m_Neck = value; break;
+ case HumanBodyBones.Head: m_Head = value; break;
+ case HumanBodyBones.LeftEye: m_LeftEye = value; break;
+ case HumanBodyBones.RightEye: m_RightEye = value; break;
+ case HumanBodyBones.Jaw: m_Jaw = value; break;
+ #endregion
+
+ #region arm
+ case HumanBodyBones.LeftShoulder: m_LeftShoulder = value; break;
+ case HumanBodyBones.RightShoulder: m_RightShoulder = value; break;
+ case HumanBodyBones.LeftUpperArm: m_LeftUpperArm = value; break;
+ case HumanBodyBones.RightUpperArm: m_RightUpperArm = value; break;
+ case HumanBodyBones.LeftLowerArm: m_LeftLowerArm = value; break;
+ case HumanBodyBones.RightLowerArm: m_RightLowerArm = value; break;
+ case HumanBodyBones.LeftHand: m_LeftHand = value; break;
+ case HumanBodyBones.RightHand: m_RightHand = value; break;
+ #endregion
+
+ #region fingers
+ case HumanBodyBones.LeftThumbProximal: m_LeftThumbProximal = value; break;
+ case HumanBodyBones.LeftThumbIntermediate: m_LeftThumbIntermediate = value; break;
+ case HumanBodyBones.LeftThumbDistal: m_LeftThumbDistal = value; break;
+ case HumanBodyBones.LeftIndexProximal: m_LeftIndexProximal = value; break;
+ case HumanBodyBones.LeftIndexIntermediate: m_LeftIndexIntermediate = value; break;
+ case HumanBodyBones.LeftIndexDistal: m_LeftIndexDistal = value; break;
+ case HumanBodyBones.LeftMiddleProximal: m_LeftMiddleProximal = value; break;
+ case HumanBodyBones.LeftMiddleIntermediate: m_LeftMiddleIntermediate = value; break;
+ case HumanBodyBones.LeftMiddleDistal: m_LeftMiddleDistal = value; break;
+ case HumanBodyBones.LeftRingProximal: m_LeftRingProximal = value; break;
+ case HumanBodyBones.LeftRingIntermediate: m_LeftRingIntermediate = value; break;
+ case HumanBodyBones.LeftRingDistal: m_LeftRingDistal = value; break;
+ case HumanBodyBones.LeftLittleProximal: m_LeftLittleProximal = value; break;
+ case HumanBodyBones.LeftLittleIntermediate: m_LeftLittleIntermediate = value; break;
+ case HumanBodyBones.LeftLittleDistal: m_LeftLittleDistal = value; break;
+ case HumanBodyBones.RightThumbProximal: m_RightThumbProximal = value; break;
+ case HumanBodyBones.RightThumbIntermediate: m_RightThumbIntermediate = value; break;
+ case HumanBodyBones.RightThumbDistal: m_RightThumbDistal = value; break;
+ case HumanBodyBones.RightIndexProximal: m_RightIndexProximal = value; break;
+ case HumanBodyBones.RightIndexIntermediate: m_RightIndexIntermediate = value; break;
+ case HumanBodyBones.RightIndexDistal: m_RightIndexDistal = value; break;
+ case HumanBodyBones.RightMiddleProximal: m_RightMiddleProximal = value; break;
+ case HumanBodyBones.RightMiddleIntermediate: m_RightMiddleIntermediate = value; break;
+ case HumanBodyBones.RightMiddleDistal: m_RightMiddleDistal = value; break;
+ case HumanBodyBones.RightRingProximal: m_RightRingProximal = value; break;
+ case HumanBodyBones.RightRingIntermediate: m_RightRingIntermediate = value; break;
+ case HumanBodyBones.RightRingDistal: m_RightRingDistal = value; break;
+ case HumanBodyBones.RightLittleProximal: m_RightLittleProximal = value; break;
+ case HumanBodyBones.RightLittleIntermediate: m_RightLittleIntermediate = value; break;
+ case HumanBodyBones.RightLittleDistal: m_RightLittleDistal = value; break;
+ #endregion
+ }
+ }
+ }
+
+ /// <summary>
+ /// Animator から Bone を割り当てる
+ /// </summary>
+ /// <returns></returns>
+ public bool AssignBonesFromAnimator()
+ {
+ var animator = GetComponent<Animator>();
+ if (animator == null)
+ {
+ return false;
+ }
+ var avatar = animator.avatar;
+ if (avatar == null)
+ {
+ return false;
+ }
+ if (!avatar.isValid)
+ {
+ return false;
+ }
+ if (!avatar.isHuman)
+ {
+ return false;
+ }
+
+ var keys = (UnityEngine.HumanBodyBones[])Enum.GetValues(typeof(UnityEngine.HumanBodyBones));
+
+ AssignBones(keys.Select(x =>
+ {
+ if (x == HumanBodyBones.LastBone)
+ {
+ return (HumanBodyBones.LastBone, null);
+ }
+ return ((HumanBodyBones)Enum.Parse(typeof(HumanBodyBones), x.ToString(), true), animator.GetBoneTransform(x));
+ }));
+
+ return true;
+ }
+ }
+}
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/Humanoid.cs.meta b/Assets/ThirdParty/VRM/MeshUtility/Runtime/Humanoid.cs.meta
new file mode 100644
index 00000000..53fc0f6d
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/Humanoid.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 889d98e41c0e8ff48bae50d1a729c2df
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/HumanoidLoader.cs b/Assets/ThirdParty/VRM/MeshUtility/Runtime/HumanoidLoader.cs
new file mode 100644
index 00000000..2a5d5252
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/HumanoidLoader.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+
+namespace MeshUtility
+{
+ public static class HumanoidLoader
+ {
+ public static Avatar LoadHumanoidAvatar(Transform root, IEnumerable<(Transform, HumanBodyBones)> boneMap)
+ {
+ var description = new HumanDescription
+ {
+ skeleton = root.GetComponentsInChildren<Transform>()
+ .Select(x => x.ToSkeletonBone()).ToArray(),
+ human = boneMap
+ .Select(x => new HumanBone
+ {
+ boneName = x.Item1.name,
+ humanName = s_humanTranitBoneNameMap[x.Item2],
+ limit = new HumanLimit
+ {
+ useDefaultValues = true,
+ }
+ }).ToArray(),
+
+ armStretch = 0.05f,
+ legStretch = 0.05f,
+ upperArmTwist = 0.5f,
+ lowerArmTwist = 0.5f,
+ upperLegTwist = 0.5f,
+ lowerLegTwist = 0.5f,
+ feetSpacing = 0,
+ hasTranslationDoF = false,
+ };
+
+ return AvatarBuilder.BuildHumanAvatar(root.gameObject, description);
+ }
+
+ static SkeletonBone ToSkeletonBone(this Transform t)
+ {
+ var sb = new SkeletonBone();
+ sb.name = t.name;
+ sb.position = t.localPosition;
+ sb.rotation = t.localRotation;
+ sb.scale = t.localScale;
+ return sb;
+ }
+
+ static HumanBodyBones TraitToHumanBone(string x)
+ {
+ return (HumanBodyBones)Enum.Parse(typeof(HumanBodyBones), x.Replace(" ", ""), true);
+ }
+
+ static readonly Dictionary<HumanBodyBones, string> s_humanTranitBoneNameMap =
+ HumanTrait.BoneName.ToDictionary(
+ x => TraitToHumanBone(x),
+ x => x);
+ }
+}
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/HumanoidLoader.cs.meta b/Assets/ThirdParty/VRM/MeshUtility/Runtime/HumanoidLoader.cs.meta
new file mode 100644
index 00000000..02965556
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/HumanoidLoader.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 12453a111483e4145852e3b057e065d9
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshExtensions.cs b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshExtensions.cs
new file mode 100644
index 00000000..aa458d52
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshExtensions.cs
@@ -0,0 +1,85 @@
+using UnityEngine;
+using System.Linq;
+
+
+namespace MeshUtility
+{
+ public static class MeshExtensions
+ {
+ public static Mesh Copy(this Mesh src, bool copyBlendShape)
+ {
+ var dst = new Mesh();
+ dst.name = src.name + "(copy)";
+#if UNITY_2017_3_OR_NEWER
+ dst.indexFormat = src.indexFormat;
+#endif
+
+ dst.vertices = src.vertices;
+ dst.normals = src.normals;
+ dst.tangents = src.tangents;
+ dst.colors = src.colors;
+ dst.uv = src.uv;
+ dst.uv2 = src.uv2;
+ dst.uv3 = src.uv3;
+ dst.uv4 = src.uv4;
+ dst.boneWeights = src.boneWeights;
+ dst.bindposes = src.bindposes;
+
+ dst.subMeshCount = src.subMeshCount;
+ for (int i = 0; i < dst.subMeshCount; ++i)
+ {
+ dst.SetIndices(src.GetIndices(i), src.GetTopology(i), i);
+ }
+
+ dst.RecalculateBounds();
+
+ if (copyBlendShape)
+ {
+ var vertices = src.vertices;
+ var normals = src.normals;
+#if VRM_NORMALIZE_BLENDSHAPE_TANGENT
+ var tangents = src.tangents.Select(x => (Vector3)x).ToArray();
+#else
+ Vector3[] tangents = null;
+#endif
+
+ for (int i = 0; i < src.blendShapeCount; ++i)
+ {
+ src.GetBlendShapeFrameVertices(i, 0, vertices, normals, tangents);
+ dst.AddBlendShapeFrame(
+ src.GetBlendShapeName(i),
+ src.GetBlendShapeFrameWeight(i, 0),
+ vertices,
+ normals,
+ tangents
+ );
+ }
+ }
+
+ return dst;
+ }
+
+ public static void ApplyRotationAndScale(this Mesh src, Matrix4x4 m)
+ {
+ m.SetColumn(3, new Vector4(0, 0, 0, 1)); // remove translation
+ src.ApplyMatrix(m);
+ }
+
+ public static void ApplyMatrix(this Mesh src, Matrix4x4 m)
+ {
+ src.vertices = src.vertices.Select(x => m.MultiplyPoint(x)).ToArray();
+ if (src.normals != null && src.normals.Length > 0)
+ {
+ src.normals = src.normals.Select(x => m.MultiplyVector(x)).ToArray();
+ }
+ if (src.tangents != null && src.tangents.Length > 0)
+ {
+ src.tangents = src.tangents.Select(x =>
+ {
+ var t = m.MultiplyVector((Vector3)x);
+ return new Vector4(t.x, t.y, t.z, x.w);
+ }).ToArray();
+ }
+ }
+ }
+}
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshExtensions.cs.meta b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshExtensions.cs.meta
new file mode 100644
index 00000000..7485178c
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshExtensions.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 4181f0b5e9a271b45b3e995a38202780
+timeCreated: 1532506262
+licenseType: Free
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrationResult.cs b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrationResult.cs
new file mode 100644
index 00000000..91742fc8
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrationResult.cs
@@ -0,0 +1,13 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace MeshUtility
+{
+ [System.Serializable]
+ public class MeshIntegrationResult
+ {
+ public List<SkinnedMeshRenderer> SourceSkinnedMeshRenderers = new List<SkinnedMeshRenderer>();
+ public List<MeshRenderer> SourceMeshRenderers = new List<MeshRenderer>();
+ public SkinnedMeshRenderer IntegratedRenderer;
+ }
+}
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrationResult.cs.meta b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrationResult.cs.meta
new file mode 100644
index 00000000..5f32450b
--- /dev/null
+++ b/Assets/ThirdParty/VRM/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/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrator.cs b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrator.cs
new file mode 100644
index 00000000..34ba7005
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrator.cs
@@ -0,0 +1,253 @@
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+
+namespace MeshUtility
+{
+ public class MeshIntegrator
+ {
+ public struct SubMesh
+ {
+ public List<int> Indices;
+ public Material Material;
+ }
+
+ public class BlendShape
+ {
+ public int VertexOffset;
+ public string Name;
+ public float FrameWeight;
+ public Vector3[] Positions;
+ public Vector3[] Normals;
+ public Vector3[] Tangents;
+ }
+
+// public List<SkinnedMeshRenderer> Renderers { get; private set; }
+ public List<Vector3> Positions { get; private set; }
+ public List<Vector3> Normals { get; private set; }
+ public List<Vector2> UV { get; private set; }
+ public List<Vector4> Tangents { get; private set; }
+ public List<BoneWeight> BoneWeights { get; private set; }
+
+ public List<SubMesh> SubMeshes
+ {
+ get;
+ private set;
+ }
+
+ public List<Matrix4x4> BindPoses { get; private set; }
+ public List<Transform> Bones { get; private set; }
+
+ public List<BlendShape> BlendShapes { get; private set; }
+ public void AddBlendShapesToMesh(Mesh mesh)
+ {
+ Dictionary<string, BlendShape> map = new Dictionary<string, BlendShape>();
+
+ foreach (var x in BlendShapes)
+ {
+ BlendShape bs = null;
+ if (!map.TryGetValue(x.Name, out bs))
+ {
+ bs = new BlendShape();
+ bs.Positions = new Vector3[Positions.Count];
+ bs.Normals = new Vector3[Normals.Count];
+ bs.Tangents = new Vector3[Tangents.Count];
+ bs.Name = x.Name;
+ bs.FrameWeight = x.FrameWeight;
+ map.Add(x.Name, bs);
+ }
+
+ var j = x.VertexOffset;
+ for (int i = 0; i < x.Positions.Length; ++i, ++j)
+ {
+ bs.Positions[j] = x.Positions[i];
+ bs.Normals[j] = x.Normals[i];
+ bs.Tangents[j] = x.Tangents[i];
+ }
+ }
+
+ foreach (var kv in map)
+ {
+ //Debug.LogFormat("AddBlendShapeFrame: {0}", kv.Key);
+ mesh.AddBlendShapeFrame(kv.Key, kv.Value.FrameWeight,
+ kv.Value.Positions, kv.Value.Normals, kv.Value.Tangents);
+ }
+ }
+
+ public MeshIntegrator()
+ {
+// Renderers = new List<SkinnedMeshRenderer>();
+
+ Positions = new List<Vector3>();
+ Normals = new List<Vector3>();
+ UV = new List<Vector2>();
+ Tangents = new List<Vector4>();
+ BoneWeights = new List<BoneWeight>();
+
+ SubMeshes = new List<SubMesh>();
+
+ BindPoses = new List<Matrix4x4>();
+ Bones = new List<Transform>();
+
+ BlendShapes = new List<BlendShape>();
+ }
+
+ static BoneWeight AddBoneIndexOffset(BoneWeight bw, int boneIndexOffset)
+ {
+ if (bw.weight0 > 0) bw.boneIndex0 += boneIndexOffset;
+ if (bw.weight1 > 0) bw.boneIndex1 += boneIndexOffset;
+ if (bw.weight2 > 0) bw.boneIndex2 += boneIndexOffset;
+ if (bw.weight3 > 0) bw.boneIndex3 += boneIndexOffset;
+ return bw;
+ }
+
+ public void Push(MeshRenderer renderer)
+ {
+ var meshFilter = renderer.GetComponent<MeshFilter>();
+ if (meshFilter == null)
+ {
+ Debug.LogWarningFormat("{0} has no mesh filter", renderer.name);
+ return;
+ }
+ var mesh = meshFilter.sharedMesh;
+ if (mesh == null)
+ {
+ Debug.LogWarningFormat("{0} has no mesh", renderer.name);
+ return;
+ }
+
+ var indexOffset = Positions.Count;
+ var boneIndexOffset = Bones.Count;
+
+ Positions.AddRange(mesh.vertices
+ .Select(x => renderer.transform.TransformPoint(x))
+ );
+ Normals.AddRange(mesh.normals
+ .Select(x => renderer.transform.TransformVector(x))
+ );
+ UV.AddRange(mesh.uv);
+ Tangents.AddRange(mesh.tangents
+ .Select(t =>
+ {
+ var v = renderer.transform.TransformVector(t.x, t.y, t.z);
+ return new Vector4(v.x, v.y, v.z, t.w);
+ })
+ );
+
+ var self = renderer.transform;
+ var bone = self.parent;
+ if (bone == null)
+ {
+ Debug.LogWarningFormat("{0} is root gameobject.", self.name);
+ return;
+ }
+ var bindpose = bone.worldToLocalMatrix;
+
+ BoneWeights.AddRange(Enumerable.Range(0, mesh.vertices.Length)
+ .Select(x => new BoneWeight()
+ {
+ boneIndex0 = Bones.Count,
+ weight0 = 1,
+ })
+ );
+
+ BindPoses.Add(bindpose);
+ Bones.Add(bone);
+
+ for (int i = 0; i < mesh.subMeshCount; ++i)
+ {
+ var indices = mesh.GetIndices(i).Select(x => x + indexOffset);
+ var mat = renderer.sharedMaterials[i];
+ var sameMaterialSubMeshIndex = SubMeshes.FindIndex(x => ReferenceEquals(x.Material, mat));
+ if (sameMaterialSubMeshIndex >= 0)
+ {
+ SubMeshes[sameMaterialSubMeshIndex].Indices.AddRange(indices);
+ }
+ else
+ {
+ SubMeshes.Add(new SubMesh
+ {
+ Indices = indices.ToList(),
+ Material = mat,
+ });
+ }
+ }
+ }
+
+ public void Push(SkinnedMeshRenderer renderer)
+ {
+ var mesh = renderer.sharedMesh;
+ if (mesh == null)
+ {
+ Debug.LogWarningFormat("{0} has no mesh", renderer.name);
+ return;
+ }
+
+// Renderers.Add(renderer);
+
+ var indexOffset = Positions.Count;
+ var boneIndexOffset = Bones.Count;
+
+ Positions.AddRange(mesh.vertices);
+ Normals.AddRange(mesh.normals);
+ UV.AddRange(mesh.uv);
+ Tangents.AddRange(mesh.tangents);
+
+ if (mesh.vertexCount == mesh.boneWeights.Length)
+ {
+ BoneWeights.AddRange(mesh.boneWeights.Select(x => AddBoneIndexOffset(x, boneIndexOffset)).ToArray());
+ BindPoses.AddRange(mesh.bindposes);
+ Bones.AddRange(renderer.bones);
+ }
+ else
+ {
+ // Bone Count 0 の SkinnedMeshRenderer
+ var rigidBoneWeight = new BoneWeight
+ {
+ boneIndex0 = boneIndexOffset,
+ weight0 = 1f,
+ };
+ BoneWeights.AddRange(Enumerable.Range(0, mesh.vertexCount).Select(x => rigidBoneWeight).ToArray());
+ BindPoses.Add(renderer.transform.localToWorldMatrix);
+ Bones.Add(renderer.transform);
+ }
+
+ for (int i = 0; i < mesh.subMeshCount; ++i)
+ {
+ var indices = mesh.GetIndices(i).Select(x => x + indexOffset);
+ var mat = renderer.sharedMaterials[i];
+ var sameMaterialSubMeshIndex = SubMeshes.FindIndex(x => ReferenceEquals(x.Material, mat));
+ if (sameMaterialSubMeshIndex >= 0)
+ {
+ SubMeshes[sameMaterialSubMeshIndex].Indices.AddRange(indices);
+ }
+ else
+ {
+ SubMeshes.Add(new SubMesh
+ {
+ Indices = indices.ToList(),
+ Material = mat,
+ });
+ }
+ }
+
+ for (int i = 0; i < mesh.blendShapeCount; ++i)
+ {
+ var positions = (Vector3[])mesh.vertices.Clone();
+ var normals = (Vector3[])mesh.normals.Clone();
+ var tangents = mesh.tangents.Select(x => (Vector3)x).ToArray();
+
+ mesh.GetBlendShapeFrameVertices(i, 0, positions, normals, tangents);
+ BlendShapes.Add(new BlendShape
+ {
+ VertexOffset = indexOffset,
+ FrameWeight = mesh.GetBlendShapeFrameWeight(i, 0),
+ Name = mesh.GetBlendShapeName(i),
+ Positions = positions,
+ Normals = normals,
+ Tangents = tangents,
+ });
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrator.cs.meta b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrator.cs.meta
new file mode 100644
index 00000000..15921c89
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrator.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 547dd57b50bf4820a570336659345084
+timeCreated: 1560168946 \ No newline at end of file
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegratorUtility.cs b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegratorUtility.cs
new file mode 100644
index 00000000..cfb1742e
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegratorUtility.cs
@@ -0,0 +1,140 @@
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+
+namespace MeshUtility
+{
+ public static class MeshIntegratorUtility
+ {
+ /// <summary>
+ /// go を root としたヒエラルキーから Renderer を集めて、統合された Mesh 作成する
+ /// </summary>
+ /// <param name="go"></param>
+ /// <param name="onlyBlendShapeRenderers">BlendShapeを保持するSkinnedMeshRendererのみ/BlendShapeを保持しないSkinnedMeshRenderer + MeshRenderer</param>
+ /// <returns></returns>
+ 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<SkinnedMeshRenderer>();
+ 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<SkinnedMeshRenderer> EnumerateSkinnedMeshRenderer(Transform root, bool hasBlendShape)
+ {
+ foreach (var x in Traverse(root))
+ {
+ var renderer = x.GetComponent<SkinnedMeshRenderer>();
+ if (renderer != null &&
+ renderer.gameObject.activeInHierarchy &&
+ renderer.sharedMesh != null &&
+ renderer.enabled &&
+ renderer.sharedMesh.blendShapeCount > 0 == hasBlendShape)
+ {
+ yield return renderer;
+ }
+ }
+ }
+
+ public static IEnumerable<MeshRenderer> EnumerateMeshRenderer(Transform root)
+ {
+ foreach (var x in Traverse(root))
+ {
+ var renderer = x.GetComponent<MeshRenderer>();
+ var filter = x.GetComponent<MeshFilter>();
+
+ if (renderer != null &&
+ filter != null &&
+ renderer.gameObject.activeInHierarchy &&
+ filter.sharedMesh != null)
+ {
+ yield return renderer;
+ }
+ }
+ }
+
+ private static IEnumerable<Transform> 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/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegratorUtility.cs.meta b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegratorUtility.cs.meta
new file mode 100644
index 00000000..b9075e71
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegratorUtility.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: a982d9d30c0145038245b0214dc2f2e4
+timeCreated: 1560190306 \ No newline at end of file
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshUtility.asmdef b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshUtility.asmdef
new file mode 100644
index 00000000..f161fcaf
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshUtility.asmdef
@@ -0,0 +1,3 @@
+{
+ "name": "MeshUtility"
+}
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshUtility.asmdef.meta b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshUtility.asmdef.meta
new file mode 100644
index 00000000..4085faa9
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshUtility.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 71ab1919192903d44971eedbc26b24d1
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityExtensions.cs b/Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityExtensions.cs
new file mode 100644
index 00000000..a772980d
--- /dev/null
+++ b/Assets/ThirdParty/VRM/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<Vector3> Positions = new List<Vector3>();
+ public List<Vector3> Normals = new List<Vector3>();
+ public List<Vector3> Tangents = new List<Vector3>();
+ }
+
+ 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<String>();
+ 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<Transform> GetChildren(this Transform self)
+ {
+ foreach (Transform child in self)
+ {
+ yield return child;
+ }
+ }
+
+ public static IEnumerable<Transform> 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<Transform> 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<MeshFilter>();
+ if (meshFilter != null)
+ {
+ return meshFilter.sharedMesh;
+ }
+
+ var skinnedMeshRenderer = t.GetComponent<SkinnedMeshRenderer>();
+ if (skinnedMeshRenderer != null)
+ {
+ return skinnedMeshRenderer.sharedMesh;
+ }
+
+ return null;
+ }
+
+ public static Material[] GetSharedMaterials(this Transform t)
+ {
+ var renderer = t.GetComponent<Renderer>();
+ if (renderer != null)
+ {
+ return renderer.sharedMaterials;
+ }
+
+ return new Material[] { };
+ }
+
+ public static bool Has<T>(this Transform transform, T t) where T : Component
+ {
+ return transform.GetComponent<T>() == t;
+ }
+
+ public static T GetOrAddComponent<T>(this GameObject go) where T : Component
+ {
+ var c = go.GetComponent<T>();
+ if (c != null)
+ {
+ return c;
+ }
+ return go.AddComponent<T>();
+ }
+ }
+}
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityExtensions.cs.meta b/Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityExtensions.cs.meta
new file mode 100644
index 00000000..07785c58
--- /dev/null
+++ b/Assets/ThirdParty/VRM/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/ThirdParty/VRM/MeshUtility/Runtime/UnityPath.cs b/Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityPath.cs
new file mode 100644
index 00000000..24404741
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityPath.cs
@@ -0,0 +1,435 @@
+using System;
+using System.IO;
+using UnityEngine;
+using System.Collections.Generic;
+#if UNITY_EDITOR
+using UnityEditor;
+#endif
+
+
+namespace MeshUtility
+{
+ /// <summary>
+ /// relative path from Unity project root.
+ /// For AssetDatabase.
+ /// </summary>
+ public struct UnityPath
+ {
+ #region UnityPath
+ public string Value
+ {
+ get;
+ private set;
+ }
+
+ public override string ToString()
+ {
+ return string.Format("unity://{0}", Value);
+ }
+
+ public bool IsNull
+ {
+ get { return Value == null; }
+ }
+
+ public bool IsUnderAssetsFolder
+ {
+ get
+ {
+ if (IsNull)
+ {
+ return false;
+ }
+ return Value == "Assets" || Value.StartsWith("Assets/");
+ }
+ }
+
+ public bool IsStreamingAsset
+ {
+ get
+ {
+ if (IsNull)
+ {
+ return false;
+ }
+
+ return FullPath.StartsWith(Application.streamingAssetsPath + "/");
+ }
+ }
+
+ public string FileName
+ {
+ get { return Path.GetFileName(Value); }
+ }
+
+ public string FileNameWithoutExtension
+ {
+ get { return Path.GetFileNameWithoutExtension(Value); }
+ }
+
+ public string Extension
+ {
+ get { return Path.GetExtension(Value); }
+ }
+
+ public UnityPath Parent
+ {
+ get
+ {
+ if (IsNull)
+ {
+ return default(UnityPath);
+ }
+
+ return new UnityPath(Path.GetDirectoryName(Value));
+ }
+ }
+
+ public bool HasParent
+ {
+ get
+ {
+ return !string.IsNullOrEmpty(Value);
+ }
+ }
+
+ static readonly char[] EscapeChars = new char[]
+ {
+ '\\',
+ '/',
+ ':',
+ '*',
+ '?',
+ '"',
+ '<',
+ '>',
+ '|',
+ };
+
+ static string EscapeFilePath(string path)
+ {
+ foreach (var x in EscapeChars)
+ {
+ path = path.Replace(x, '+');
+ }
+ return path;
+ }
+
+ public UnityPath Child(string name)
+ {
+ if (IsNull)
+ {
+ throw new NotImplementedException();
+ }
+ else if (Value == "")
+ {
+ return new UnityPath(name);
+ }
+ else
+ {
+ return new UnityPath(Value + "/" + name);
+ }
+ }
+
+ public override int GetHashCode()
+ {
+ if (IsNull)
+ {
+ return 0;
+ }
+ return Value.GetHashCode();
+ }
+
+ public override bool Equals(object obj)
+ {
+ if(obj is UnityPath)
+ {
+ var rhs = (UnityPath)obj;
+ if(Value==null && rhs.Value == null)
+ {
+ return true;
+ }
+ else if (Value == null)
+ {
+ return false;
+ }
+ else if (rhs.Value == null)
+ {
+ return false;
+ }
+ else
+ {
+ return Value == rhs.Value;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Remove extension and add suffix
+ /// </summary>
+ /// <param name="prefabPath"></param>
+ /// <param name="suffix"></param>
+ /// <returns></returns>
+ public UnityPath GetAssetFolder(string suffix)
+ {
+ if (!IsUnderAssetsFolder)
+ {
+ throw new NotImplementedException();
+ }
+
+ return new UnityPath(
+ string.Format("{0}/{1}{2}",
+ Parent.Value,
+ FileNameWithoutExtension,
+ suffix
+ ));
+ }
+
+ UnityPath(string value) : this()
+ {
+ Value = value.Replace("\\", "/");
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="unityPath">Relative from unity current path. GetParent(Application.dataPath)</param>
+ /// <returns></returns>
+ public static UnityPath FromUnityPath(string unityPath)
+ {
+ if (String.IsNullOrEmpty(unityPath))
+ {
+ return new UnityPath
+ {
+ Value=""
+ };
+ }
+ return FromFullpath(Path.GetFullPath(unityPath));
+ }
+ #endregion
+
+ #region FullPath
+ static string s_basePath;
+ static string BaseFullPath
+ {
+ get
+ {
+ if (string.IsNullOrEmpty(s_basePath))
+ {
+ s_basePath = Path.GetFullPath(Application.dataPath + "/..").Replace("\\", "/");
+ }
+ return s_basePath;
+ }
+ }
+
+ static string AssetFullPath
+ {
+ get
+ {
+ return BaseFullPath + "/Assets";
+ }
+ }
+
+ public string FullPath
+ {
+ get
+ {
+ if (IsNull)
+ {
+ throw new NotImplementedException();
+ }
+ return Path.Combine(BaseFullPath, Value).Replace("\\", "/");
+ }
+ }
+
+ public bool IsFileExists
+ {
+ get { return File.Exists(FullPath); }
+ }
+
+ public bool IsDirectoryExists
+ {
+ get { return Directory.Exists(FullPath); }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="fullPath">C:/path/to/file</param>
+ /// <returns></returns>
+ public static UnityPath FromFullpath(string fullPath)
+ {
+ if(fullPath == null)
+ {
+ fullPath = "";
+ }
+ fullPath = fullPath.Replace("\\", "/");
+
+ if (fullPath == BaseFullPath) {
+ return new UnityPath
+ {
+ Value=""
+ };
+ }
+ else if(fullPath.StartsWith(BaseFullPath + "/"))
+ {
+ return new UnityPath(fullPath.Substring(BaseFullPath.Length + 1));
+ }
+ else
+ {
+ return default(UnityPath);
+ }
+ }
+
+ public static bool IsUnderAssetFolder(string fullPath)
+ {
+ return fullPath.Replace("\\", "/").StartsWith(AssetFullPath);
+ }
+ #endregion
+
+ [Obsolete("Use TraverseDir()")]
+ public IEnumerable<UnityPath> TravserseDir()
+ {
+ return TraverseDir();
+ }
+
+ public IEnumerable<UnityPath> TraverseDir()
+ {
+ if (IsDirectoryExists)
+ {
+ yield return this;
+
+ foreach(var child in ChildDirs)
+ {
+ foreach(var x in child.TraverseDir())
+ {
+ yield return x;
+ }
+ }
+ }
+ }
+
+ public IEnumerable<UnityPath> ChildDirs
+ {
+ get
+ {
+ foreach(var x in Directory.GetDirectories(FullPath))
+ {
+ yield return UnityPath.FromFullpath(x);
+ }
+ }
+ }
+
+ public IEnumerable<UnityPath> ChildFiles
+ {
+ get
+ {
+ foreach (var x in Directory.GetFiles(FullPath))
+ {
+ yield return UnityPath.FromFullpath(x);
+ }
+ }
+ }
+
+#if UNITY_EDITOR
+ public T GetImporter<T>() where T : AssetImporter
+ {
+ return AssetImporter.GetAtPath(Value) as T;
+ }
+
+ public static UnityPath FromAsset(UnityEngine.Object asset)
+ {
+ return new UnityPath(AssetDatabase.GetAssetPath(asset));
+ }
+
+ public void ImportAsset()
+ {
+ if (!IsUnderAssetsFolder)
+ {
+ throw new NotImplementedException();
+ }
+ AssetDatabase.ImportAsset(Value);
+ }
+
+ public void EnsureFolder()
+ {
+ if (IsNull)
+ {
+ throw new NotImplementedException();
+ }
+
+ if (HasParent)
+ {
+ Parent.EnsureFolder();
+ }
+
+ if (!IsDirectoryExists)
+ {
+ var parent = Parent;
+ // ensure parent
+ parent.ImportAsset();
+ // create
+ AssetDatabase.CreateFolder(
+ parent.Value,
+ Path.GetFileName(Value)
+ );
+ ImportAsset();
+ }
+ }
+
+ public UnityEngine.Object[] GetSubAssets()
+ {
+ if (!IsUnderAssetsFolder)
+ {
+ throw new NotImplementedException();
+ }
+
+ return AssetDatabase.LoadAllAssetsAtPath(Value);
+ }
+
+ public void CreateAsset(UnityEngine.Object o)
+ {
+ if (!IsUnderAssetsFolder)
+ {
+ throw new NotImplementedException();
+ }
+
+ AssetDatabase.CreateAsset(o, Value);
+ }
+
+ public void AddObjectToAsset(UnityEngine.Object o)
+ {
+ if (!IsUnderAssetsFolder)
+ {
+ throw new NotImplementedException();
+ }
+
+ AssetDatabase.AddObjectToAsset(o, Value);
+ }
+
+ public T LoadAsset<T>() where T : UnityEngine.Object
+ {
+ if (!IsUnderAssetsFolder)
+ {
+ throw new NotImplementedException();
+ }
+
+ return AssetDatabase.LoadAssetAtPath<T>(Value);
+ }
+
+ public UnityPath GenerateUniqueAssetPath()
+ {
+ if (!IsUnderAssetsFolder)
+ {
+ throw new NotImplementedException();
+ }
+
+ return new UnityPath(AssetDatabase.GenerateUniqueAssetPath(Value));
+ }
+ #endif
+ }
+}
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityPath.cs.meta b/Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityPath.cs.meta
new file mode 100644
index 00000000..f64923d8
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityPath.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 7b7af908694806c469d62ce0b5b2f06a
+timeCreated: 1532326996
+licenseType: Free
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant: