/// <summary> /// Copies a Unity Mesh to a KrablMesh.MeshEdges. /// </summary> /// <param name='unityMesh'> /// The Unity Mesh to use as input. /// </param> /// <param name='meshEdges'> /// The KrablMesh.meshEdges to fill with the data from the input mesh. Needs to be empty. /// </param> /// <param name='tolerance'> /// The maximum difference between two values (vertex coordinates, normal coordinates) to treat as begin equal. /// Some modelling software outputs float values that are only almost the same when they should be the same. /// In this case using a tolerance of about 1e-5f can fix problems. /// </param> public static void UnityMeshToMeshEdges(UnityEngine.Mesh unityMesh, KrablMesh.MeshEdges meshEdges, float tolerance = 0.0f) { Vector3[] verts = unityMesh.vertices; Vector3[] normals = unityMesh.normals; Color[] vertColors = unityMesh.colors; BoneWeight[] boneWeights = unityMesh.boneWeights; Vector2[] uv1 = unityMesh.uv; Vector2[] uv2 = unityMesh.uv2; meshEdges.Clear(); meshEdges.numMaterials = unityMesh.subMeshCount; meshEdges.equalityTolerance = tolerance; int numVerts = verts.Length; meshEdges.hasVertexColors = (vertColors.Length == numVerts); meshEdges.bindposes = unityMesh.bindposes; meshEdges.hasBoneWeights = (meshEdges.bindposes != null && boneWeights.Length == numVerts); meshEdges.hasUV1 = (uv1.Length == numVerts); meshEdges.hasUV2 = (uv2.Length == numVerts); int i; for (i = 0; i < numVerts; ++i) { meshEdges.AddVertex(verts[i]); } if (meshEdges.hasVertexColors) { for (i = 0; i < numVerts; ++i) { meshEdges.vertices[i].color = vertColors[i]; } } if (meshEdges.hasBoneWeights) { for (i = 0; i < numVerts; ++i) { meshEdges.vertices[i].boneWeight = boneWeights[i]; } } // Figure out if this is a unity quad mesh. // theoretically this could be different per material bool quad = true; for (int m = 0; m < meshEdges.numMaterials; ++m) { if (unityMesh.GetTopology(m) != UnityEngine.MeshTopology.Quads) { quad = false; break; } } int v0, v1, v2, v3; for (int m = 0; m < meshEdges.numMaterials; ++m) { if (quad) { int[] indices = unityMesh.GetIndices(m); int num = indices.Length; for (i = 0; i < num;) { v0 = indices[i++]; v1 = indices[i++]; v2 = indices[i++]; v3 = indices[i++]; Face f = new Face(v0, v1, v2, v3); meshEdges.AddFace(f); f.vertexNormal[0] = normals[v0]; f.vertexNormal[1] = normals[v1]; f.vertexNormal[2] = normals[v2]; f.vertexNormal[3] = normals[v3]; if (meshEdges.hasUV1) { f.uv1[0] = uv1[v0]; f.uv1[1] = uv1[v1]; f.uv1[2] = uv1[v2]; f.uv1[3] = uv1[v3]; } if (meshEdges.hasUV2) { f.uv2[0] = uv2[v0]; f.uv2[1] = uv2[v1]; f.uv2[2] = uv2[v2]; f.uv2[3] = uv2[v3]; } f.material = m; } } else { int[] tris = unityMesh.GetTriangles(m); int num = tris.Length; for (i = 0; i < num;) { v0 = tris[i++]; v1 = tris[i++]; v2 = tris[i++]; Face f = new Face(v0, v1, v2); meshEdges.AddFace(f); f.vertexNormal[0] = normals[v0]; f.vertexNormal[1] = normals[v1]; f.vertexNormal[2] = normals[v2]; if (meshEdges.hasUV1) { f.uv1[0] = uv1[v0]; f.uv1[1] = uv1[v1]; f.uv1[2] = uv1[v2]; } if (meshEdges.hasUV2) { f.uv2[0] = uv2[v0]; f.uv2[1] = uv2[v1]; f.uv2[2] = uv2[v2]; } f.material = m; } } } KrablMesh.Ops.RemoveDoubleVertices(meshEdges); meshEdges.GenerateEdgeList(); meshEdges.CalculateEdgeLinkedFaces(); meshEdges.topology = quad ? MeshTopology.Quads : MeshTopology.Triangles; KrablMesh.CreaseDetect.MarkCreasesFromFaceNormals(meshEdges); }
public void Subdivide(ref MeshEdges mesh) { int i, j; int numVerts = mesh.vertCount(); int numFaces = mesh.faceCount(); int numEdges = mesh.edgeCount(); mesh.CalculateEdgeLinkedFaces(); _calculateVertexPositions(mesh); // TODO:don't generate a new mesh... just add the verts to the old mesh = faster and uses less memory MeshEdges newMesh = new MeshEdges(); int faceOffset = numVerts; int edgeOffset = numVerts + numFaces; float[] edgeRatio = new float[numEdges]; // Add vertices to new mesh, precalculate stuff for (i = 0; i < numVerts; ++i) { newMesh.AddVertex(vertPoints[i]); } for (i = 0; i < numFaces; ++i) { newMesh.AddVertex(facePoints[i]); } for (i = 0; i < numEdges; ++i) { int vertexIndex = newMesh.AddVertex(edgePoints[i]); Vertex nv = newMesh.vertices[vertexIndex]; Vertex ov0 = mesh.vertices[mesh.edges[i].v[0]]; Vertex ov1 = mesh.vertices[mesh.edges[i].v[1]]; edgeRatio[i] = KrablMesh.UnityUtils.ProjectedRatioOfPointOnVector(nv.coords, ov0.coords, ov1.coords); } if (mesh.hasBoneWeights) { for (i = 0; i < numVerts; ++i) { newMesh.vertices[i].boneWeight = mesh.vertices[i].boneWeight; } for (i = 0; i < numEdges; ++i) { int[] vi = mesh.edges[i].v; newMesh.vertices[edgeOffset + i].boneWeight = KrablMesh.UnityUtils.BoneWeightLerp( mesh.vertices[vi[0]].boneWeight, mesh.vertices[vi[1]].boneWeight, edgeRatio[i]); } for (i = 0; i < numFaces; ++i) { newMesh.vertices[faceOffset + i].boneWeight = mesh.CalculateFaceCenterBoneWeight(i); } } if (mesh.hasVertexColors) { for (i = 0; i < numVerts; ++i) { newMesh.vertices[i].color = mesh.vertices[i].color; } for (i = 0; i < numEdges; ++i) { int[] vi = mesh.edges[i].v; newMesh.vertices[edgeOffset + i].color = Color.Lerp( mesh.vertices[vi[0]].color, mesh.vertices[vi[1]].color, edgeRatio[i]); } for (i = 0; i < numFaces; ++i) { newMesh.vertices[faceOffset + i].color = mesh.CalculateFaceCenterColor(i); } } // Create the faces Face nf, of; int g, h; int a, b, c, d; for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) { of = mesh.faces[faceIndex]; if (of.valid) { h = of.cornerCount - 1; // scan through with indices g, h, i g = of.cornerCount - 2; Vector2 centerUV1 = mesh.CalculateFaceCenterUV1(faceIndex); Vector2 centerUV2 = mesh.CalculateFaceCenterUV2(faceIndex); Vector3 centerVertexNormal = mesh.CalculateFaceCenterVertexNormal(faceIndex); for (i = 0; i < of.cornerCount; ++i) { int edgeIndex0 = mesh.EdgeIndexForVertices(of.v[h], of.v[i]); if (edgeIndex0 < 0) { continue; } float ratio0 = edgeRatio[edgeIndex0]; if (mesh.edges[edgeIndex0].v[0] == of.v[h]) { a = h; b = i; // interpolation indexes. 1- ratio gives inaccurate results (floating point problems) } else { a = i; b = h; } int edgeIndex1 = mesh.EdgeIndexForVertices(of.v[g], of.v[h]); if (edgeIndex1 < 0) { continue; } float ratio1 = edgeRatio[edgeIndex1]; if (mesh.edges[edgeIndex1].v[0] == of.v[g]) { c = g; d = h; } else { c = h; d = g; } nf = new Face( of.v[h], // corner point edgeOffset + edgeIndex0, faceOffset + faceIndex, // center point edgeOffset + edgeIndex1 ); nf.uv1[0] = of.uv1[h]; nf.uv1[1] = Vector2.Lerp(of.uv1[a], of.uv1[b], ratio0); nf.uv1[2] = centerUV1; nf.uv1[3] = Vector2.Lerp(of.uv1[c], of.uv1[d], ratio1); if (mesh.hasUV2) { nf.uv2[0] = of.uv2[h]; nf.uv2[1] = Vector2.Lerp(of.uv2[a], of.uv2[b], ratio0); nf.uv2[2] = centerUV2; nf.uv2[3] = Vector2.Lerp(of.uv2[c], of.uv2[d], ratio1); } if (!recalculateNormals) { nf.vertexNormal[0] = of.vertexNormal[h]; nf.vertexNormal[1] = Vector3.Lerp(of.vertexNormal[a], of.vertexNormal[b], ratio0); nf.vertexNormal[2] = centerVertexNormal; nf.vertexNormal[3] = Vector3.Lerp(of.vertexNormal[c], of.vertexNormal[d], ratio1); } nf.material = of.material; newMesh.AddFace(nf); g = h; h = i; } } } newMesh.hasUV1 = mesh.hasUV1; newMesh.hasUV2 = mesh.hasUV2; newMesh.hasBoneWeights = mesh.hasBoneWeights; newMesh.bindposes = mesh.bindposes; newMesh.numMaterials = mesh.numMaterials; newMesh.hasVertexColors = mesh.hasVertexColors; newMesh.topology = MeshTopology.Quads; newMesh.GenerateEdgeList(); newMesh.GenerateEdgeTopology(); // Need to copy edge information from the original mesh to the new mesh // Every edge of the original mesh now has two parts int edgePointIndex; for (i = 0; i < numEdges; ++i) { Edge e = mesh.edges[i]; edgePointIndex = edgeOffset + i; // as newmesh was just constructed, we know the correct vertex index of the edge center point! for (j = 0; j < 2; ++j) { int eindex = newMesh.EdgeIndexForVertices(e.v[j], edgePointIndex); // Copy attributes (just crease for now) newMesh.edges[eindex].crease = e.crease; } } mesh = newMesh; }