public static MeshData GenerateTerrainMesh(float[,] heightMap, float heightMultiplier, AnimationCurve heightCurve, int levelOfDetail, bool flatshading, MapGenerator mg) { int width = heightMap.GetLength(0); int height = heightMap.GetLength(1); float topLeftX = (width - 1) / -2f; float topLeftZ = (height - 1) / 2f; int borderedSize = heightMap.GetLength(0); int meshSimplificationIncrement = (levelOfDetail == 0) ? 1 : levelOfDetail * 2; int verticesPerLine = (width - 1) / meshSimplificationIncrement + 1; int borderVertexIndex = -1; MeshData meshData = new MeshData(verticesPerLine, verticesPerLine); int vertexIndex = 0; for (int y = 0; y < height; y += meshSimplificationIncrement) { for (int x = 0; x < width; x += meshSimplificationIncrement) { meshData.vertices[vertexIndex] = new Vector3(topLeftX + x, heightCurve.Evaluate(heightMap[x, y]) * heightMultiplier, topLeftZ - y); meshData.uvs[vertexIndex] = new Vector2(x / (float)width, y / (float)height); if (x < width - 1 && y < height - 1) { meshData.AddTriangle(vertexIndex, vertexIndex + verticesPerLine + 1, vertexIndex + verticesPerLine); meshData.AddTriangle(vertexIndex + verticesPerLine + 1, vertexIndex, vertexIndex + 1); } vertexIndex++; } } mg.ColorMap(); meshData.ProcessMesh(flatshading); return(meshData); }
public static MeshData GenerateTerrainMesh(float[,] heightMap, float heightMultiplier, AnimationCurve _heightCurve, int levelOfDetail, bool useFlatShading) { AnimationCurve heightCurve = new AnimationCurve(_heightCurve.keys); int meshSimplificationIncrement = (levelOfDetail == 0) ? 1 : levelOfDetail * 2; int meshSize = heightMap.GetLength(0) - 2 * meshSimplificationIncrement; int meshSizeUnsimplified = heightMap.GetLength(0) - 2; float topLeftX = (meshSizeUnsimplified - 1) / -2f; float topLeftZ = (meshSizeUnsimplified - 1) / 2f; int verticesPerLine = (meshSize - 1) / meshSimplificationIncrement + 1; MeshData meshData = new MeshData(verticesPerLine, useFlatShading); int[,] vertexIndicesMap = new int[meshSize, meshSize]; int meshVertexIndex = 0; for (int y = 0; y < meshSize; y += meshSimplificationIncrement) { for (int x = 0; x < meshSize; x += meshSimplificationIncrement) { vertexIndicesMap[x, y] = meshVertexIndex; meshVertexIndex++; } } for (int y = 0; y < meshSize; y += meshSimplificationIncrement) { for (int x = 0; x < meshSize; x += meshSimplificationIncrement) { int vertexIndex = vertexIndicesMap[x, y]; float height = heightCurve.Evaluate(heightMap[x, y]) * heightMultiplier; Vector2 percent = new Vector2((x - meshSimplificationIncrement) / (float)meshSize, (y - meshSimplificationIncrement) / (float)meshSize); Vector3 vertexPosition = new Vector3(topLeftX + percent.x * meshSizeUnsimplified, height, topLeftZ - percent.y * meshSizeUnsimplified); meshData.AddVertex(vertexPosition, percent, vertexIndex); if (x < meshSize - 1 && y < meshSize - 1) { int a = vertexIndicesMap[x, y]; int b = vertexIndicesMap[x + meshSimplificationIncrement, y]; int c = vertexIndicesMap[x, y + meshSimplificationIncrement]; int d = vertexIndicesMap[x + meshSimplificationIncrement, y + meshSimplificationIncrement]; meshData.AddTriangle(a, d, c); meshData.AddTriangle(d, a, b); } vertexIndex++; } } meshData.ProcessMesh(); return(meshData); }
public Task <MeshData> GenerateTerrainMeshNew(float[,] heightMap, int levelOfDetail) { int skipIncrement = (levelOfDetail == 0) ? 1 : levelOfDetail * 2; var vertexIndicesMap = InitializeVertexIndicesMap(skipIncrement); var meshData = new MeshData(numVertsPerLine, skipIncrement, settings.useFlatShading); var meshVertexIndex = 0; var outOfMeshVertexIndex = -1; for (var y = 0; y < numVertsPerLine; ++y) { for (var x = 0; x < numVertsPerLine; ++x) { var v = new VertexInfo(x, y, skipIncrement, heightMap, vertexIndicesMap); if (v.isSkipped) { continue; } var vertexIndex = v.VertexIndex; var percent = new Vector2(x - 1, y - 1) / (numVertsPerLine - 3); var vertexPosition2D = settings.TopLeft + new Vector2(percent.x, -percent.y) * settings.meshWorldSize; if (v.isEdgeConnection) { var edgeConnectionVertexData = new EdgeConnectionVertexData(vertexIndex, v.VertexIndexCoordA, v.VertexIndexCoordB, v.dstPercentFromAToB); meshData.DeclareEdgeConnectionVertex(edgeConnectionVertexData); } try { meshData.AddVertex(new Vector3(vertexPosition2D.x, v.height, vertexPosition2D.y), percent, vertexIndex); } catch (IndexOutOfRangeException) { //Debug.Log(vertexIndex); } if (!v.shouldCreateTriangle) { continue; } int[] corners = v.Corners; meshData.AddTriangle(corners[0], corners[3], corners[2]); meshData.AddTriangle(corners[3], corners[0], corners[1]); } } meshData.ProcessMesh(); return(Task.FromResult(meshData)); }
public static MeshData GenerateTerrainMesh(float[,] heightMap, float heightMultiplier, AnimationCurve _heightCurve, int levelOfDetail, bool useFlatShading, bool buildingWall) { AnimationCurve heightCurve = new AnimationCurve(_heightCurve.keys); int width = heightMap.GetLength(0); int height = heightMap.GetLength(1); float topLeftX = (width - 1) / -2f; float topLeftZ = (height - 1) / 2f; int meshSimplificationIncrement = (levelOfDetail == 0) ? 1 : levelOfDetail * 2; int verticesPerLine = (width - 1) / meshSimplificationIncrement + 1; MeshData meshData = new MeshData(verticesPerLine, verticesPerLine, useFlatShading); int vertexIndex = 0; for (int y = 0; y < height; y += meshSimplificationIncrement) { for (int x = 0; x < width; x += meshSimplificationIncrement) { if (buildingWall) { meshData.vertices[vertexIndex] = new Vector3(topLeftX + x, topLeftZ - y, heightCurve.Evaluate(heightMap[x, y]) * heightMultiplier); } else { meshData.vertices[vertexIndex] = new Vector3(topLeftX + x, heightCurve.Evaluate(heightMap[x, y]) * heightMultiplier, topLeftZ - y); } meshData.uvs[vertexIndex] = new Vector2(x / (float)width, y / (float)height); if (x < width - 1 && y < height - 1) { if (buildingWall) { meshData.AddTriangle(vertexIndex, vertexIndex + verticesPerLine, vertexIndex + verticesPerLine + 1); meshData.AddTriangle(vertexIndex + verticesPerLine + 1, vertexIndex + 1, vertexIndex); } else { meshData.AddTriangle(vertexIndex, vertexIndex + verticesPerLine + 1, vertexIndex + verticesPerLine); meshData.AddTriangle(vertexIndex + verticesPerLine + 1, vertexIndex, vertexIndex + 1); } } vertexIndex++; } } meshData.ProcessMesh(); return(meshData); }
// Creates a mesh from a 2D height map public static MeshData GenerateTerrainMesh(float[,] heightMap, float heightMultiplier, AnimationCurve _heightCurve, int levelOfDetail, bool useFlatShading) { // Each thread will have its own height curve object AnimationCurve heightCurve = new AnimationCurve(_heightCurve.keys); // Create a new animation curve at the start to avoid errors int width = heightMap.GetLength(0); int height = heightMap.GetLength(1); float topLeftX = (width - 1) / -2f; // Scales the lefmost point so that the mesh is centered on the screen float topLeftZ = (height - 1) / 2f; // The number of vertices to skip over (1 draws all vertices) int meshSimplificationIncrement = (levelOfDetail == 0) ? 1: levelOfDetail * 2; int verticesPerLine = (width - 1) / meshSimplificationIncrement + 1; MeshData meshData = new MeshData(verticesPerLine, verticesPerLine, useFlatShading); int vertexIndex = 0; // Current index of the vertices array for (int y = 0; y < height; y += meshSimplificationIncrement) // Loop through the height map { for (int x = 0; x < width; x += meshSimplificationIncrement) { meshData.vertices [vertexIndex] = new Vector3(topLeftX + x, heightCurve.Evaluate(heightMap [x, y]) * heightMultiplier, topLeftZ - y); // Each vertex's position in the map is represented as a percentage meshData.uvs[vertexIndex] = new Vector2(x / (float)width, y / (float)height); // Ignore indexes at the right and bottom of the mesh if (x < width - 1 && y < height - 1) { meshData.AddTriangle(vertexIndex, vertexIndex + verticesPerLine + 1, vertexIndex + verticesPerLine); // First triangle meshData.AddTriangle(vertexIndex + verticesPerLine + 1, vertexIndex, vertexIndex + 1); // Second triangle } vertexIndex++; } } meshData.ProcessMesh(); return(meshData); }
public static MeshData GenerateTerrainMesh(float[,] heightMap, float heightMultiplier, AnimationCurve _heightCurve) { AnimationCurve heightCurve = new AnimationCurve(_heightCurve.keys); int mapWidth = heightMap.GetLength(0); int mapHeight = heightMap.GetLength(1); float topLeftX = (mapWidth - 1) / -2f; float topLeftZ = (mapHeight - 1) / 2f; MeshData meshData = new MeshData(mapWidth, mapHeight); int vertexIndex = 0; for (int y = 0; y < mapHeight; y++) { for (int x = 0; x < mapWidth; x++) { float height = heightCurve.Evaluate(heightMap[x, y]) * heightMultiplier; Vector2 uv = new Vector2(x / (float)mapWidth, y / (float)mapHeight); Vector3 position = new Vector3(topLeftX + x, height, topLeftZ - y); meshData.AddVertex(position, uv, vertexIndex); if (x < mapWidth - 1 && y < mapHeight - 1) { meshData.AddTriangle(vertexIndex, vertexIndex + mapWidth + 1, vertexIndex + mapWidth); meshData.AddTriangle(vertexIndex + mapWidth + 1, vertexIndex, vertexIndex + 1); } vertexIndex = vertexIndex + 1; } } meshData.ProcessMesh(); return(meshData); }
public MeshData GenerateMeshData(MeshSettings meshSettings, int lod) { float topLeftX = (width - 1) / -2f; float topLeftZ = (height - 1) / 2f; int meshSimplificationIncrement = (lod == 0) ? 1 : lod * 2; int verticesPerLine = (width - 1) / meshSimplificationIncrement + 1; MeshData meshData = new MeshData(verticesPerLine, verticesPerLine, meshSettings.useFlatShading); int vertexIndex = 0; for (int y = 0; y < height; y += meshSimplificationIncrement) { for (int x = 0; x < width; x += meshSimplificationIncrement) { float heightY = values[x, y]; Vector3 vertice = new Vector3((topLeftX + x) * meshSettings.meshScale, heightY, (topLeftZ - y) * meshSettings.meshScale); Vector2 uv = new Vector2(x / (float)width, y / (float)height); meshData.AddVertice(vertexIndex, vertice, uv); if (x < width - 1 && y < height - 1) { meshData.AddTriangle(vertexIndex, vertexIndex + verticesPerLine + 1, vertexIndex + verticesPerLine); meshData.AddTriangle(vertexIndex + verticesPerLine + 1, vertexIndex, vertexIndex + 1); } vertexIndex++; } } meshData.ProcessMesh(); return(meshData); }
public static MeshData GenerateTerrianMesh(float[,] heightMap, float heightMulti, int lod, AnimationCurve curve) { int borderSize = heightMap.GetLength(0); int meshSimpleInc = (lod == 0) ? 1 : lod * 2; int meshSize = (borderSize - 1) / meshSimpleInc + 1; var meshData = new MeshData(meshSize); float topLeftX = borderSize / -2; float topLeftZ = borderSize / 2; float[,] newHeightMap = new float[borderSize, borderSize]; Buffer.BlockCopy(heightMap, 0, newHeightMap, 0, borderSize * borderSize); int[,] vertexIdxMap = new int[meshSize, meshSize]; int meshIdx = 0; for (int y = 0; y < borderSize; y += meshSimpleInc) { for (int x = 0; x < borderSize; x += meshSimpleInc) { vertexIdxMap[y / meshSimpleInc, x / meshSimpleInc] = meshIdx++; } } for (int y = 0; y < borderSize; y += meshSimpleInc) { for (int x = 0; x < borderSize; x += meshSimpleInc) { float height = curve.Evaluate(heightMap[y, x]) * heightMulti; newHeightMap[y, x] = height; Vector3 vertexPos = new Vector3(x, height, y); Vector2 uv = new Vector2(x / (float)borderSize, y / (float)borderSize); meshData.AddVertex(vertexPos, uv, vertexIdxMap[y / meshSimpleInc, x / meshSimpleInc]); if (x < borderSize - meshSimpleInc && y < borderSize - meshSimpleInc) { int xx = x / meshSimpleInc; int yy = y / meshSimpleInc; int a = vertexIdxMap[yy, xx]; int b = vertexIdxMap[yy, xx + 1]; int c = vertexIdxMap[yy + 1, xx]; int d = vertexIdxMap[yy + 1, xx + 1]; meshData.AddTriangle(c, b, a); meshData.AddTriangle(c, d, b); } } } meshData.meshSimpleInc = meshSimpleInc; meshData.heightMap = newHeightMap; meshData.ProcessMesh(); return(meshData); }
//The return type for this is MeshData so that threading can be implemented later on, thereby heavily increasing performance //An animation curve is used to define the height of various specific location groups, such as making "water" appear flat public static MeshData GenerateTerrainMesh(float[,] heightMap, float heightMultiplier, AnimationCurve _heightCurve, int levelOfDetail, bool useFlatshading) { AnimationCurve heightCurve = new AnimationCurve(_heightCurve.keys); int meshSimplificationIncrement = (levelOfDetail == 0) ? 1 : levelOfDetail * 2; int borderedSize = heightMap.GetLength(0); int meshSize = borderedSize - 2 * meshSimplificationIncrement; int meshSizeUnsimplified = borderedSize - 2; int verticesPerLine = (meshSize - 1) / meshSimplificationIncrement + 1; //The mesh, using this along with the vertex array, will begin in the center of the plane float topLeftX = (meshSizeUnsimplified - 1) / -2f; float topLeftZ = (meshSizeUnsimplified - 1) / 2f; MeshData meshData = new MeshData(verticesPerLine, useFlatshading); int[,] vertexIndicesMap = new int[borderedSize, borderedSize]; int meshVertexIndex = 0; int borderVertexIndex = -1; //In order to account for border vertices in the terrain for lighting/normals purposes, run a loop to identify where they are for (int y = 0; y < borderedSize; y += meshSimplificationIncrement) { for (int x = 0; x < borderedSize; x += meshSimplificationIncrement) { bool isBorderVertex = y == 0 || y == borderedSize - 1 || x == 0 || x == borderedSize - 1; if (isBorderVertex) { vertexIndicesMap[x, y] = borderVertexIndex; borderVertexIndex--; } else { vertexIndicesMap[x, y] = meshVertexIndex; meshVertexIndex++; } } } //The heightMap quite literally corresponds with how high the plane is at coordinates (x,y) //The uvs are calculated using mesh size, not bordered size for (int y = 0; y < borderedSize; y += meshSimplificationIncrement) { for (int x = 0; x < borderedSize; x += meshSimplificationIncrement) { int vertexIndex = vertexIndicesMap[x, y]; Vector2 percent = new Vector2((x - meshSimplificationIncrement) / (float)meshSize, (y - meshSimplificationIncrement) / (float)meshSize); float height = heightCurve.Evaluate(heightMap[x, y]) * heightMultiplier; Vector3 vertexPosition = new Vector3(topLeftX + percent.x * meshSizeUnsimplified, height, topLeftZ - percent.y * meshSizeUnsimplified); meshData.AddVertex(vertexPosition, percent, vertexIndex); //Create 2 triangles according to the vertex indices map //Imagine a square with each point indicated like so: // //A---B //| + | //C---D // //The triangles needing to be calculated and added into the mesh data are triangles ADC and DAB if (x < borderedSize - 1 && y < borderedSize - 1) { int a = vertexIndicesMap[x, y]; int b = vertexIndicesMap[x + meshSimplificationIncrement, y]; int c = vertexIndicesMap[x, y + meshSimplificationIncrement]; int d = vertexIndicesMap[x + meshSimplificationIncrement, y + meshSimplificationIncrement]; meshData.AddTriangle(a, d, c); meshData.AddTriangle(d, a, b); } vertexIndex++; } } meshData.ProcessMesh(); return(meshData); }
public static MeshData GenerateTerrainMesh(float[,] heightMap, float heightMultiplier, AnimationCurve _heightCurve, int levelOfDetail, bool useFlatShading) { AnimationCurve heightCurve = new AnimationCurve(_heightCurve.keys); // each thread has its on own heightCurve object, no need for locking int meshSimplificationIncrement = (levelOfDetail == 0)?1:levelOfDetail * 2; int borderedSize = heightMap.GetLength(0); int meshSize = borderedSize - 2 * meshSimplificationIncrement; int meshSizeUnsimplified = borderedSize - 2; //independent of lod float topLeftX = (meshSizeUnsimplified - 1) / -2f; float topLeftZ = (meshSizeUnsimplified - 1) / 2f; int verticesPerLine = (meshSize - 1) / meshSimplificationIncrement + 1; MeshData meshData = new MeshData(verticesPerLine, useFlatShading); int[,] vertexIndicesMap = new int[borderedSize, borderedSize]; int meshVertexIndex = 0; int borderVertexIndex = -1; for (int y = 0; y < borderedSize; y += meshSimplificationIncrement) { for (int x = 0; x < borderedSize; x += meshSimplificationIncrement) { bool isBorderVertex = y == 0 || y == borderedSize - 1 || x == 0 || x == borderedSize - 1; if (isBorderVertex) { vertexIndicesMap [x, y] = borderVertexIndex; borderVertexIndex--; } else { vertexIndicesMap [x, y] = meshVertexIndex; meshVertexIndex++; } } } for (int y = 0; y < borderedSize; y += meshSimplificationIncrement) { for (int x = 0; x < borderedSize; x += meshSimplificationIncrement) { int vertexIndex = vertexIndicesMap [x, y]; Vector2 percent = new Vector2((x - meshSimplificationIncrement) / (float)meshSize, (y - meshSimplificationIncrement) / (float)meshSize); float height = heightCurve.Evaluate(heightMap [x, y]) * heightMultiplier; Vector3 vertexPosition = new Vector3(topLeftX + percent.x * meshSizeUnsimplified, height, topLeftZ - percent.y * meshSizeUnsimplified); meshData.AddVertex(vertexPosition, percent, vertexIndex); if (x < borderedSize - 1 && y < borderedSize - 1) { int a = vertexIndicesMap [x, y]; int b = vertexIndicesMap [x + meshSimplificationIncrement, y]; int c = vertexIndicesMap [x, y + meshSimplificationIncrement]; int d = vertexIndicesMap [x + meshSimplificationIncrement, y + meshSimplificationIncrement]; meshData.AddTriangle(a, d, c); //triangle adc meshData.AddTriangle(d, a, b); //triangle dab } vertexIndex++; } } meshData.ProcessMesh(); // run on seperate thread - since generate terrain mesh is run on different thread return(meshData); }
// CREDIT: Sebastian Lague: https://www.youtube.com/channel/UCmtyQOKKmrMVaKuRXz02jbQ public static MeshData GenerateTerrainMesh(float[,] heightMap, int levelOfDetail, bool useFlatShading) { int meshSimplificationIncrement = (levelOfDetail == 0) ? 1 : levelOfDetail * 2; // 2 int borderedSize = heightMap.GetLength(0); // 7 int meshSize = borderedSize - 2 * meshSimplificationIncrement; // 3 int meshSizeUnsimplified = borderedSize - 2; // 5 float topLeftX = (meshSizeUnsimplified - 1) / -2f; float topLeftZ = (meshSizeUnsimplified - 1) / 2f; int verticesPerLine = (meshSize - 1) / meshSimplificationIncrement + 1; // if full (1): 5 4 + 1 // if low (2): 3 2 + 1 // if lower (4): 2 1 + 1 int tilesPerSide = borderedSize - 3; for (int i = 0; i < levelOfDetail; i++) { tilesPerSide /= 2; if (tilesPerSide < 1) { tilesPerSide = 1; break; } } verticesPerLine = tilesPerSide + 1; //Debug.Log("Generating mesh with " + verticesPerLine + " verticies per line"); MeshData meshData = new MeshData(verticesPerLine, useFlatShading); int[,] vertexIndicesMap = new int[borderedSize, borderedSize]; int meshVertexIndex = 0; int borderVertexIndex = -1; int curIncrement = 1; //for (int y = 0; y < borderedSize; y++) { // for (int x = 0; x < borderedSize; x++) { // vertexIndicesMap[x, y] = 100; // } //} for (int y = 0; y < borderedSize; y += curIncrement) { for (int x = 0; x < borderedSize; x += curIncrement) { if (x == 0 || x == borderedSize - 2) { curIncrement = 1; } else { curIncrement = meshSimplificationIncrement; } bool isBorderVertex = y == 0 || y == borderedSize - 1 || x == 0 || x == borderedSize - 1; //Debug.Log(new Vector2Int(x, y) + " border: " + isBorderVertex); if (isBorderVertex) { vertexIndicesMap [x, y] = borderVertexIndex; borderVertexIndex--; } else { vertexIndicesMap [x, y] = meshVertexIndex; meshVertexIndex++; } } if (y == 0 || y == borderedSize - 2) { curIncrement = 1; } else { curIncrement = meshSimplificationIncrement; } } //for (int y = 0; y < borderedSize; y++) { // string lineStr = y + " | "; // for (int x = 0; x < borderedSize; x++) { // int val = vertexIndicesMap[x, y]; // lineStr += val == 100 ? "N " : val + " "; // } // Debug.Log(lineStr); //} int curIncrementX; int curIncrementY; for (int y = 0; y < borderedSize; y += curIncrementY) { if (y == 0 || y == borderedSize - 2) { curIncrementY = 1; } else { curIncrementY = meshSimplificationIncrement; } for (int x = 0; x < borderedSize; x += curIncrementX) { if (x == 0 || x == borderedSize - 2) { curIncrementX = 1; } else { curIncrementX = meshSimplificationIncrement; } int vertexIndex = vertexIndicesMap [x, y]; //Vector2 percent = new Vector2 ((x- curIncrement) / (float)meshSize, (y- curIncrement) / (float)meshSize); float height = heightMap [x, y]; //Vector3 vertexPosition = new Vector3 (topLeftX + percent.x * meshSizeUnsimplified, height, topLeftZ - percent.y * meshSizeUnsimplified); Vector3 vertexPosition = new Vector3(topLeftX + x - 1, height, topLeftZ - y + 1); meshData.AddVertex(vertexPosition, Vector2.zero, vertexIndex); if (x < borderedSize - 1 && y < borderedSize - 1) { int a = vertexIndicesMap [x, y]; int b = vertexIndicesMap [x + curIncrementX, y]; int c = vertexIndicesMap [x, y + curIncrementY]; int d = vertexIndicesMap [x + curIncrementX, y + curIncrementY]; //Debug.Log(new Vector2Int(x, y) + " | Inc: " + new Vector2Int(curIncrementX, curIncrementY) + " | a: " + a + " b: " + b + " c: " + c + " d: " + d); meshData.AddTriangle(a, d, c); meshData.AddTriangle(d, a, b); } vertexIndex++; } } meshData.ProcessMesh(); return(meshData); }
public static MeshData GenerateTerrainMesh(float[,] heightMap, MeshSettings meshSettings, int levelOfDetail) { int meshSimplificationIncrement = (levelOfDetail == 0) ? 1 : levelOfDetail * 2; int borderedSize = heightMap.GetLength(0); int meshSize = borderedSize - 2 * meshSimplificationIncrement; int meshSizeUnsimplified = borderedSize - 2; float topLeftX = (meshSizeUnsimplified - 1) / -2f; float topLeftZ = (meshSizeUnsimplified - 1) / 2f; int verticesPerLine = (meshSize - 1) / meshSimplificationIncrement + 1; MeshData meshData = new MeshData(verticesPerLine, meshSettings.useFlatShading); int[,] vertexIndicesMap = new int[borderedSize, borderedSize]; int meshVertexIndex = 0; int borderVertexIndex = -1; for (int y = 0; y < borderedSize; y += meshSimplificationIncrement) { for (int x = 0; x < borderedSize; x += meshSimplificationIncrement) { bool isBorderVertex = y == 0 || y == borderedSize - 1 || x == 0 || x == borderedSize - 1; if (isBorderVertex) { vertexIndicesMap[x, y] = borderVertexIndex; borderVertexIndex--; } else { vertexIndicesMap[x, y] = meshVertexIndex; meshVertexIndex++; } } } for (int y = 0; y < borderedSize; y += meshSimplificationIncrement) { for (int x = 0; x < borderedSize; x += meshSimplificationIncrement) { int vertexIndex = vertexIndicesMap[x, y]; Vector2 percent = new Vector2((x - meshSimplificationIncrement) / (float)meshSize, (y - meshSimplificationIncrement) / (float)meshSize); float height = heightMap[x, y]; Vector3 vertexPosition = new Vector3((topLeftX + percent.x * meshSizeUnsimplified) * meshSettings.meshScale, height, (topLeftZ - percent.y * meshSizeUnsimplified) * meshSettings.meshScale); meshData.AddVertex(vertexPosition, percent, vertexIndex); if (x < borderedSize - 1 && y < borderedSize - 1) { int a = vertexIndicesMap[x, y]; int b = vertexIndicesMap[x + meshSimplificationIncrement, y]; int c = vertexIndicesMap[x, y + meshSimplificationIncrement]; int d = vertexIndicesMap[x + meshSimplificationIncrement, y + meshSimplificationIncrement]; meshData.AddTriangle(a, d, c); meshData.AddTriangle(d, a, b); } vertexIndex++; } } meshData.ProcessMesh(); return(meshData); }
public static MeshData GenerateTerrainMesh(float[,] heightMap, MeshSettings meshSettings, int levelOfDetail) { int skipIncrement = levelOfDetail == 0 ? 1 : levelOfDetail * 2; int numVertsPerLine = meshSettings.NumVerticesPerLine; Vector2 topLeft = new Vector2(-1, 1) * meshSettings.MeshWorldSize / 2f; MeshData meshData = new MeshData(numVertsPerLine, skipIncrement, meshSettings.UseFlatShading); int [,] vertexIndicesMap = new int[numVertsPerLine, numVertsPerLine]; int meshVertexIndex = 0; int outOfMeshVertexIndex = -1; for (int y = 0; y < numVertsPerLine; y++) { for (int x = 0; x < numVertsPerLine; x++) { bool isOutOfMeshVertex = (y == 0 || y == numVertsPerLine - 1 || x == 0 || x == numVertsPerLine - 1); bool isMainVertex = ((x - 2) % skipIncrement != 0 || (y - 2) % skipIncrement != 0); bool isSkippedVertex = x > 2 && x < numVertsPerLine - 3 && y > 2 && y < numVertsPerLine - 3 && isMainVertex; if (isOutOfMeshVertex) { vertexIndicesMap[x, y] = outOfMeshVertexIndex; outOfMeshVertexIndex--; } else if (!isSkippedVertex) { vertexIndicesMap[x, y] = meshVertexIndex; meshVertexIndex++; } } } for (int y = 0; y < numVertsPerLine; y++) { for (int x = 0; x < numVertsPerLine; x++) { bool isSkippedVertex = x > 2 && x < numVertsPerLine - 3 && y > 2 && y < numVertsPerLine - 3 && ((x - 2) % skipIncrement != 0 || (y - 2) % skipIncrement != 0); if (!isSkippedVertex) { bool isOutOfMeshVertex = y == 0 || y == numVertsPerLine - 1 || x == 0 || x == numVertsPerLine - 1; bool isMeshEdgeVertex = (y == 1 || y == numVertsPerLine - 2 || x == 1 || x == numVertsPerLine - 2) && !isOutOfMeshVertex; bool isMainVertex = (x - 2) % skipIncrement == 0 && (y - 2) % skipIncrement == 0 && !isOutOfMeshVertex && !isMeshEdgeVertex; bool isEdgeConnectionVertex = (y == 2 || y == numVertsPerLine - 3 || x == 2 || x == numVertsPerLine - 3) && !isOutOfMeshVertex && !isMeshEdgeVertex && !isMainVertex; int vertexIndex = vertexIndicesMap[x, y]; Vector2 percent = new Vector2(x - 1, y - 1) / (numVertsPerLine - 3); float height = heightMap[x, y]; Vector2 vertexPosition2D = topLeft + new Vector2(percent.x, -percent.y) * meshSettings.MeshWorldSize; if (isEdgeConnectionVertex) { bool isVertical = x == 2 || x == numVertsPerLine - 3; int dstToMainVertexA = (isVertical ? (y - 2) : (x - 2)) % skipIncrement; int dstToMainVertexB = skipIncrement - dstToMainVertexA; float dstPercentFromAToB = dstToMainVertexA / (float)skipIncrement; float heightMainVertexA = heightMap[isVertical ? x : x - dstToMainVertexA, isVertical ? y - dstToMainVertexA : y]; float heightMainVertexB = heightMap[isVertical ? x : x + dstToMainVertexB, isVertical ? y + dstToMainVertexB : y]; height = heightMainVertexA * (1 - dstPercentFromAToB) + heightMainVertexB * dstPercentFromAToB; } meshData.AddVertex(new Vector3(vertexPosition2D.x, height, vertexPosition2D.y), percent, vertexIndex); bool createTriangle = x < numVertsPerLine - 1 && y < numVertsPerLine - 1 && (!isEdgeConnectionVertex || (x != 2 && y != 2)); if (createTriangle) { int currentIncrement = (isMainVertex && x != numVertsPerLine - 3 && y != numVertsPerLine - 3) ? skipIncrement : 1; int pointA = vertexIndicesMap[x, y]; int pointB = vertexIndicesMap[x + currentIncrement, y]; int pointC = vertexIndicesMap[x, y + currentIncrement]; int pointD = vertexIndicesMap[x + currentIncrement, y + currentIncrement]; /* Setting the triangle according to the square point: * * a b * O O * * O O * c d * * Run clockwise to define the 2 triangles we have * Triangle A = adc * Triangle B = dab */ meshData.AddTriangle(pointA, pointD, pointC); meshData.AddTriangle(pointD, pointA, pointB); } } } } meshData.ProcessMesh(); return(meshData); }
public static MeshData GenerateTerrainMesh(float[,] heightMap, MeshSettings meshSettings, int levelOfDetail) { var skipIncrement = (levelOfDetail == 0) ? 1 : levelOfDetail * 2; var numVertsPerLine = meshSettings.numVertsPerLine; var topLeft = new Vector2(-1, 1) * meshSettings.meshWorldSize / 2f; var meshData = new MeshData(numVertsPerLine, skipIncrement, meshSettings.useFlatShading); var vertexIndicesMap = new int[numVertsPerLine, numVertsPerLine]; var meshVertexIndex = 0; var outOfMeshVertexIndex = -1; for (var y = 0; y < numVertsPerLine; ++y) { for (var x = 0; x < numVertsPerLine; ++x) { var isOutOfMeshVertex = y == 0 || y == numVertsPerLine - 1 || x == 0 || x == numVertsPerLine - 1; var isSkippedVertex = x > 2 && x < numVertsPerLine - 3 && y > 2 && y < numVertsPerLine - 3 && ((x - 2) % skipIncrement != 0 || (y - 2) % skipIncrement != 0); if (isOutOfMeshVertex) { vertexIndicesMap[x, y] = outOfMeshVertexIndex; outOfMeshVertexIndex--; } else if (!isSkippedVertex) { vertexIndicesMap[x, y] = meshVertexIndex; meshVertexIndex++; } } } for (var y = 0; y < numVertsPerLine; ++y) { for (var x = 0; x < numVertsPerLine; ++x) { var isSkippedVertex = x > 2 && x < numVertsPerLine - 3 && y > 2 && y < numVertsPerLine - 3 && ((x - 2) % skipIncrement != 0 || (y - 2) % skipIncrement != 0); if (!isSkippedVertex) { var isOutOfMeshVertex = y == 0 || y == numVertsPerLine - 1 || x == 0 || x == numVertsPerLine - 1; var isMeshEdgeVertex = (y == 1 || y == numVertsPerLine - 2 || x == 1 || x == numVertsPerLine - 2) && !isOutOfMeshVertex; var isMainVertex = (x - 2) % skipIncrement == 0 && (y - 2) % skipIncrement == 0 && !isOutOfMeshVertex && !isMeshEdgeVertex; var isEdgeConnectionVertex = (y == 2 || y == numVertsPerLine - 3 || x == 2 || x == numVertsPerLine - 3) && !isOutOfMeshVertex && !isMeshEdgeVertex && !isMainVertex; var vertexIndex = vertexIndicesMap[x, y]; var percent = new Vector2(x - 1, y - 1) / (numVertsPerLine - 3); var vertexPosition2D = topLeft + new Vector2(percent.x, -percent.y) * meshSettings.meshWorldSize; var height = heightMap[x, y]; if (isEdgeConnectionVertex) { var isVertical = x == 2 || x == numVertsPerLine - 3; var dstToMainVertexA = ((isVertical) ? y - 2 : x - 2) % skipIncrement; var dstToMainVertexB = skipIncrement - dstToMainVertexA; var dstPercentFromAToB = dstToMainVertexA / (float)skipIncrement; var coordA = new Coord((isVertical) ? x : x - dstToMainVertexA, (isVertical) ? y - dstToMainVertexA : y); var coordB = new Coord((isVertical) ? x : x + dstToMainVertexB, (isVertical) ? y + dstToMainVertexB : y); var heightMainVertexA = heightMap[coordA.x, coordA.y]; var heightMainVertexB = heightMap[coordB.x, coordB.y]; height = heightMainVertexA * (1 - dstPercentFromAToB) + heightMainVertexB * dstPercentFromAToB; var edgeConnectionVertexData = new EdgeConnectionVertexData(vertexIndex, vertexIndicesMap[coordA.x, coordA.y], vertexIndicesMap[coordB.x, coordB.y], dstPercentFromAToB); meshData.DeclareEdgeConnectionVertex(edgeConnectionVertexData); } meshData.AddVertex(new Vector3(vertexPosition2D.x, height, vertexPosition2D.y), percent, vertexIndex); var createTriangle = x < numVertsPerLine - 1 && y < numVertsPerLine - 1 && (!isEdgeConnectionVertex || (x != 2 && y != 2)); if (createTriangle) { var currentIncrement = (isMainVertex && x != numVertsPerLine - 3 && y != numVertsPerLine - 3) ? skipIncrement : 1; var a = vertexIndicesMap[x, y]; var b = vertexIndicesMap[x + currentIncrement, y]; var c = vertexIndicesMap[x, y + currentIncrement]; var d = vertexIndicesMap[x + currentIncrement, y + currentIncrement]; meshData.AddTriangle(a, d, c); meshData.AddTriangle(d, a, b); } } } } meshData.ProcessMesh(); return(meshData); }
//generates meshData from appropriate data passed in public static MeshData GenerateTerrainMesh(float[,] heightMap, MeshSettings meshSettings, int levelOfDetail) { //how many vertices to skip, scales with LOD (this being 2 means we skip every other vertex) int skipIncrement = (levelOfDetail == 0) ? 1 : levelOfDetail * 2; //number of verts to a side in the mesh int numVertsPerLine = meshSettings.numVertsPerLine; //Top left X and Z of the verticies in the soon-to-be-created meshData Vector2 topLeft = new Vector2(-1, -1) * meshSettings.meshWorldSize / 2f; //creates a new meshdata with the correct amount of verticies for the level of detail specified MeshData meshData = new MeshData(numVertsPerLine, skipIncrement, meshSettings.useFlatShading); /*the map of verticies for dealing with the lighting errors that occur at the edge of each mesh looks like this on a 3x3 mesh * -1 -2 -3 -4 -5 * -6 0 1 2 -7 * -8 3 4 5 -9 *-10 6 7 8 -11 *-12 -13 -14 -15 -16 * because negative indices vertexes aren't included in the final mesh. This is obviously hard to create so that's what these variables and for loops are for */ int[,] vertexIndiciesMap = new int[numVertsPerLine, numVertsPerLine]; int meshVertexIndex = 0; int outOfMeshVertexIndex = -1; //creating the map of vertices for (int y = 0; y < numVertsPerLine; y++) { for (int x = 0; x < numVertsPerLine; x++) { //check if we're on the outside border fo the mesh bool isOutOfMeshVertex = y == 0 || y == numVertsPerLine - 1 || x == 0 || x == numVertsPerLine - 1; //check if we're skipping the verice for LOD stuff bool isSkippedVertex = x > 2 && x < numVertsPerLine - 3 && y > 2 && y < numVertsPerLine - 3 && ((x - 2) % skipIncrement != 0 || (y - 2) % skipIncrement != 0); if (isOutOfMeshVertex) { vertexIndiciesMap[x, y] = outOfMeshVertexIndex; outOfMeshVertexIndex--; } else if (!isSkippedVertex) { vertexIndiciesMap[x, y] = meshVertexIndex; meshVertexIndex++; } } } //runs through each vertice according to LOD for (int y = 0; y < numVertsPerLine; y++) { for (int x = 0; x < numVertsPerLine; x++) { //check if we're skipping the verice for LOD stuff bool isSkippedVertex = x > 2 && x < numVertsPerLine - 3 && y > 2 && y < numVertsPerLine - 3 && ((x - 2) % skipIncrement != 0 || (y - 2) % skipIncrement != 0); if (!isSkippedVertex) { //check what kind of vertex we are //https://www.desmos.com/calculator/bcagu8b0vn bool isOutOfMeshVertex = y == 0 || y == numVertsPerLine - 1 || x == 0 || x == numVertsPerLine - 1; bool isMeshEdgeVertex = (y == 1 || y == numVertsPerLine - 2 || x == 1 || x == numVertsPerLine - 2) && !isOutOfMeshVertex; bool isMainVertex = (x - 2) % skipIncrement == 0 && (y - 2) % skipIncrement == 0 && !isOutOfMeshVertex && !isMeshEdgeVertex; bool isEdgeConnectionVertex = (y == 2 || y == numVertsPerLine - 3 || x == 2 || x == numVertsPerLine - 3) && !isOutOfMeshVertex && !isMeshEdgeVertex && !isMainVertex; //gets the correct vertexIndex from the indicies map we just made int vertexIndex = vertexIndiciesMap[x, y]; //used to map the texture to the mesh Vector2 percent = new Vector2(x - 1, y - 1) / (numVertsPerLine - 3); //we flip y in order to alighn the unity editor z axis with the programming y axis Vector2 vertexPosition2D = topLeft + new Vector2(percent.x, -percent.y) * meshSettings.meshWorldSize; //the height of the vertex at the given x, y coordinates float height = heightMap[x, y]; //this is to make the edgeconnection vertices match up with the mesh when it's at a different LOD by linearly interpolating between the 2 closest vertices' heights if (isEdgeConnectionVertex) { bool isVertical = x == 2 || x == numVertsPerLine - 3; int dstToMainVertexA = ((isVertical) ? y - 2 : x - 2) % skipIncrement; // distance to the closest main vertex above int dstToMainVertexB = skipIncrement - dstToMainVertexA; // distance to the closest main vertex below float dstPercentFromAToB = dstToMainVertexA / (float)skipIncrement; float heightMainVertexA = heightMap[(isVertical) ? x : x - dstToMainVertexA, (isVertical) ? y - dstToMainVertexA : y]; float heightMainVertexB = heightMap[(isVertical) ? x : x + dstToMainVertexB, (isVertical) ? y + dstToMainVertexB : y]; height = heightMainVertexA * (1 - dstPercentFromAToB) + heightMainVertexB * dstPercentFromAToB; } meshData.AddVertex(new Vector3(vertexPosition2D.x, height, vertexPosition2D.y), percent, vertexIndex); //should we create a triangle bool createTriangle = x < numVertsPerLine - 1 && y < numVertsPerLine - 1 && (!isEdgeConnectionVertex || (x != 2 && y != 2)); //if we aren't on the finishing edges/half of the outside edge if (createTriangle) { //the size of the triangle int currentIncrement = (isMainVertex && x != numVertsPerLine - 3 && y != numVertsPerLine - 3) ? skipIncrement : 1; //the indicies our 2 triangles are being made of int a = vertexIndiciesMap[x, y]; int b = vertexIndiciesMap[x + currentIncrement, y]; int c = vertexIndiciesMap[x, y + currentIncrement]; int d = vertexIndiciesMap[x + currentIncrement, y + currentIncrement]; //adding triangles to the mesh Data meshData.AddTriangle(a, d, c); meshData.AddTriangle(d, a, b); } } } } //calculate the normals meshData.ProcessMesh(); //return the meshData return(meshData); }
public static MeshData GenerateTerrainMesh(float[,] heightMap, MeshSettings meshSettings, int levelOfDetail) { var skipIncrement = (levelOfDetail == 0) ? 1 : levelOfDetail * 2; int numVertsPerLine = meshSettings.NumberOfVerticesPerLine; Vector2 topLeft = new Vector2(-1, 1) * meshSettings.MeshWorldSize / 0.5f; var meshData = new MeshData(numVertsPerLine, skipIncrement, meshSettings.useFlatShading); var vertexIndicesMap = new int[numVertsPerLine, numVertsPerLine]; var meshVertexIndex = 0; var outOfMeshVertexIndex = -1; for (var y = 0; y < numVertsPerLine; y++) { for (var x = 0; x < numVertsPerLine; x++) { bool isOutOfMeshVertex = y == 0 || y == numVertsPerLine - 1 || x == 0 || x == numVertsPerLine - 1; bool isSkippedVertex = x > 2 && x < numVertsPerLine - 3 && y > 2 && y < numVertsPerLine - 3 && ((x - 2) % skipIncrement != 0 || (y - 2) % skipIncrement != 0); if (isOutOfMeshVertex) { vertexIndicesMap[x, y] = outOfMeshVertexIndex; --outOfMeshVertexIndex; } else if (!isSkippedVertex) { vertexIndicesMap[x, y] = meshVertexIndex; ++meshVertexIndex; } } } for (var y = 0; y < numVertsPerLine; y++) { for (var x = 0; x < numVertsPerLine; x++) { bool isSkippedVertex = x > 2 && x < numVertsPerLine - 3 && y > 2 && y < numVertsPerLine - 3 && ((x - 2) % skipIncrement != 0 || (y - 2) % skipIncrement != 0); if (!isSkippedVertex) { bool isOutOfMeshVertex = y == 0 || y == numVertsPerLine - 1 || x == 0 || x == numVertsPerLine - 1; bool isMeshEdgeVertex = (y == 1 || y == numVertsPerLine - 2 || x == 1 || x == numVertsPerLine - 2) && !isOutOfMeshVertex; bool isMainVertex = (x - 2) % skipIncrement == 0 && (y - 2) % skipIncrement == 0 && !isOutOfMeshVertex && !isMeshEdgeVertex; bool isEdgeConnectionVertex = ((y == 2) || y == numVertsPerLine - 3 || x == 2 || x == numVertsPerLine - 3) && !isOutOfMeshVertex && !isMeshEdgeVertex && !isMainVertex; var vertexIndex = vertexIndicesMap[x, y]; var percent = new Vector2(x - 1, y - 1) / (numVertsPerLine - 3); var vertexPosition2D = topLeft + new Vector2(percent.x, -percent.y) * meshSettings.MeshWorldSize; var height = heightMap[x, y]; if (isEdgeConnectionVertex) { bool isVertical = x == 2 || x == numVertsPerLine - 3; int distanceToMainVertexA = ((isVertical ? y : x) - 2) % skipIncrement; int distanceToMainVertexB = skipIncrement - distanceToMainVertexA; float distancePercentFromAToB = distanceToMainVertexA / (float)skipIncrement; float heightMainVertexA = heightMap[(isVertical ? x : x - distanceToMainVertexA), (isVertical ? y - distanceToMainVertexA : y)]; float heightMainVertexB = heightMap[(isVertical ? x : x + distanceToMainVertexB), (isVertical ? y + distanceToMainVertexB : y)]; height = heightMainVertexA * (1 - distancePercentFromAToB) + heightMainVertexB * distancePercentFromAToB; } meshData.AddVertex(new Vector3(vertexPosition2D.x, height, vertexPosition2D.y), percent, vertexIndex); bool createTriangle = x < numVertsPerLine - 1 && y < numVertsPerLine - 1 && (!isEdgeConnectionVertex || (x != 2 && y != 2)); if (createTriangle) { int currentIncrement = (isMainVertex && x != numVertsPerLine - 3 && y != numVertsPerLine - 3) ? skipIncrement : 1; var a = vertexIndicesMap[x, y]; var b = vertexIndicesMap[x + currentIncrement, y]; var c = vertexIndicesMap[x, y + currentIncrement]; var d = vertexIndicesMap[x + currentIncrement, y + currentIncrement]; meshData.AddTriangle(a, d, c); meshData.AddTriangle(d, a, b); } } } } meshData.ProcessMesh(); return(meshData); }
public static MeshData GenerateMesh(float[,] heightMap, float heightMultiplier, AnimationCurve heightCurve, int levelOfDetail, bool useFlatShading) { AnimationCurve meshHeightCurve = new AnimationCurve(heightCurve.keys); int meshSimplificationIncrement = (levelOfDetail == 0) ? 1 : levelOfDetail * 2;//if level of detail is set to 0 make it equal to 1 instead of multiplying it by two int borderedSize = heightMap.GetLength(0);//border around verteces used to calculate normals int meshSize = borderedSize - 2 * meshSimplificationIncrement; int meshSizeUnsimplified = borderedSize - 2; float topLeftX = (meshSizeUnsimplified - 1) / -2f; float topLeftZ = (meshSizeUnsimplified - 1) / 2f; int verticesPerLine = (meshSize - 1) / meshSimplificationIncrement + 1; MeshData meshData = new MeshData(verticesPerLine, useFlatShading); int[,] vertexIndicesMap = new int[borderedSize, borderedSize]; int meshVertexIndex = 0; int borderVertexIndex = -1; for (int y = 0; y < borderedSize; y += meshSimplificationIncrement) { for (int x = 0; x < borderedSize; x += meshSimplificationIncrement) { bool isBorderVertex = y == 0 || y == borderedSize - 1 || x == 0 || x == borderedSize - 1; if (isBorderVertex) { vertexIndicesMap[x, y] = borderVertexIndex; borderVertexIndex--; } else { vertexIndicesMap[x, y] = meshVertexIndex; meshVertexIndex++; } } } for (int y = 0; y < borderedSize; y += meshSimplificationIncrement) { for (int x = 0; x < borderedSize; x += meshSimplificationIncrement) { int vertexIndex = vertexIndicesMap[x, y]; Vector2 percent = new Vector2((x - meshSimplificationIncrement) / (float)meshSize, (y - meshSimplificationIncrement) / (float)meshSize); float height = meshHeightCurve.Evaluate(heightMap[x, y]) * heightMultiplier; Vector3 vertexPosition = new Vector3(topLeftX + percent.x * meshSizeUnsimplified, height, topLeftZ - percent.y * meshSizeUnsimplified);//toplefts allow the map to be centered meshData.AddVertex(vertexPosition, percent, vertexIndex); if (x < borderedSize - 1 && y < borderedSize - 1)//these two lines create two triangles out of the vertices { int a = vertexIndicesMap[x, y]; int b = vertexIndicesMap[x + meshSimplificationIncrement, y]; int c = vertexIndicesMap[x, y + meshSimplificationIncrement]; int d = vertexIndicesMap[x + meshSimplificationIncrement, y + meshSimplificationIncrement]; meshData.AddTriangle(a, d, c); meshData.AddTriangle(d, a, b); } vertexIndex += 1; } } meshData.ProcessMesh(); return(meshData);//returns meshData for threading so that the game doesnt freeze up when we generate chunks }
/** * Method that generates the mesh values, including the vertices and triangles * @param heightMap The height map which supplies height values to the mesh * @param heightMultiplier Value that is multiplied with the height; allows the elevation of the terrain to be more visible * @param _heightCurve The curve that determines the level of effect the heightMultiplier has on a given elevation * @param levelOfDetail A value that determines the number of vertices and triangles in the mesh * @param useFlatShading Bool that determines if flat shading is enables or not * @return meshData The data of the mesh */ public static MeshData GenerateTerrainMesh(float[,] heightMap, float heightMultiplier, AnimationCurve _heightCurve, int levelOfDetail, bool useFlatShading) { // Created a new animation curve to avoid a weird issue from occurring AnimationCurve heightCurve = new AnimationCurve(_heightCurve.keys); // Implement level of detail; avoid the zero case int meshIncrement = (levelOfDetail == 0) ? 1 : levelOfDetail * 2; int borderedSize = heightMap.GetLength(0); int meshSize = borderedSize - (2 * meshIncrement); int meshSizeUnsimplified = borderedSize - 2; // Values used in calculating the mesh vertices float topLeftX = (meshSizeUnsimplified - 1) / -2f; float topLeftZ = (meshSizeUnsimplified - 1) / 2f; int verticesPerLine = ((meshSize - 1) / meshIncrement) + 1; MeshData meshData = new MeshData(verticesPerLine, useFlatShading); int[,] vertexIndicesMap = new int[borderedSize, borderedSize]; int meshVertexIndex = 0; int borderedVertexIndex = -1; // Implement border indices and mesh indices for (int y = 0; y < borderedSize; y += meshIncrement) { for (int x = 0; x < borderedSize; x += meshIncrement) { bool isBorderVertex = (y == 0) || (y == borderedSize - 1) || (x == 0) || (x == borderedSize - 1); if (isBorderVertex) { vertexIndicesMap[x, y] = borderedVertexIndex; borderedVertexIndex--; } else { vertexIndicesMap[x, y] = meshVertexIndex; meshVertexIndex++; } } } // Where the mesh values are all assigned for (int y = 0; y < borderedSize; y += meshIncrement) { for (int x = 0; x < borderedSize; x += meshIncrement) { int vertexIndex = vertexIndicesMap[x, y]; Vector2 percent = new Vector2((x - meshIncrement) / (float)meshSize, (y - meshIncrement) / (float)meshSize); float height = heightCurve.Evaluate(heightMap[x, y]) * heightMultiplier; Vector3 vertexPosition = new Vector3(topLeftX + (percent.x * meshSizeUnsimplified), height, topLeftZ - (percent.y * meshSizeUnsimplified)); meshData.AddVertex(vertexPosition, percent, vertexIndex); if (x < (borderedSize - 1) && y < (borderedSize - 1)) { // Vertices for our two triangles int a = vertexIndicesMap[x, y]; int b = vertexIndicesMap[x + meshIncrement, y]; int c = vertexIndicesMap[x, y + meshIncrement]; int d = vertexIndicesMap[x + meshIncrement, y + meshIncrement]; meshData.AddTriangle(a, d, c); meshData.AddTriangle(d, a, b); } vertexIndex++; } } meshData.ProcessMesh(); return(meshData); }
/// <summary> /// Generates mesh data from a height map with customisable settings. /// </summary> /// <param name="heightMap">The height map values.</param> /// <param name="meshSettings">Mesh settings to vary the mesh.</param> /// <param name="levelOfDetail">The level of detail of the mesh.</param> /// <returns>Collections of vertices and triangles that make up the mesh.</returns> public static MeshData GenerateTerrainMesh(float[,] heightMap, MeshSettings meshSettings, int levelOfDetail) { // the amount of vertices skipped each line int skipIncrement = (levelOfDetail == 0) ? 1 : levelOfDetail * 2; // the number of vertices in each line int numVertsPerLine = meshSettings.NumVertsPerLine; // the top left coordinate of the mesh Vector2 topLeft = new Vector2(-1, 1) * meshSettings.MeshWorldSize / 2.0f; // initialises a mesh's vertices and triangles MeshData meshData = new MeshData(numVertsPerLine, skipIncrement, meshSettings.useFlatShading); // the index of each vertex int[,] vertexIndicesMap = new int[numVertsPerLine, numVertsPerLine]; // the index of the current vertex int meshVertexIndex = 0; // the index of the current vertex not in the mesh bounds int outOfMeshVertexIndex = -1; // for every index of the index map, determine if the vertex is in or out of the mesh for (int y = 0; y < numVertsPerLine; y++) { for (int x = 0; x < numVertsPerLine; x++) { // determines if the vertex is out of the mesh bool isOutOfMeshVertex = y == 0 || y == numVertsPerLine - 1 || x == 0 || x == numVertsPerLine - 1; // determines if the vertex is skipped bool isSkippedVertex = x > 2 && x < numVertsPerLine - 3 && y > 2 && y < numVertsPerLine - 3 && ((x - 2) % skipIncrement != 0 || (y - 2) % skipIncrement != 0); // adds an out of mesh vertex index to the map if (isOutOfMeshVertex) { vertexIndicesMap[x, y] = outOfMeshVertexIndex; outOfMeshVertexIndex--; } // adds an in mesh vertex index to the map if it is not skipped else if (!isSkippedVertex) { vertexIndicesMap[x, y] = meshVertexIndex; meshVertexIndex++; } } } // adds the vertex positions to the mesh data for (int y = 0; y < numVertsPerLine; y++) { for (int x = 0; x < numVertsPerLine; x++) { // determines if the vertex is skipped bool isSkippedVertex = x > 2 && x < numVertsPerLine - 3 && y > 2 && y < numVertsPerLine - 3 && ((x - 2) % skipIncrement != 0 || (y - 2) % skipIncrement != 0); // checks if the vertex is not skipped if (!isSkippedVertex) { // determines if the vertex is out of the mesh bool isOutOfMeshVertex = y == 0 || y == numVertsPerLine - 1 || x == 0 || x == numVertsPerLine - 1; // determines if the vertex is on the edge bool isMeshEdgeVertex = (y == 1 || y == numVertsPerLine - 2 || x == 1 || x == numVertsPerLine - 2) && !isOutOfMeshVertex; // determines if the vertex is counted bool isMainVertex = (x - 2) % skipIncrement == 0 && (y - 2) % skipIncrement == 0 && !isOutOfMeshVertex && !isMeshEdgeVertex; // determines if the vertex is being connected to bool isEdgeConnectionVertex = (y == 2 || y == numVertsPerLine - 3 || x == 2 || x == numVertsPerLine - 3) && !isOutOfMeshVertex && !isMeshEdgeVertex && !isMainVertex; // the index of the vertex in the mesh int vertexIndex = vertexIndicesMap[x, y]; // calculates the vertex's position as a percentage between main vertices Vector2 percent = new Vector2(x - 1, y - 1) / (numVertsPerLine - 3); // gets the 2D position of the vertex Vector2 vertexPosition2D = topLeft + new Vector2(percent.x, -percent.y) * meshSettings.MeshWorldSize; // gets the height value of the vertex from the height map float height = heightMap[x, y]; // checks if the vertex is being connected to along the edge if (isEdgeConnectionVertex) { // determines if the connection is along the left or right side bool isVertical = x == 2 || x == numVertsPerLine - 3; // gets the distances to the main vertices int distToMainVertexA = ((isVertical) ? y - 2 : x - 2) % skipIncrement; int distToMainVertexB = skipIncrement - distToMainVertexA; // gets the distance as a percentage between the two float distPercentFromAToB = distToMainVertexA / (float)skipIncrement; // gets the height of the two vertices float heightOfMainVertexA = heightMap[(isVertical) ? x : x - distToMainVertexA, (isVertical) ? y - distToMainVertexA : y]; float heightOfMainVertexB = heightMap[(isVertical) ? x : x + distToMainVertexB, (isVertical) ? y + distToMainVertexB : y]; // averages out the height height = heightOfMainVertexA * (1 - distPercentFromAToB) + heightOfMainVertexB * distPercentFromAToB; } // adds the vertex to the mesh meshData.AddVertex(new Vector3(vertexPosition2D.x, height, vertexPosition2D.y), percent, vertexIndex); // determines if a triangle should be made based on if it is not on an edge bool createTriangle = x < numVertsPerLine - 1 && y < numVertsPerLine - 1 && (!isEdgeConnectionVertex || (x != 2 && y != 2)); // checks if a triangle should be made if (createTriangle) { int currentIncrement = (isMainVertex && x != numVertsPerLine - 3 && y != numVertsPerLine - 3) ? skipIncrement : 1; // gets the 4 vertices of a tile of the mesh int a = vertexIndicesMap[x, y]; int b = vertexIndicesMap[x + currentIncrement, y]; int c = vertexIndicesMap[x, y + currentIncrement]; int d = vertexIndicesMap[x + currentIncrement, y + currentIncrement]; // adds 2 triangles to make up a tile meshData.AddTriangle(a, d, c); meshData.AddTriangle(d, a, b); } } } } // calculates the normals of the mesh meshData.ProcessMesh(); return(meshData); }
public static MeshData GenerateTerrainMesh(float[,] heightMap, MeshSettings meshSettings, int levelOfDetail) { // so further meshes don't have to be as detailed int meshSimplificationIncrement = (levelOfDetail == 0) ? 1 : levelOfDetail * 2; int borderedSize = heightMap.GetLength(0); int meshSize = borderedSize - 2 * meshSimplificationIncrement; int meshSizeUnsimplified = borderedSize - 2; float topLeftX = (meshSizeUnsimplified - 1) / -2f; float topLeftZ = (meshSizeUnsimplified - 1) / 2f; int verticesPerLine = (meshSize - 1) / meshSimplificationIncrement + 1; MeshData meshData = new MeshData(verticesPerLine, meshSettings.useFlatShading); // int vertexIndex = 0; int[,] vertexIndicesMap = new int[borderedSize, borderedSize]; int meshVertexIndex = 0; int borderVertexIndex = -1; for (int y = 0; y < borderedSize; y += meshSimplificationIncrement) { for (int x = 0; x < borderedSize; x += meshSimplificationIncrement) { bool isBorderVertex = y == 0 || y == borderedSize - 1 || x == 0 || x == borderedSize - 1; if (isBorderVertex) { vertexIndicesMap[x, y] = borderVertexIndex; borderVertexIndex--; } else { vertexIndicesMap[x, y] = meshVertexIndex; meshVertexIndex++; } } } for (int y = 0; y < borderedSize; y += meshSimplificationIncrement) { for (int x = 0; x < borderedSize; x += meshSimplificationIncrement) { int vertexIndex = vertexIndicesMap[x, y]; // make sure the UVs are properly centered by subtracting meshSimplificationIncrement Vector2 percent = new Vector2((x - meshSimplificationIncrement) / (float)meshSize, (y - meshSimplificationIncrement) / (float)meshSize); float height = heightMap[x, y]; Vector3 vertexPosition = new Vector3((topLeftX + percent.x * meshSizeUnsimplified), height, (topLeftZ - percent.y * meshSizeUnsimplified)); //Vector3 vertexPosition = new Vector3((topLeftX + percent.x * meshSizeUnsimplified) * meshSettings.meshScale, height, (topLeftZ - percent.y * meshSizeUnsimplified) * meshSettings.meshScale); meshData.AddVertex(vertexPosition, percent, vertexIndex); // if not bottom or far right, add square // x,y --- x+1,y // | \ | // x,y+i --- x+i,y+i if (x < borderedSize - 1 && y < borderedSize - 1) { int a = vertexIndicesMap[x, y]; int b = vertexIndicesMap[x + meshSimplificationIncrement, y]; int c = vertexIndicesMap[x, y + meshSimplificationIncrement]; int d = vertexIndicesMap[x + meshSimplificationIncrement, y + meshSimplificationIncrement]; meshData.AddTriangle(a, d, c); meshData.AddTriangle(d, a, b); } vertexIndex++; } } meshData.ProcessMesh(); return(meshData); // return meshData, not mesh for treading later }
public static MeshData GenerateTerrainMesh(float[,] heightMap, MeshSettings meshSettings, int levelOfDetail) { int skipIncrement = levelOfDetail * 2; int verticesPerLine = meshSettings.numVerticesPerLine; Vector2 topLeft = new Vector2(-1, 1) * meshSettings.meshWorldSize / 2f; if (levelOfDetail == 0) { skipIncrement = 1; } MeshData meshData = new MeshData(verticesPerLine, skipIncrement, meshSettings.useFlatShading); int[,] vertexIndicesMap = new int[verticesPerLine, verticesPerLine]; int meshVertexIndex = 0; int outOfMeshVertexIndex = -1; for (int z = 0; z < verticesPerLine; z++) { for (int x = 0; x < verticesPerLine; x++) { bool isOutOfMeshVertex = z == 0 || z == verticesPerLine - 1 || x == 0 || x == verticesPerLine - 1; bool isSkippedVertex = MeshGenerator.isSkippedVertex(skipIncrement, verticesPerLine, z, x); if (isOutOfMeshVertex) { vertexIndicesMap[x, z] = outOfMeshVertexIndex; outOfMeshVertexIndex--; } else if (!isSkippedVertex) { vertexIndicesMap[x, z] = meshVertexIndex; meshVertexIndex++; } } } for (int z = 0; z < verticesPerLine; z++) { for (int x = 0; x < verticesPerLine; x++) { bool isSkippedVertex = MeshGenerator.isSkippedVertex(skipIncrement, verticesPerLine, z, x); if (!isSkippedVertex) { bool isOutOfMeshVertex = z == 0 || z == verticesPerLine - 1 || x == 0 || x == verticesPerLine - 1; bool isMeshEdgeVertex = (z == 1 || z == verticesPerLine - 2 || x == 1 || x == verticesPerLine - 2) && !isOutOfMeshVertex; bool isMainVertex = (x - 2) % skipIncrement == 0 && (z - 2) % skipIncrement == 0 && !isOutOfMeshVertex && !isMeshEdgeVertex; bool isEdgeConnectionVertex = (z == 2 || z == verticesPerLine - 3 || x == 2 || x == verticesPerLine - 3) && !isOutOfMeshVertex && !isMeshEdgeVertex && !isMainVertex; int vertexIndex = vertexIndicesMap[x, z]; Vector2 percent = new Vector2(x - 1, z - 1) / (verticesPerLine - 3); Vector2 vertexPosition2D = topLeft + new Vector2(percent.x, -percent.y) * meshSettings.meshWorldSize; float height = heightMap[x, z]; if (isEdgeConnectionVertex) { bool isVertical = x == 2 || x == verticesPerLine - 3; int distanceToMainVertexA = isVertical ? z : x; distanceToMainVertexA = (distanceToMainVertexA - 2) % skipIncrement; int distanceToMainVertexB = skipIncrement - distanceToMainVertexA; float distancePercentFromAToB = distanceToMainVertexA / (float)skipIncrement; float heightMainVertexA = heightMap[(isVertical) ? x : x - distanceToMainVertexA, (isVertical) ? z - distanceToMainVertexA : z]; float heightMainVertexB = heightMap[(isVertical) ? x : x + distanceToMainVertexB, (isVertical) ? z + distanceToMainVertexB : z]; height = heightMainVertexA * (1 - distancePercentFromAToB) + heightMainVertexB * distancePercentFromAToB; } meshData.AddVertex(new Vector3(vertexPosition2D.x, height, vertexPosition2D.y), percent, vertexIndex); bool shouldCreateTriangle = x < verticesPerLine - 1 && z < verticesPerLine - 1 && (!isEdgeConnectionVertex || (x != 2 && z != 2)); if (shouldCreateTriangle) { int currentIncrement = 1; if (isMainVertex && x != verticesPerLine - 3 && z != verticesPerLine - 3) { currentIncrement = skipIncrement; } int a = vertexIndicesMap[x, z]; int b = vertexIndicesMap[x + currentIncrement, z]; int c = vertexIndicesMap[x, z + currentIncrement]; int d = vertexIndicesMap[x + currentIncrement, z + currentIncrement]; meshData.AddTriangle(a, d, c); meshData.AddTriangle(d, a, b); } } } } meshData.ProcessMesh(); return(meshData); }
public static MeshData TestMeshData(float[,] heightMap, MeshSettings meshSettings) { Vector2 topLeft = new Vector2(-1, 1) * meshSettings.meshWorldSize / 2; int numVertsPerLine = meshSettings.numVertsPerLine; MeshData meshData = new MeshData(numVertsPerLine); int[,] vertexIndicesMap = new int[numVertsPerLine, numVertsPerLine]; int meshVertexIndex = 0; int outOfMeshVertexIndex = -1; for (int y = 0; y < numVertsPerLine; y++) { for (int x = 0; x < numVertsPerLine; x++) { bool isOutOfMeshVertex = y == 0 || y == numVertsPerLine - 1 || x == 0 || x == numVertsPerLine - 1; if (isOutOfMeshVertex) { vertexIndicesMap[x, y] = outOfMeshVertexIndex; outOfMeshVertexIndex--; } else { vertexIndicesMap[x, y] = meshVertexIndex; meshVertexIndex++; } } } for (int x = 0; x < numVertsPerLine; x++) { for (int y = 0; y < numVertsPerLine; y++) { //bool isOutOfMeshVertex = y == 0 || y == numVertsPerLine - 1 || x == 0 || x == numVertsPerLine - 1; //bool isMeshEdgeVertex = (y == 1 || y == numVertsPerLine - 2 || x == 1 || x == numVertsPerLine - 2) && !isOutOfMeshVertex; //bool isMainVertex = !isOutOfMeshVertex && !isMeshEdgeVertex; int vertexIndex = vertexIndicesMap[x, y]; Vector2 percent = new Vector2(x - 1, y - 1) / (numVertsPerLine - 3); Vector2 vertexPosition2D = topLeft + new Vector2(percent.x, -percent.y) * meshSettings.meshWorldSize; float height = heightMap[x, y]; meshData.AddVertex(new Vector3(vertexPosition2D.x, height, vertexPosition2D.y), percent, vertexIndex); bool createTriangle = x < numVertsPerLine - 1 && y < numVertsPerLine - 1; if (createTriangle) { int currentIncrement = 1; int a = vertexIndicesMap[x, y]; int b = vertexIndicesMap[x + currentIncrement, y]; int c = vertexIndicesMap[x, y + currentIncrement]; int d = vertexIndicesMap[x + currentIncrement, y + currentIncrement]; meshData.AddTriangle(a, d, c); meshData.AddTriangle(d, a, b); } } } meshData.ProcessMesh(); return(meshData); }
public static MeshData GenerateTerrainMesh(float[,] heightMap, float heightMultiplier, AnimationCurve _heightCurve, int levelOfDetail, bool useFlatShading) { AnimationCurve heightCurve = new AnimationCurve (_heightCurve.keys); int meshSimplificationIncrement = (levelOfDetail == 0)?1:levelOfDetail * 2; int borderedSize = heightMap.GetLength (0); int meshSize = borderedSize - 2*meshSimplificationIncrement; int meshSizeUnsimplified = borderedSize - 2; float topLeftX = (meshSizeUnsimplified - 1) / -2f; float topLeftZ = (meshSizeUnsimplified - 1) / 2f; int verticesPerLine = (meshSize - 1) / meshSimplificationIncrement + 1; MeshData meshData = new MeshData (verticesPerLine,useFlatShading); int[,] vertexIndicesMap = new int[borderedSize,borderedSize]; int meshVertexIndex = 0; int borderVertexIndex = -1; for (int y = 0; y < borderedSize; y += meshSimplificationIncrement) { for (int x = 0; x < borderedSize; x += meshSimplificationIncrement) { bool isBorderVertex = y == 0 || y == borderedSize - 1 || x == 0 || x == borderedSize - 1; if (isBorderVertex) { vertexIndicesMap [x, y] = borderVertexIndex; borderVertexIndex--; } else { vertexIndicesMap [x, y] = meshVertexIndex; meshVertexIndex++; } } } for (int y = 0; y < borderedSize; y += meshSimplificationIncrement) { for (int x = 0; x < borderedSize; x += meshSimplificationIncrement) { int vertexIndex = vertexIndicesMap [x, y]; Vector2 percent = new Vector2 ((x-meshSimplificationIncrement) / (float)meshSize, (y-meshSimplificationIncrement) / (float)meshSize); float height = heightCurve.Evaluate (heightMap [x, y]) * heightMultiplier; Vector3 vertexPosition = new Vector3 (topLeftX + percent.x * meshSizeUnsimplified, height, topLeftZ - percent.y * meshSizeUnsimplified); meshData.AddVertex (vertexPosition, percent, vertexIndex); if (x < borderedSize - 1 && y < borderedSize - 1) { int a = vertexIndicesMap [x, y]; int b = vertexIndicesMap [x + meshSimplificationIncrement, y]; int c = vertexIndicesMap [x, y + meshSimplificationIncrement]; int d = vertexIndicesMap [x + meshSimplificationIncrement, y + meshSimplificationIncrement]; meshData.AddTriangle (a,d,c); meshData.AddTriangle (d,a,b); } vertexIndex++; } } meshData.ProcessMesh (); return meshData; }
// this returns MeshData (instead of Mesh) because we need the individual data points that allow multi-threading to be possible public static MeshData GenerateTerrainMeshData(float[,] heightMap, float heightMultiplier, AnimationCurve _heightCurve, int levelOfDetail, bool applyFlatShading) { // each thread has its own heightCurve with this statement (so no wild discrepancies as a result) AnimationCurve heightCurve = new AnimationCurve(_heightCurve.keys); int borderedSize = heightMap.GetLength(0); int meshSimplificationIncrement = levelOfDetail == 0 ? 1 : levelOfDetail * 2; int meshSizeSimplified = borderedSize - 2 * meshSimplificationIncrement; int meshSizeUnsimplified = borderedSize - 2; float topLeftX = (meshSizeUnsimplified - 1) / -2f; float topLeftZ = (meshSizeUnsimplified - 1) / 2f; int verticesPerLine = (meshSizeSimplified - 1) / meshSimplificationIncrement + 1; MeshData meshData = new MeshData(verticesPerLine, applyFlatShading); int[,] vertexIndicesMap = new int[borderedSize, borderedSize]; int borderVertexIndex = -1; int meshVertexIndex = 0; for (int y = 0; y < borderedSize; y += meshSimplificationIncrement) { for (int x = 0; x < borderedSize; x += meshSimplificationIncrement) { bool isBorderVertex = y == 0 || y == borderedSize - 1 || x == 0 || x == borderedSize - 1; if (isBorderVertex) { vertexIndicesMap[x, y] = borderVertexIndex; borderVertexIndex--; } else { vertexIndicesMap[x, y] = meshVertexIndex; meshVertexIndex++; } } } for (int y = 0; y < borderedSize; y += meshSimplificationIncrement) { for (int x = 0; x < borderedSize; x += meshSimplificationIncrement) { int vertexIndex = vertexIndicesMap[x, y]; Vector2 percent = new Vector2((x - meshSimplificationIncrement) / (float)meshSizeSimplified, (y - meshSimplificationIncrement) / (float)meshSizeSimplified); float height = heightCurve.Evaluate(heightMap[x, y]) * heightMultiplier; Vector3 vertexPosition = new Vector3(topLeftX + percent.x * meshSizeUnsimplified, height, topLeftZ - percent.y * meshSizeUnsimplified); meshData.AddVertex(vertexPosition, percent, vertexIndex); if (x < borderedSize - 1 && y < borderedSize - 1) { int a = vertexIndicesMap[x, y]; int b = vertexIndicesMap[x + meshSimplificationIncrement, y]; int c = vertexIndicesMap[x, y + meshSimplificationIncrement]; int d = vertexIndicesMap[x + meshSimplificationIncrement, y + meshSimplificationIncrement]; meshData.AddTriangle(a, d, c); meshData.AddTriangle(d, a, b); } vertexIndex++; } } meshData.ProcessMesh(); return(meshData); }
public static MeshData GenerateTerrainMesh(float[,] heightMap, float meshHeightMultiplier, AnimationCurve _heightCurve, int levelOfDetail, bool useFlatShading) { AnimationCurve heightCurve = new AnimationCurve(_heightCurve.keys); int meshSimplificationIncrement = (levelOfDetail == 0) ? 1 : levelOfDetail * 2; int borderedSize = heightMap.GetLength(0); int meshSize = borderedSize - 2 * meshSimplificationIncrement; int meshSizeUnsimplified = borderedSize - 2; float topLeftX = (meshSizeUnsimplified - 1) / -2f; // Vai servir para centrar verticalmente float topLeftZ = (meshSizeUnsimplified - 1) / 2f; // Vai servir para centrar horizontalmente int verticesPerLine = (meshSize - 1) / meshSimplificationIncrement + 1; MeshData meshData = new MeshData(verticesPerLine, useFlatShading); int[,] vertexIndicesMap = new int[borderedSize, borderedSize]; int meshVertexIndex = 0; int borderVertexIndex = -1; for (int y = 0; y < borderedSize; y += meshSimplificationIncrement) { for (int x = 0; x < borderedSize; x += meshSimplificationIncrement) { bool isBorderVertex = y == 0 || y == borderedSize - 1 || x == 0 || x == borderedSize - 1; if (isBorderVertex) { vertexIndicesMap[x, y] = borderVertexIndex; borderVertexIndex--; } else { vertexIndicesMap[x, y] = meshVertexIndex; meshVertexIndex++; } } } for (int y = 0; y < borderedSize; y += meshSimplificationIncrement) { for (int x = 0; x < borderedSize; x += meshSimplificationIncrement) { int vertexIndex = vertexIndicesMap[x, y]; // O UV é posição em relação ao mapa, em percentagem (0 a 1) Vector2 percent = new Vector2((x - meshSimplificationIncrement) / (float)meshSize, (y - meshSimplificationIncrement) / (float)meshSize); float height = heightCurve.Evaluate(heightMap[x, y]) * meshHeightMultiplier; // A posição dos vértices na Mesh é baseado no canto superior esquerdo, para centrar Vector3 vertexPosition = new Vector3(topLeftX + percent.x * meshSizeUnsimplified, height, topLeftZ - percent.y * meshSizeUnsimplified); meshData.AddVertex(vertexPosition, percent, vertexIndex); // Calcular os triângulos ligados a cada vértice, que está no mapa de vértices if (x < borderedSize - 1 && y < borderedSize - 1) { // Estamos no vértice a, vamos adicionar os dois triângulos abaixo. // A ORDEM DE ROTACAO É IMPORTANTE!!! // a - b // | \ | // c - d int a = vertexIndicesMap[x, y]; int b = vertexIndicesMap[x + meshSimplificationIncrement, y]; int c = vertexIndicesMap[x, y + meshSimplificationIncrement]; int d = vertexIndicesMap[x + meshSimplificationIncrement, y + meshSimplificationIncrement]; // Triângulo definido pelos vértices: a-d-c meshData.AddTriangles(a, d, c); // Triângulo definido pelos véritices: d-a-b meshData.AddTriangles(d, a, b); } } } meshData.ProcessMesh(); return(meshData); }
public static MeshData GenerateTerrainMesh(float[,] heightMap, float heightMultiplier, AnimationCurve heightCurve, int levelOfDetail, bool useFlatShading) { //cf meshSize = borderedSize - 2 int borderedSize = heightMap.GetLength(0); int meshSimplificationIncrement = levelOfDetail.Equals(0)? 1: levelOfDetail * 2; int meshSize = borderedSize - 2 * meshSimplificationIncrement; int meshSizeUnsimplified = borderedSize - 2; //use to calculate topleftX and topLeftZ int verticesPerLine = (meshSize - 1) / meshSimplificationIncrement + 1; MeshData meshData = new MeshData(verticesPerLine, useFlatShading); //To center the vertices at the center float topLeftX = (meshSizeUnsimplified - 1) / -2f; //do not forget the -1 and the f for -2f to yield a float result float topLeftZ = (meshSizeUnsimplified - 1) / 2f; // positive 2f because the z goes up (-1 0 1 => x = (width - 1)/(-2)) float floatMeshSize = (float)meshSize; float vertexX = 0f; float vertexY = 0f; float vertexZ = 0f; AnimationCurve aHeightCurve = new AnimationCurve(heightCurve.keys); //a great improvisation over the generation int[,] vertexIndicesMap = new int[borderedSize, borderedSize]; int meshVertexIndex = 0; int borderVertexIndex = -1; for (int y = 0; y < borderedSize; y += meshSimplificationIncrement) { for (int x = 0; x < borderedSize; x += meshSimplificationIncrement) { bool isBorderVertex = (y == 0 || y == borderedSize - 1 || x == 0 || x == borderedSize - 1); if (isBorderVertex) { vertexIndicesMap [x, y] = borderVertexIndex; borderVertexIndex--; } else { vertexIndicesMap [x, y] = meshVertexIndex; meshVertexIndex++; } } } int vertexIndex; Vector3 vertexPosition; Vector2 percent; for (int y = 0; y < borderedSize; y += meshSimplificationIncrement) { for (int x = 0; x < borderedSize; x += meshSimplificationIncrement) { vertexIndex = vertexIndicesMap[x, y]; // tell each vertex where it is in relation to the rest of the map as a percentage for both the x and the y axis //it is a percentage between 0 and 1 percent = new Vector2( (x - meshSimplificationIncrement) / floatMeshSize, (y - meshSimplificationIncrement) / floatMeshSize); vertexX = topLeftX + percent.x * meshSizeUnsimplified; vertexY = aHeightCurve.Evaluate(heightMap [x, y]) * heightMultiplier; vertexZ = topLeftZ - percent.y * meshSizeUnsimplified; //we don't want to move down from topLeftZ, we move down the y value vertexPosition = new Vector3(vertexX, vertexY, vertexZ); meshData.AddVertex(vertexPosition, percent, vertexIndex); if (x < borderedSize - 1 && y < borderedSize - 1) // we ignore the vertices at the most rigth and the most bottom { int a = vertexIndicesMap [x, y]; int b = vertexIndicesMap [x + meshSimplificationIncrement, y]; int c = vertexIndicesMap [x, y + meshSimplificationIncrement]; int d = vertexIndicesMap [x + meshSimplificationIncrement, y + meshSimplificationIncrement]; meshData.AddTriangle(a, d, c); // first triangle (clock wise on a square) meshData.AddTriangle(d, a, b); // second triangle } vertexIndex++; } } meshData.ProcessMesh(); return(meshData); //useful to threading instead of returning the mesh, we return the meshData }
public static MeshData GenerateTerrainMesh(float[,] _heightMap, float _heightMultiplier, AnimationCurve _heightCurve, int _levelOfDetail, bool _useFlatShading) { int meshSimplificationIncrement = (_levelOfDetail == 0) ? 1 : _levelOfDetail * 2; // Allows each thread to use the animation curve without locking the thread AnimationCurve heightCurve = new AnimationCurve(_heightCurve.keys); int borderedSize = _heightMap.GetLength(0); int meshSize = borderedSize - 2 * meshSimplificationIncrement; int meshSizeUnsimplified = borderedSize - 2; float topLeftX = (meshSizeUnsimplified - 1) / -2f; float topLeftZ = (meshSizeUnsimplified - 1) / 2f; int verticesPerLine = (meshSize - 1) / meshSimplificationIncrement + 1; MeshData meshData = new MeshData(verticesPerLine, _useFlatShading); int[,] vertextIndicesMap = new int[borderedSize, borderedSize]; int meshVertexIndex = 0; int borderVertexIndex = -1; for (int y = 0; y < borderedSize; y += meshSimplificationIncrement) { for (int x = 0; x < borderedSize; x += meshSimplificationIncrement) { bool isBorderVertex = y == 0 || y == borderedSize - 1 || x == 0 || x == borderedSize - 1; if (isBorderVertex) { vertextIndicesMap[x, y] = borderVertexIndex; borderVertexIndex--; } else { vertextIndicesMap[x, y] = meshVertexIndex; meshVertexIndex++; } } } for (int y = 0; y < borderedSize; y += meshSimplificationIncrement) { for (int x = 0; x < borderedSize; x += meshSimplificationIncrement) { int vertexIndex = vertextIndicesMap[x, y]; Vector2 percent = new Vector2((x - meshSimplificationIncrement) / (float)meshSize, (y - meshSimplificationIncrement) / (float)meshSize); float height = heightCurve.Evaluate(_heightMap[x, y]) * _heightMultiplier; Vector3 vertexPosition = new Vector3(topLeftX + percent.x * meshSizeUnsimplified, height, topLeftZ - percent.y * meshSizeUnsimplified); meshData.AddVertex(vertexPosition, percent, vertexIndex); if (x < borderedSize - 1 && y < borderedSize - 1) { int a = vertextIndicesMap[x, y]; int b = vertextIndicesMap[x + meshSimplificationIncrement, y]; int c = vertextIndicesMap[x, y + meshSimplificationIncrement]; int d = vertextIndicesMap[x + meshSimplificationIncrement, y + meshSimplificationIncrement]; meshData.AddTriangle(a, d, c); meshData.AddTriangle(d, a, b); } vertexIndex++; } } meshData.ProcessMesh(); return(meshData); }
public static MeshData GenerateTerrainMesh(float[,] heightMap, MeshSettings meshSettings, int levelOfDetail) { int skipIncrement = (levelOfDetail == 0)?1:levelOfDetail * 2; int numVertsPerLine = meshSettings.numVertsPerLine; Vector2 topLeft = new Vector2(-1, 1) * meshSettings.meshWorldSize / 2f; MeshData meshData = new MeshData(numVertsPerLine, skipIncrement, meshSettings.useFlatShading); int[,] vertexIndicesMap = new int[numVertsPerLine, numVertsPerLine]; int meshVertexIndex = 0; int outOfMeshVertexIndex = -1; for (int y = 0; y < numVertsPerLine; y++) { for (int x = 0; x < numVertsPerLine; x++) { bool isOutOfMeshVertex = y == 0 || y == numVertsPerLine - 1 || x == 0 || x == numVertsPerLine - 1; bool isSkippedVertex = x > 2 && x < numVertsPerLine - 3 && y > 2 && y < numVertsPerLine - 3 && ((x - 2) % skipIncrement != 0 || (y - 2) % skipIncrement != 0); if (isOutOfMeshVertex) { vertexIndicesMap [x, y] = outOfMeshVertexIndex; outOfMeshVertexIndex--; } else if (!isSkippedVertex) { vertexIndicesMap [x, y] = meshVertexIndex; meshVertexIndex++; } } } for (int y = 0; y < numVertsPerLine; y++) { for (int x = 0; x < numVertsPerLine; x++) { bool isSkippedVertex = x > 2 && x < numVertsPerLine - 3 && y > 2 && y < numVertsPerLine - 3 && ((x - 2) % skipIncrement != 0 || (y - 2) % skipIncrement != 0); if (!isSkippedVertex) { bool isOutOfMeshVertex = y == 0 || y == numVertsPerLine - 1 || x == 0 || x == numVertsPerLine - 1; bool isMeshEdgeVertex = (y == 1 || y == numVertsPerLine - 2 || x == 1 || x == numVertsPerLine - 2) && !isOutOfMeshVertex; bool isMainVertex = (x - 2) % skipIncrement == 0 && (y - 2) % skipIncrement == 0 && !isOutOfMeshVertex && !isMeshEdgeVertex; bool isEdgeConnectionVertex = (y == 2 || y == numVertsPerLine - 3 || x == 2 || x == numVertsPerLine - 3) && !isOutOfMeshVertex && !isMeshEdgeVertex && !isMainVertex; int vertexIndex = vertexIndicesMap [x, y]; Vector2 percent = new Vector2(x - 1, y - 1) / (numVertsPerLine - 3); Vector2 vertexPosition2D = topLeft + new Vector2(percent.x, -percent.y) * meshSettings.meshWorldSize; float height = heightMap [x, y]; if (isEdgeConnectionVertex) { bool isVertical = x == 2 || x == numVertsPerLine - 3; int dstToMainVertexA = ((isVertical)?y - 2:x - 2) % skipIncrement; int dstToMainVertexB = skipIncrement - dstToMainVertexA; float dstPercentFromAToB = dstToMainVertexA / (float)skipIncrement; float heightMainVertexA = heightMap [(isVertical) ? x : x - dstToMainVertexA, (isVertical) ? y - dstToMainVertexA : y]; float heightMainVertexB = heightMap [(isVertical) ? x : x + dstToMainVertexB, (isVertical) ? y + dstToMainVertexB : y]; height = heightMainVertexA * (1 - dstPercentFromAToB) + heightMainVertexB * dstPercentFromAToB; } meshData.AddVertex(new Vector3(vertexPosition2D.x, height, vertexPosition2D.y), percent, vertexIndex); bool createTriangle = x < numVertsPerLine - 1 && y < numVertsPerLine - 1 && (!isEdgeConnectionVertex || (x != 2 && y != 2)); if (createTriangle) { int currentIncrement = (isMainVertex && x != numVertsPerLine - 3 && y != numVertsPerLine - 3) ? skipIncrement : 1; int a = vertexIndicesMap [x, y]; int b = vertexIndicesMap [x + currentIncrement, y]; int c = vertexIndicesMap [x, y + currentIncrement]; int d = vertexIndicesMap [x + currentIncrement, y + currentIncrement]; meshData.AddTriangle(a, d, c); meshData.AddTriangle(d, a, b); } } } } meshData.ProcessMesh(); return(meshData); }
public static MeshData GenerateTerrainMesh(float[,] heightMap, MeshSettings settings, int lod) { int meshSimplificationIncrement = (lod == 0 ? 1 : lod * 2); int borderedSize = heightMap.GetLength(0); int meshSize = borderedSize - 2 * meshSimplificationIncrement; int meshSizeUnsimplified = borderedSize - 2; float topLeftX = (meshSizeUnsimplified - 1) / -2f; float topLeftZ = (meshSizeUnsimplified - 1) / 2f; int verticesPerLine = (meshSize - 1) / meshSimplificationIncrement + 1; MeshData meshData = new MeshData(verticesPerLine, settings.useFlatShading); int[,] vertexIndicesMap = new int[borderedSize, borderedSize]; int meshVertexIndex = 0; int borderVertexIndex = -1; // the idea here is that we calculate the border of vertices around the mesh to calculate normals of adjacent meshes // each border vertex is less than 0, and will get excluded from the final mesh for (int y = 0; y < borderedSize; y += meshSimplificationIncrement) { for (int x = 0; x < borderedSize; x += meshSimplificationIncrement) { bool isBorderVertex = (y == 0 || y == borderedSize - 1 || x == 0 || x == borderedSize - 1); if (isBorderVertex) { vertexIndicesMap[x, y] = borderVertexIndex; borderVertexIndex--; } else { vertexIndicesMap[x, y] = meshVertexIndex; meshVertexIndex++; } } } for (int y = 0; y < borderedSize; y += meshSimplificationIncrement) { for (int x = 0; x < borderedSize; x += meshSimplificationIncrement) { int vertexIndex = vertexIndicesMap[x, y]; Vector2 percent = new Vector2((x - meshSimplificationIncrement) / (float)meshSize, (y - meshSimplificationIncrement) / (float)meshSize); float height = heightMap[x, y]; Vector3 vertexPosition = new Vector3((topLeftX + percent.x * meshSizeUnsimplified) * settings.meshScale, height, (topLeftZ - percent.y * meshSizeUnsimplified) * settings.meshScale); meshData.AddVertex(vertexPosition, percent, vertexIndex); // ignore the right and bottom edge vertices of the map if (x < borderedSize - 1 && y < borderedSize - 1) { int a = vertexIndicesMap[x, y]; int b = vertexIndicesMap[x + meshSimplificationIncrement, y]; int c = vertexIndicesMap[x, y + meshSimplificationIncrement]; int d = vertexIndicesMap[x + meshSimplificationIncrement, y + meshSimplificationIncrement]; meshData.AddTriangle(a, d, c); meshData.AddTriangle(d, a, b); } vertexIndex++; } } meshData.ProcessMesh(); return(meshData); }