using System.Collections.Generic; using System.Linq; using UnityEngine; namespace MeshUtility { public static class MeshIntegratorUtility { /// /// go を root としたヒエラルキーから Renderer を集めて、統合された Mesh 作成する /// /// /// BlendShapeを保持するSkinnedMeshRendererのみ/BlendShapeを保持しないSkinnedMeshRenderer + MeshRenderer /// public static MeshIntegrationResult Integrate(GameObject go, bool onlyBlendShapeRenderers) { var result = new MeshIntegrationResult(); var meshNode = new GameObject(); if (onlyBlendShapeRenderers) { meshNode.name = "MeshIntegrator(BlendShape)"; } else { meshNode.name = "MeshIntegrator"; } meshNode.transform.SetParent(go.transform, false); // レンダラから情報を集める var integrator = new MeshUtility.MeshIntegrator(); if (onlyBlendShapeRenderers) { foreach (var x in EnumerateSkinnedMeshRenderer(go.transform, true)) { integrator.Push(x); result.SourceSkinnedMeshRenderers.Add(x); } } else { foreach (var x in EnumerateSkinnedMeshRenderer(go.transform, false)) { integrator.Push(x); result.SourceSkinnedMeshRenderers.Add(x); } foreach (var x in EnumerateMeshRenderer(go.transform)) { integrator.Push(x); result.SourceMeshRenderers.Add(x); } } var mesh = new Mesh(); mesh.name = "integrated"; if (integrator.Positions.Count > ushort.MaxValue) { Debug.LogFormat("exceed 65535 vertices: {0}", integrator.Positions.Count); mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; } mesh.vertices = integrator.Positions.ToArray(); mesh.normals = integrator.Normals.ToArray(); mesh.uv = integrator.UV.ToArray(); mesh.tangents = integrator.Tangents.ToArray(); mesh.boneWeights = integrator.BoneWeights.ToArray(); mesh.subMeshCount = integrator.SubMeshes.Count; for (var i = 0; i < integrator.SubMeshes.Count; ++i) { mesh.SetIndices(integrator.SubMeshes[i].Indices.ToArray(), MeshTopology.Triangles, i); } mesh.bindposes = integrator.BindPoses.ToArray(); if (onlyBlendShapeRenderers) { integrator.AddBlendShapesToMesh(mesh); } var integrated = meshNode.AddComponent(); integrated.sharedMesh = mesh; integrated.sharedMaterials = integrator.SubMeshes.Select(x => x.Material).ToArray(); integrated.bones = integrator.Bones.ToArray(); result.IntegratedRenderer = integrated; return result; } public static IEnumerable EnumerateSkinnedMeshRenderer(Transform root, bool hasBlendShape) { foreach (var x in Traverse(root)) { var renderer = x.GetComponent(); if (renderer != null && renderer.gameObject.activeInHierarchy && renderer.sharedMesh != null && renderer.enabled && renderer.sharedMesh.blendShapeCount > 0 == hasBlendShape) { yield return renderer; } } } public static IEnumerable EnumerateMeshRenderer(Transform root) { foreach (var x in Traverse(root)) { var renderer = x.GetComponent(); var filter = x.GetComponent(); if (renderer != null && filter != null && renderer.gameObject.activeInHierarchy && filter.sharedMesh != null) { yield return renderer; } } } private static IEnumerable Traverse(Transform parent) { if (parent.gameObject.activeSelf) { yield return parent; foreach (Transform child in parent) { foreach (var x in Traverse(child)) { yield return x; } } } } } }