public static List <Mesh> ConvertTerrain2Mesh(Terrain terrain, IndexFormat format, int splitCount = 0, int lod = 0) { var terrainData = terrain.terrainData; var width = GetTerrainResolution(terrainData, format, lod, splitCount); var height = width; var size = terrainData.size; var tileGridNum = (int)Mathf.Pow(2, splitCount); var maxWidth = (width - 1) * tileGridNum + 1; var maxHeight = maxWidth; var meshScale = new Vector3(size.x / (width - 1) / tileGridNum, 1, size.z / (height - 1) / tileGridNum); // The function returns a two-dimensional array of size [yCount, xCount] var heights = terrainData.GetInterpolatedHeights(0, 0, maxWidth, maxHeight, 1f / (maxWidth - 1), 1f / (maxHeight - 1)); var meshes = new List <Mesh>(tileGridNum * tileGridNum); for (int chunkI = 0; chunkI < tileGridNum; chunkI++) { for (int chunkJ = 0; chunkJ < tileGridNum; chunkJ++) { var meshData = new QuadMeshData(width, height); // 左下角开始,从下往上,从左往右添加顶点 for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { // 共用一条边 var widthIndex = chunkI * (width - 1) + i; var heightIndex = chunkJ * (height - 1) + j; // meshData.AddVertex(i, j, heights[heightIndex, widthIndex], meshScale); meshData.AddVertex(i, j, heights[heightIndex, widthIndex], meshScale, new Vector2(widthIndex / (maxWidth - 1f), heightIndex / (maxHeight - 1f))); } } // 正方形顺序随顶点顺序,三角形顺时针方向为模型的正面 for (int i = 0; i < width - 1; i++) { for (int j = 0; j < height - 1; j++) { var a = i + j * width; var b = i + (j + 1) * width; var c = (i + 1) + (j + 1) * width; var d = (i + 1) + j * width; meshData.AddTriangle(a, b, c); meshData.AddTriangle(a, c, d); } } meshes.Add(meshData.CreateMesh(format)); } } return(meshes); }
public QuadMeshData Parse(TextAsset OBJFile) { lines = OBJFile.text.Split('\n'); currLine = 0; parsedData = new QuadMeshData(); string[] line; while ((line = getNextLine()) != null) { // Parse vertex position if (line[KEYWORD] == "v") { var vertex = new Vector3(float.Parse(line[X], CultureInfo.InvariantCulture), float.Parse(line[Y], CultureInfo.InvariantCulture), float.Parse(line[Z], CultureInfo.InvariantCulture)); parsedData.vertices.Add(vertex); } // Parse face vertex indices else if (line[KEYWORD] == "f") { int vertexIndex; string vertexIndexString; Vector4 quad = new Vector4(); for (int i = 1; i <= 4; i++) { vertexIndexString = line[i]; if (vertexIndexString.Contains("//")) { vertexIndexString = vertexIndexString.Split(new string[] { "//" }, StringSplitOptions.None)[0]; } // Remove 1 from index, in OBJ format indices start at 1 and not 0 vertexIndex = int.Parse(vertexIndexString, CultureInfo.InvariantCulture) - 1; quad[i - 1] = vertexIndex; if (vertexIndex > parsedData.vertices.Count) { PrintError("Vertex index out of bounds"); } } parsedData.quads.Add(quad); } // Ignore comments and other OBJ data else { // continue } } Debug.Log("Finished Parsing OBJ with " + parsedData.vertices.Count + " vertices " + (parsedData.quads.Count / 4) + " quads"); return(parsedData); }
// Returns a QuadMeshData representing the input mesh after one iteration of Catmull-Clark subdivision. public static QuadMeshData Subdivide(QuadMeshData quadMeshData) { // Create and initialize a CCMeshData corresponding to the given QuadMeshData CCMeshData meshData = new CCMeshData(); meshData.points = quadMeshData.vertices; meshData.faces = quadMeshData.quads; meshData.edges = GetEdges(meshData); meshData.facePoints = GetFacePoints(meshData); meshData.edgePoints = GetEdgePoints(meshData); meshData.newPoints = GetNewPoints(meshData); // Combine facePoints, edgePoints and newPoints into a subdivided QuadMeshData return(CreateNewQuadMeshData(meshData)); }
// Returns a QuadMeshData representing the input mesh after one iteration of Catmull-Clark subdivision. public static QuadMeshData Subdivide(QuadMeshData quadMeshData) { // Create and initialize a CCMeshData corresponding to the given QuadMeshData CCMeshData meshData = new CCMeshData(); meshData.points = quadMeshData.vertices; meshData.faces = quadMeshData.quads; meshData.edges = GetEdges(meshData); meshData.facePoints = GetFacePoints(meshData); meshData.edgePoints = GetEdgePoints(meshData); meshData.newPoints = GetNewPoints(meshData); // Combine facePoints, edgePoints and newPoints into a subdivided QuadMeshData // Your implementation here... var quads = new List <Vector4>(); var vertices = new List <Vector3>(); var vertToIdx = getPointDict(meshData, vertices); var t = edges_dict(meshData); for (int i = 0; i < meshData.facePoints.Count; i++) { var fp = vertToIdx[meshData.facePoints[i]]; var points = meshData.faces[i]; for (int p = 0; p < 4; p++) { var np = vertToIdx[meshData.newPoints[(int)points[p]]]; var next_point = (int)points[(p + 1) % 4]; var original_point_cur = (int)points[p]; var key1 = new Vector2(i, original_point_cur); var key2 = new Vector2(i, next_point); var cur_original_edges = t[key1]; var next_edges = t[key2]; int right = 0; for (int idx1 = 0; idx1 < cur_original_edges.Count; idx1++) { for (int idx2 = 0; idx2 < next_edges.Count; idx2++) { if (cur_original_edges[idx1] == next_edges[idx2]) { right = idx1; break; } } } var quad = new Vector4(fp, vertToIdx[meshData.edgePoints[(int)cur_original_edges[(right + 1) % 2]]], np, vertToIdx[meshData.edgePoints[(int)cur_original_edges[right % 2]]]); quads.Add(quad); } } return(new QuadMeshData(vertices, quads)); }
// Returns a QuadMeshData representing the input mesh after one iteration of Catmull-Clark subdivision. public static QuadMeshData Subdivide(QuadMeshData quadMeshData) { // Create and initialize a CCMeshData corresponding to the given QuadMeshData CCMeshData meshData = new CCMeshData(); meshData.points = quadMeshData.vertices; meshData.faces = quadMeshData.quads; meshData.edges = GetEdges(meshData); meshData.facePoints = GetFacePoints(meshData); meshData.edgePoints = GetEdgePoints(meshData); meshData.newPoints = GetNewPoints(meshData); List <List <int> > faceEdges = new List <List <int> >(); for (int i = 0; i < meshData.faces.Count; ++i) { faceEdges.Add(new List <int>()); } for (int i = 0; i < meshData.edges.Count; ++i) { faceEdges[(int)meshData.edges[i][2]].Add(i); faceEdges[(int)meshData.edges[i][3]].Add(i); } List <List <Vector2> > faceEdgePoints = new List <List <Vector2> >(); for (int i = 0; i < faceEdges.Count; ++i) { faceEdgePoints.Add(new List <Vector2>()); for (int j = 0; j < 4; ++j) { if (i == meshData.edges[faceEdges[i][j]][2]) { faceEdgePoints[i].Add(new Vector2(meshData.edges[faceEdges[i][j]][0], meshData.edges[faceEdges[i][j]][1])); } else { faceEdgePoints[i].Add(new Vector2(meshData.edges[faceEdges[i][j]][1], meshData.edges[faceEdges[i][j]][0])); } } } List <Vector3> newPoints = meshData.facePoints.Concat(meshData.edgePoints).Concat(meshData.newPoints).ToList(); int edgePointStart = meshData.facePoints.Count; int newPointStart = edgePointStart + meshData.edgePoints.Count; List <Vector4> newFaces = new List <Vector4>(); for (int i = 0; i < faceEdges.Count; ++i) { for (int j = 0; j < 3; ++j) { for (int k = j + 1; k < 4; ++k) { if (faceEdgePoints[i][j][0] == faceEdgePoints[i][k][1]) { newFaces.Add(new Vector4(i, faceEdges[i][k] + edgePointStart, faceEdgePoints[i][j][0] + newPointStart, faceEdges[i][j] + edgePointStart)); } else if (faceEdgePoints[i][j][1] == faceEdgePoints[i][k][0]) { newFaces.Add(new Vector4(i, faceEdges[i][j] + edgePointStart, faceEdgePoints[i][j][1] + newPointStart, faceEdges[i][k] + edgePointStart)); } } } } return(new QuadMeshData(newPoints, newFaces)); }
public void Subdivide() { meshData = CatmullClark.Subdivide(meshData); meshFilter.mesh = meshData.ToUnityMesh(); }
// Loads a given OBJ file, calculates its surface normals and displays it public void ShowMesh() { meshData = parser.Parse(QuadOBJFile); meshFilter.mesh = meshData.ToUnityMesh(); }