public Submesh3D Clone() { var clone = new Submesh3D(); clone.Mesh = Mesh.ShallowClone(); clone.BoneNames = new List <string>(BoneNames); clone.BoneBindPoses = new List <Matrix44>(BoneBindPoses); clone.Material = Material.Clone(); clone.Owner = null; return(clone); }
public static Submesh3D Combine(params Submesh3D[] submeshes) { var firstMesh = submeshes.First(); var newSubmesh = new Submesh3D { Material = firstMesh.Material }; var numVertices = submeshes.Select(sm => sm.Mesh).Sum(m => m.Vertices.Length); var numIndices = submeshes.Select(sm => sm.Mesh).Sum(m => m.Indices.Length); var outVertices = new Mesh3D.Vertex[numVertices]; var outIndices = new ushort[numIndices]; var currentVertex = 0; var currentIndex = 0; foreach (var sm in submeshes) { var m = sm.Mesh; var indices = m.Indices; for (var i = currentIndex; i < currentIndex + indices.Length; i++) { outIndices[i] = (ushort)(indices[i - currentIndex] + currentVertex); } var idx = (byte)newSubmesh.BoneNames.Count; for (var i = 0; i < sm.BoneNames.Count; i++) { newSubmesh.BoneNames.Add(sm.BoneNames[i]); newSubmesh.BoneBindPoses.Add(sm.BoneBindPoses[i]); } currentIndex += indices.Length; var vertices = m.Vertices; vertices.CopyTo(outVertices, currentVertex); for (var j = currentVertex; j < currentVertex + vertices.Length; j++) { var bi = outVertices[j].BlendIndices; bi.Index0 += idx; bi.Index1 += idx; bi.Index2 += idx; bi.Index3 += idx; outVertices[j].BlendIndices = bi; } currentVertex += vertices.Length; } newSubmesh.Mesh = new Mesh <Mesh3D.Vertex> { Vertices = outVertices, Indices = outIndices, AttributeLocations = firstMesh.Mesh.AttributeLocations, DirtyFlags = MeshDirtyFlags.All }; return(newSubmesh); }
private void MergeMeshes(Dictionary <int, List <Mesh3D> > map, Node3D model) { const int meshLimit = ushort.MaxValue; const int bonesLimit = 50; if (map.Count == 0) { return; } foreach (var pair in map) { var materialsMap = new Dictionary <IMaterial, Dictionary <Mesh3D, List <Submesh3D> > >(); foreach (var mesh in pair.Value) { foreach (var submesh in mesh.Submeshes) { var material = submesh.Material; if (!materialsMap.ContainsKey(material)) { materialsMap[material] = new Dictionary <Mesh3D, List <Submesh3D> >(); } if (!materialsMap[material].ContainsKey(mesh)) { materialsMap[material][mesh] = new List <Submesh3D>(); } materialsMap[material][mesh].Add(submesh); } } foreach (var meshDescriptor in materialsMap.Values) { var first = meshDescriptor.First().Key; var newMesh = new Mesh3D { Opaque = first.Opaque, CullMode = first.CullMode, SkinningMode = first.SkinningMode, HitTestTarget = first.HitTestTarget }; Submesh3D curSubmesh = null; foreach (var meshAndSubmeshes in meshDescriptor) { var meshIdx = 0; while (meshIdx < meshAndSubmeshes.Value.Count) { var submeshToMerge = meshAndSubmeshes.Value[meshIdx]; var meshLocalTransform = meshAndSubmeshes.Key.LocalTransform; MeshUtils.TransformVertices(submeshToMerge.Mesh, (ref Mesh3D.Vertex v) => { v.Pos = meshLocalTransform.TransformVector(v.Pos); }); if (curSubmesh == null) { curSubmesh = submeshToMerge; meshAndSubmeshes.Value.RemoveAt(meshIdx); meshIdx++; continue; } if (curSubmesh.Mesh.Indices.Length + submeshToMerge.Mesh.Indices.Length < meshLimit && curSubmesh.BoneNames.Count + submeshToMerge.BoneNames.Count < bonesLimit ) { curSubmesh = Combine(curSubmesh, submeshToMerge); meshAndSubmeshes.Value.RemoveAt(meshIdx); } else { newMesh.Submeshes.Add(curSubmesh); curSubmesh = null; } } newMesh.Id += (newMesh.Id == null ? "" : "|") + meshAndSubmeshes.Key.Id; } newMesh.Submeshes.Add(curSubmesh); model.AddNode(newMesh); } foreach (var mesh in materialsMap.Values.SelectMany(kv => kv.Keys)) { mesh.UnlinkAndDispose(); } } }