/// <summary> /// Copy mesh data from a KrablMesh meshEdges to a Unity Mesh. /// </summary> /// <param name='meshEdges'> /// The input mesh. /// </param> /// <param name='unityMesh'> /// The output Unity Mesh. Any data it contains will be overwritten. /// </param> public static void MeshEdgesToUnityMesh(KrablMesh.MeshEdges meshEdges, UnityEngine.Mesh unityMesh) { meshEdges.InvalidateDegenerateFaces(); // Ops.TriangulateWithEdges(meshEdges); int numFaces = meshEdges.faceCount(); List <ExportVertex> exVerts = new List <ExportVertex>(numFaces * 3); List <Vector3> verts = new List <Vector3>(); List <int>[] indices = new List <int> [meshEdges.numMaterials]; List <int> vertexTable = new List <int>(); // Create a list of all vertices based on face corners (= lots of duplicates) for (int material = 0; material < meshEdges.numMaterials; ++material) { indices[material] = new List <int>(); for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) { Face f = meshEdges.faces[faceIndex]; if (f.valid && f.material == material) { int cornerCount = f.cornerCount; for (int cornerIndex = 0; cornerIndex < cornerCount; ++cornerIndex) { ExportVertex ev = new ExportVertex(); ev.vertIndex = f.v[cornerIndex]; ev.cornerCount = cornerCount; ev.material = material; ev.coords = meshEdges.vertices[f.v[cornerIndex]].coords; ev.normal = f.vertexNormal[cornerIndex]; ev.uv1 = f.uv1[cornerIndex]; ev.uv2 = f.uv2[cornerIndex]; vertexTable.Add(exVerts.Count); exVerts.Add(ev); } } } } vertexTable.Sort(delegate(int a, int b) { return(ExportVertex.CompareEV(exVerts[a], exVerts[b])); }); // Create index list to collapse list to the unique verts added to the final mesh // compile unique mesh arrays List <Vector3> normals = new List <Vector3>(); List <Vector2> uv1 = new List <Vector2>(); List <Vector2> uv2 = new List <Vector2>(); List <Color> vertColors = new List <Color>(); List <BoneWeight> boneWeights = new List <BoneWeight>(); int[] uniqueTable = new int[exVerts.Count]; int numUnique = 0; for (int i = 0; i < exVerts.Count; ++i) { int exIndex = vertexTable[i]; if (i == 0 || ExportVertex.CompareEV(exVerts[vertexTable[i - 1]], exVerts[exIndex]) != 0) { verts.Add(exVerts[exIndex].coords); normals.Add(exVerts[exIndex].normal); uv1.Add(exVerts[exIndex].uv1); uv2.Add(exVerts[exIndex].uv2); Vertex v = meshEdges.vertices[exVerts[exIndex].vertIndex]; vertColors.Add(v.color); boneWeights.Add(v.boneWeight); numUnique++; } uniqueTable[exIndex] = numUnique - 1; } // Debug.Log("Num exVerts " + exVerts.Length + " num collapsed " + numUnique + " vertsCount " + verts.Count); #if false // Quad topology seams to be broken on windows directx! Disabled it for now. if (meshEdges.topology == MeshTopology.Triangles) // quads/tris only { for (int i = 0; i < exVerts.Count; i += 3) { int mat = exVerts[i].material; indices[mat].Add(uniqueTable[i]); indices[mat].Add(uniqueTable[i + 1]); indices[mat].Add(uniqueTable[i + 2]); } } else if (meshEdges.topology == MeshTopology.Quads) { for (int i = 0; i < exVerts.Count; i += 4) { int mat = exVerts[i].material; indices[mat].Add(uniqueTable[i]); indices[mat].Add(uniqueTable[i + 1]); indices[mat].Add(uniqueTable[i + 2]); indices[mat].Add(uniqueTable[i + 3]); } } else #endif { // Mixed tris/quads need to split quads int cornerCount, mat; int i0, i1, i2, i3; for (i0 = 0; i0 < exVerts.Count;) { i1 = i0 + 1; i2 = i0 + 2; cornerCount = exVerts[i0].cornerCount; mat = exVerts[i0].material; if (cornerCount == 3) { indices[mat].Add(uniqueTable[i0]); indices[mat].Add(uniqueTable[i1]); indices[mat].Add(uniqueTable[i2]); i0 += 3; } else // Quad! { i3 = i0 + 3; Vector3 diag02 = exVerts[i0].coords - exVerts[i2].coords; Vector3 diag13 = exVerts[i1].coords - exVerts[i3].coords; if (diag02.sqrMagnitude > diag13.sqrMagnitude) { // If 0-2 if shorter than 1-3 indices[mat].Add(uniqueTable[i0]); indices[mat].Add(uniqueTable[i1]); indices[mat].Add(uniqueTable[i2]); indices[mat].Add(uniqueTable[i0]); indices[mat].Add(uniqueTable[i2]); indices[mat].Add(uniqueTable[i3]); } else { indices[mat].Add(uniqueTable[i0]); indices[mat].Add(uniqueTable[i1]); indices[mat].Add(uniqueTable[i3]); indices[mat].Add(uniqueTable[i1]); indices[mat].Add(uniqueTable[i2]); indices[mat].Add(uniqueTable[i3]); } i0 += 4; } } } unityMesh.Clear(false); unityMesh.name = "KMesh"; if (verts.Count >= 65536 || exVerts.Count >= 65536 * 3) { Debug.Log("Cannot create Unity mesh from KrablMesh.MeshEdges. " + "The mesh is too large (>65k). " + "Vertices: " + verts.Count + " Triangles: " + exVerts.Count / 3); return; } unityMesh.subMeshCount = meshEdges.numMaterials; unityMesh.vertices = verts.ToArray(); unityMesh.normals = normals.ToArray(); if (meshEdges.hasVertexColors) { unityMesh.colors = vertColors.ToArray(); } if (meshEdges.hasUV1) { unityMesh.uv = uv1.ToArray(); } if (meshEdges.hasUV2) { unityMesh.uv2 = uv2.ToArray(); } if (meshEdges.hasBoneWeights) { unityMesh.bindposes = meshEdges.bindposes; unityMesh.boneWeights = boneWeights.ToArray(); } #if false if (meshEdges.topology == MeshTopology.Quads) { for (int mat = 0; mat < meshEdges.numMaterials; ++mat) { unityMesh.SetIndices(indices[mat].ToArray(), UnityEngine.MeshTopology.Quads, mat); } } else #endif { for (int mat = 0; mat < meshEdges.numMaterials; ++mat) { unityMesh.SetTriangles(indices[mat].ToArray(), mat); } } if (meshEdges.hasUV1 && meshEdges.calculateTangents) { _calculateMeshTangents(unityMesh); } }