diff --git a/Scripts/SkinnedMeshUtility/Editor/MeshIntegrator.cs b/Scripts/SkinnedMeshUtility/Editor/MeshIntegrator.cs
index 78b0f1e5f..7b2575416 100644
--- a/Scripts/SkinnedMeshUtility/Editor/MeshIntegrator.cs
+++ b/Scripts/SkinnedMeshUtility/Editor/MeshIntegrator.cs
@@ -1,359 +1,458 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using UnityEditor;
-using UnityEngine;
-
-
-namespace VRM
-{
- ///
- /// 複数のメッシュをまとめる
- ///
- [DisallowMultipleComponent]
- public static class MeshIntegrator
- {
- const string MENU_KEY = "GameObject/UnityEditorScripts/MeshIntegrator";
- const int MENU_PRIORITY = 0;
- const string ASSET_SUFFIX = ".mesh.asset";
- const string ASSET_WITH_BLENDSHAPE_SUFFIX = ".blendshape.asset";
-
- [MenuItem(MENU_KEY, true, MENU_PRIORITY)]
- private static bool ExportValidate()
- {
- return Selection.activeObject != null && Selection.activeObject is GameObject;
- }
-
- [MenuItem(MENU_KEY, false, MENU_PRIORITY)]
- private static void ExportFromMenu()
- {
- var go = Selection.activeObject as GameObject;
-
- Integrate(go);
- }
-
- public static SkinnedMeshRenderer Integrate(GameObject go)
- {
- var without_blendshape = _Integrate(go, false);
- if (without_blendshape == null)
- {
- return null;
-
- }
-
- // save mesh to Assets
- var assetPath = string.Format("{0}{1}", go.name, ASSET_SUFFIX);
- var prefab = PrefabUtility.GetPrefabParent(go);
- if (prefab != null)
- {
- var prefabPath = AssetDatabase.GetAssetPath(prefab);
- assetPath = string.Format("{0}/{1}{2}",
- Path.GetDirectoryName(prefabPath),
- Path.GetFileNameWithoutExtension(prefabPath),
- ASSET_SUFFIX
- );
- }
-
- Debug.LogFormat("CreateAsset: {0}", assetPath);
- AssetDatabase.CreateAsset(without_blendshape.sharedMesh, assetPath);
- return without_blendshape;
- }
-
- struct SubMesh
- {
- public List Indices;
- public Material Material;
- }
-
- class BlendShape
- {
- public int VertexOffset;
- public string Name;
- public float FrameWeight;
- public Vector3[] Positions;
- public Vector3[] Normals;
- public Vector3[] Tangents;
- }
-
- class Integrator
- {
- public List Renderers { get; private set; }
- public List Positions { get; private set; }
- public List Normals { get; private set; }
- public List UV { get; private set; }
- public List Tangents { get; private set; }
- public List BoneWeights { get; private set; }
-
- public List SubMeshes
- {
- get;
- private set;
- }
-
- public List BindPoses { get; private set; }
- public List Bones { get; private set; }
-
- public List BlendShapes { get; private set; }
- public void AddBlendShapesToMesh(Mesh mesh)
- {
- Dictionary map = new Dictionary();
-
- foreach (var x in BlendShapes)
- {
- BlendShape bs = null;
- if (!map.TryGetValue(x.Name, out bs))
- {
- bs = new BlendShape();
- bs.Positions = Positions.ToArray();
- bs.Normals = Normals.ToArray();
- bs.Tangents = Tangents.Select(y => (Vector3)y).ToArray();
- 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 Integrator()
- {
- Renderers = new List();
-
- Positions = new List();
- Normals = new List();
- UV = new List();
- Tangents = new List();
- BoneWeights = new List();
-
- SubMeshes = new List();
-
- BindPoses = new List();
- Bones = new List();
-
- BlendShapes = new List();
- }
-
- 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(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());
- }
- else
- {
- BoneWeights.AddRange(Enumerable.Range(0, mesh.vertexCount).Select(x => new BoneWeight()).ToArray());
- }
-
- BindPoses.AddRange(mesh.bindposes);
- Bones.AddRange(renderer.bones);
-
- 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,
- });
- }
- }
- }
-
- 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;
- }
- }
- }
- }
-
- static public IEnumerable EnumerateRenderer(Transform root, bool hasBlendShape)
- {
- foreach (var x in Traverse(root))
- {
- var renderer = x.GetComponent();
- if (renderer != null)
- {
- if (renderer.sharedMesh != null)
- {
- if (renderer.gameObject.activeSelf)
- {
- if (renderer.sharedMesh.blendShapeCount > 0 == hasBlendShape)
- {
- yield return renderer;
- }
- }
- }
- }
- }
- }
-
- static IEnumerable Ancestors(Transform self)
- {
- yield return self;
-
- if (self.parent != null)
- {
- foreach (var x in Ancestors(self.parent))
- {
- yield return x;
- }
- }
- }
-
- static SkinnedMeshRenderer _Integrate(GameObject go, bool hasBlendShape)
- {
- var meshNode = new GameObject();
- if (hasBlendShape)
- {
- meshNode.name = "MeshIntegrator(BlendShape)";
- }
- else
- {
- meshNode.name = "MeshIntegrator";
- }
- meshNode.transform.SetParent(go.transform, false);
-
- var renderers = EnumerateRenderer(go.transform, hasBlendShape).ToArray();
-
- // Root objectを選出する
- var root = renderers.Select(x => x.rootBone != null ? x.rootBone : x.transform)
- .Select(x => Ancestors(x).Reverse().ToArray())
- .Aggregate((a, b) =>
- {
- int i = 0;
- for(; i 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();
- 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 (hasBlendShape)
- {
- integrator.AddBlendShapesToMesh(mesh);
- }
-
- var integrated = meshNode.AddComponent();
- integrated.sharedMesh = mesh;
- integrated.sharedMaterials = integrator.SubMeshes.Select(x => x.Material).ToArray();
- integrated.bones = integrator.Bones.ToArray();
-
- return integrated;
- }
- }
-}
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using UnityEditor;
+using UnityEngine;
+
+
+namespace VRM
+{
+ ///
+ /// 複数のメッシュをまとめる
+ ///
+ [DisallowMultipleComponent]
+ public static class MeshIntegrator
+ {
+ const string MENU_KEY = "GameObject/UnityEditorScripts/MeshIntegrator";
+ const int MENU_PRIORITY = 0;
+ const string ASSET_SUFFIX = ".mesh.asset";
+ const string ASSET_WITH_BLENDSHAPE_SUFFIX = ".blendshape.asset";
+
+ [MenuItem(MENU_KEY, true, MENU_PRIORITY)]
+ private static bool ExportValidate()
+ {
+ return Selection.activeObject != null && Selection.activeObject is GameObject;
+ }
+
+ [MenuItem(MENU_KEY, false, MENU_PRIORITY)]
+ private static void ExportFromMenu()
+ {
+ var go = Selection.activeObject as GameObject;
+
+ Integrate(go);
+ }
+
+ public static SkinnedMeshRenderer Integrate(GameObject go)
+ {
+ var without_blendshape = _Integrate(go, false);
+ if (without_blendshape == null)
+ {
+ return null;
+
+ }
+
+ // save mesh to Assets
+ var assetPath = string.Format("{0}{1}", go.name, ASSET_SUFFIX);
+ var prefab = PrefabUtility.GetPrefabParent(go);
+ if (prefab != null)
+ {
+ var prefabPath = AssetDatabase.GetAssetPath(prefab);
+ assetPath = string.Format("{0}/{1}_{2}{3}",
+ Path.GetDirectoryName(prefabPath),
+ Path.GetFileNameWithoutExtension(prefabPath),
+ go.name,
+ ASSET_SUFFIX
+ );
+ }
+ else
+ {
+ assetPath = string.Format("Assets/{0}{1}", go.name, ASSET_SUFFIX);
+ }
+
+ Debug.LogFormat("CreateAsset: {0}", assetPath);
+ AssetDatabase.CreateAsset(without_blendshape.sharedMesh, assetPath);
+ return without_blendshape;
+ }
+
+ struct SubMesh
+ {
+ public List Indices;
+ public Material Material;
+ }
+
+ class BlendShape
+ {
+ public int VertexOffset;
+ public string Name;
+ public float FrameWeight;
+ public Vector3[] Positions;
+ public Vector3[] Normals;
+ public Vector3[] Tangents;
+ }
+
+ class Integrator
+ {
+// public List Renderers { get; private set; }
+ public List Positions { get; private set; }
+ public List Normals { get; private set; }
+ public List UV { get; private set; }
+ public List Tangents { get; private set; }
+ public List BoneWeights { get; private set; }
+
+ public List SubMeshes
+ {
+ get;
+ private set;
+ }
+
+ public List BindPoses { get; private set; }
+ public List Bones { get; private set; }
+
+ public List BlendShapes { get; private set; }
+ public void AddBlendShapesToMesh(Mesh mesh)
+ {
+ Dictionary map = new Dictionary();
+
+ foreach (var x in BlendShapes)
+ {
+ BlendShape bs = null;
+ if (!map.TryGetValue(x.Name, out bs))
+ {
+ bs = new BlendShape();
+ bs.Positions = Positions.ToArray();
+ bs.Normals = Normals.ToArray();
+ bs.Tangents = Tangents.Select(y => (Vector3)y).ToArray();
+ 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 Integrator()
+ {
+// Renderers = new List();
+
+ Positions = new List();
+ Normals = new List();
+ UV = new List();
+ Tangents = new List();
+ BoneWeights = new List();
+
+ SubMeshes = new List();
+
+ BindPoses = new List();
+ Bones = new List();
+
+ BlendShapes = new List();
+ }
+
+ 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();
+ 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());
+ }
+ else
+ {
+ BoneWeights.AddRange(Enumerable.Range(0, mesh.vertexCount).Select(x => new BoneWeight()).ToArray());
+ }
+
+ BindPoses.AddRange(mesh.bindposes);
+ Bones.AddRange(renderer.bones);
+
+ 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,
+ });
+ }
+ }
+ }
+
+ 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;
+ }
+ }
+ }
+ }
+
+ static public IEnumerable EnumerateRenderer(Transform root, bool hasBlendShape)
+ {
+ foreach (var x in Traverse(root))
+ {
+ var renderer = x.GetComponent();
+ if (renderer != null)
+ {
+ if (renderer.sharedMesh != null)
+ {
+ if (renderer.gameObject.activeSelf)
+ {
+ if (renderer.sharedMesh.blendShapeCount > 0 == hasBlendShape)
+ {
+ yield return renderer;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ static IEnumerable EnumerateMeshRenderer(Transform root)
+ {
+ foreach (var x in Traverse(root))
+ {
+ var renderer = x.GetComponent();
+ if (renderer != null)
+ {
+ var filter = x.GetComponent();
+ if (filter != null && filter.sharedMesh != null && renderer.gameObject.activeSelf)
+ {
+ yield return renderer;
+ }
+ }
+ }
+ }
+
+ static IEnumerable Ancestors(Transform self)
+ {
+ yield return self;
+
+ if (self.parent != null)
+ {
+ foreach (var x in Ancestors(self.parent))
+ {
+ yield return x;
+ }
+ }
+ }
+
+ static SkinnedMeshRenderer _Integrate(GameObject go, bool hasBlendShape)
+ {
+ var meshNode = new GameObject();
+ if (hasBlendShape)
+ {
+ meshNode.name = "MeshIntegrator(BlendShape)";
+ }
+ else
+ {
+ meshNode.name = "MeshIntegrator";
+ }
+ meshNode.transform.SetParent(go.transform, false);
+
+ var renderers = EnumerateRenderer(go.transform, hasBlendShape).ToArray();
+
+ // Root objectを選出する
+ var root = renderers.Select(x => x.rootBone != null ? x.rootBone : x.transform)
+ .Select(x => Ancestors(x).Reverse().ToArray())
+ .Aggregate((a, b) =>
+ {
+ int i = 0;
+ for(; i 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();
+ 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 (hasBlendShape)
+ {
+ integrator.AddBlendShapesToMesh(mesh);
+ }
+
+ var integrated = meshNode.AddComponent();
+ integrated.sharedMesh = mesh;
+ integrated.sharedMaterials = integrator.SubMeshes.Select(x => x.Material).ToArray();
+ integrated.bones = integrator.Bones.ToArray();
+
+ return integrated;
+ }
+ }
+}