public static MeshData GenerateTerrainMesh(float[,] heightMap, int levelOfDetail, float heightMultiplier, AnimationCurve heightCurve) { var localHeightCurve = 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 meshSimplificationIncrement = (int)Mathf.Pow(2, levelOfDetail); int verticesPerLine = (width - 1) / meshSimplificationIncrement + 1; MeshData meshData = new MeshData(verticesPerLine); int vertexIndex = 0; for (int y = 0; y < height; y += meshSimplificationIncrement) { for (int x = 0; x < width; x += meshSimplificationIncrement) { float heightValue = localHeightCurve.Evaluate(heightMap[x, y]) * heightMultiplier; meshData.vertices[vertexIndex] = new Vector3(topLeftX + x, heightValue, topLeftZ + y); meshData.uvs[vertexIndex] = new Vector2((x + 0.5f) / width, (y + 0.5f) / height); if (x < width - 1 && y < height - 1) { meshData.AddTriangle(vertexIndex + verticesPerLine, vertexIndex + verticesPerLine + 1, vertexIndex); meshData.AddTriangle(vertexIndex + 1, vertexIndex, vertexIndex + 1 + verticesPerLine); } vertexIndex++; } } meshData.BakeNormals(); return(meshData); }
MeshData GenerateMesh(float[,] heightMap, int lod) { int width = heightMap.GetLength(0); int height = heightMap.GetLength(1); AnimationCurve curve = new AnimationCurve(elevationCurve.keys); float topLeftX = (width - 1) / -2.0f; float topLeftZ = (height - 1) / 2.0f; int meshSimplificationLevel = (lod == 0)? 1 : lod * 2; int verticesPerLine = (width - 1) / meshSimplificationLevel + 1; MeshData meshData = new MeshData(verticesPerLine, verticesPerLine); int vertexIndex = 0; for (int y = 0; y < height; y += meshSimplificationLevel) { for (int x = 0; x < width; x += meshSimplificationLevel) { meshData.vertices[vertexIndex] = new Vector3(topLeftX + x, elevation * curve.Evaluate(heightMap[x, y]), 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++; } } meshData.BakeNormals(); return(meshData); }
public static MeshData GenerateTerrainMesh(float[,] heightMap, float heightMultiplier, AnimationCurve _heightCurve, int levelOfDetail) { 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); 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.BakeNormals(); return(meshData); }
/* * -1 -2 -3 -4 -5 * o o o o o * -6 0 1 2 -7 * o # # # o * -8 3 4 5 -9 * o # # # o * -10 6 7 8 -11 * o # # # o * -12 -13 -14 -15 -16 * o o o o o */ public static MeshData GenerateTerrainMesh(float[,] heightMap, float heightFactor, AnimationCurve _heightCurve, int levelOfDetail) { 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); 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 -= 1; } else { vertexIndicesMap[x, y] = meshVertexIndex; meshVertexIndex += 1; } } } // see for details : https://www.youtube.com/watch?v=4RpVBYW1r5M 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]) * heightFactor; 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) { /* * * (x;y) * / * a b (x+i; y) * o ___o * |\\ | triangle adc * | \\ | triangle dab * |__\\| * o o * c d (x+i;y+i) * \ * (x;y+i) * */ 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.BakeNormals(); return(meshData); }
public static MeshData GenerateTerrainMesh(float[,] heightMap, MeshSettings meshSettings, int levelOfDetail) { //Used to simplify mesh triangles on distance int skipIncrement = (levelOfDetail == 0) ? 1 : levelOfDetail * 2; // If levelofdetail is 0 set it to 1 otherwise double int numVertsPerLine = meshSettings.NumVertsPerLine; Vector2 topLeft = new Vector2(-1, 1) * meshSettings.MeshWorldSize / 2f; MeshData meshData = new MeshData(numVertsPerLine, skipIncrement); //Uses data for threading 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]; meshData.AddVertex(new Vector3(vertexPosition2D.x, height, vertexPosition2D.y), percent, vertexIndex); 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); } vertexIndex++; } } } meshData.BakeNormals(); return(meshData); }
public static MeshData FromHeightMap(int seed, MeshSettings settings, float[,] heightMap, int levelOfDetail) { Random.State initialState = Random.state; Random.InitState(seed); int meshSimplificationIncrement = (levelOfDetail == 0) ? 1 : levelOfDetail * 2; int borderedSize = heightMap.GetLength(0); #region Border Array #region Variables int[,] vertexIndices = new int[borderedSize, borderedSize]; int borderVertexIndex = -1; int meshVertexIndex = 0; #endregion for (int z = 0; z < borderedSize; z += meshSimplificationIncrement) { for (int x = 0; x < borderedSize; x += meshSimplificationIncrement) { bool isBorderVertex = z == 0 || z == borderedSize - 1 || x == 0 || x == borderedSize - 1; if (isBorderVertex) { vertexIndices[x, z] = borderVertexIndex; borderVertexIndex--; } else { vertexIndices[x, z] = meshVertexIndex; meshVertexIndex++; } } } #endregion #region Mesh Data #region Variables 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.flatShade); int vertexIndex; Vector2 uvPercent; Vector3 vertexPosition; #endregion for (int z = 0; z < borderedSize; z += meshSimplificationIncrement) { for (int x = 0; x < borderedSize; x += meshSimplificationIncrement) { vertexIndex = vertexIndices[x, z]; uvPercent = new Vector2( (x - meshSimplificationIncrement) / (float)meshSize, (z - meshSimplificationIncrement) / (float)meshSize ); vertexPosition = new Vector3( (topLeftX + uvPercent.x * meshSizeUnsimplified) * settings.scale, heightMap[x, z], (topLeftZ - uvPercent.y * meshSizeUnsimplified) * settings.scale ); meshData.AddVertex(vertexPosition, uvPercent, vertexIndex); if (x < borderedSize - 1 && z < borderedSize - 1) { int a = vertexIndices[x, z]; int b = vertexIndices[x + meshSimplificationIncrement, z]; int c = vertexIndices[x, z + meshSimplificationIncrement]; int d = vertexIndices[x + meshSimplificationIncrement, z + meshSimplificationIncrement]; meshData.AddTriangle(a, d, c); meshData.AddTriangle(d, a, b); } vertexIndex++; } } #endregion meshData.BakeNormals(); Random.state = initialState; return(meshData); }
public static MeshData GenerateTerrainMesh(float[,] heightMap, float heightMultiplier, AnimationCurve heightCurve, int levelOfDetail) { //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); //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.BakeNormals(); 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) { AnimationCurve heightCurve = new AnimationCurve(_heightCurve.keys); // makes water flat int meshSimplificationIncrement = (levelOfDetail == 0) ? 1 : levelOfDetail * 2; // changes resolution parameter int borderedSize = heightMap.GetLength(0); // make a border to make the terrain seamless across chunks int meshSize = borderedSize - 2 * meshSimplificationIncrement; int meshSizeUnsimplified = borderedSize - 2; float topLeftX = (meshSizeUnsimplified - 1) / -2f; // index for top left corner float topLeftZ = (meshSizeUnsimplified - 1) / 2f; int verticesPerLine = (meshSize - 1) / meshSimplificationIncrement + 1; // how many vertices should be created MeshData meshData = new MeshData(verticesPerLine); int [,] vertexIndicesMap = new int [borderedSize, borderedSize]; // keeps track of vertex info before creating the mesh data 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--; // make border vertices negative to differentiate them from internal vertices } 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.BakeNormals(); return(meshData); }
public static MeshData GenerateTerrainMesh(float[,] heightMap, float heightMultiplier, AnimationCurve _heightCurve, int levelOfDetail, int chunkIndex) { AnimationCurve heightCurve = new AnimationCurve(_heightCurve.keys); int skipIncriment = (levelOfDetail == 0) ? 1 : levelOfDetail * 2; int numVertsPerLine = supportedChunkSizes[chunkIndex] + 5; int meshWorldSize = numVertsPerLine - 3; Vector2 topLeft = new Vector2(-1, 1) * meshWorldSize / 2f; int[,] vertexIndicesMap = new int[numVertsPerLine, numVertsPerLine]; int meshVertexIndex = 0; int outOfMeshVertexIndex = -1; int mainVertexIndex = 0; MeshData meshData = new MeshData(numVertsPerLine, skipIncriment); 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) % skipIncriment != 0 || (y - 2) % skipIncriment != 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) % skipIncriment != 0 || (y - 2) % skipIncriment != 0); if (!isSkippedVertex) { bool isOutOfMeshVertex = y == 0 || y == numVertsPerLine - 1 || x == 0 || x == numVertsPerLine - 1; bool isMeshEdgeVertex = (y == 1 || x == 1 || y == numVertsPerLine - 2 || x == numVertsPerLine - 2) && !isOutOfMeshVertex; bool isMainVertex = ((x - 2) % skipIncriment == 0 && (y - 2) % skipIncriment == 0) && !isOutOfMeshVertex && !isMeshEdgeVertex; bool isEdgeConnectionVertex = (y == 2 || y == numVertsPerLine - 3 || x == 2 || x == numVertsPerLine - 3) && !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) * meshWorldSize; float height = heightCurve.Evaluate(heightMap[x, y]) * heightMultiplier; if (isEdgeConnectionVertex) { bool isVertical = x == 2 || x == numVertsPerLine - 3; int dstToMainVertexA = ((isVertical) ? y - 2 : x - 2) % skipIncriment; int dstToMainVertexB = skipIncriment - dstToMainVertexA; float dstPercentFromAToB = dstToMainVertexA / (float)skipIncriment; float heightMainVertexA = heightCurve.Evaluate(heightMap[(isVertical) ? x : x - dstToMainVertexA, (isVertical) ? y - dstToMainVertexA : y]) * heightMultiplier; float heightMainVertexB = heightCurve.Evaluate(heightMap[(isVertical) ? x : x + dstToMainVertexB, (isVertical) ? y + dstToMainVertexB : y]) * heightMultiplier; height = heightMainVertexA * (1 - dstPercentFromAToB) + heightMainVertexB * dstPercentFromAToB; } else if (isMainVertex) { meshData.addMainVertex(new Vector3(vertexPosition2D.x, height, vertexPosition2D.y), mainVertexIndex); mainVertexIndex++; } 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 currentIncriment = (isMainVertex && x != numVertsPerLine - 3 && y != numVertsPerLine - 3) ? skipIncriment : 1; int a = vertexIndicesMap[x, y]; int b = vertexIndicesMap[x + currentIncriment, y]; int c = vertexIndicesMap[x, y + currentIncriment]; int d = vertexIndicesMap[x + currentIncriment, y + currentIncriment]; meshData.AddTriangle(a, d, c); meshData.AddTriangle(d, a, b); } } } } meshData.BakeNormals(); return(meshData); }
public static MeshData GenerateTerrainMesh(float[,] heightMap, float heightMultiplier, AnimationCurve _heightCurve, int levelOfDetail) { 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); 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.BakeNormals (); return meshData; }
public static MeshData GenerateTerrainMesh(float[,] heightMap, MeshSettings meshSettings, int levelOfDetail) { var skipIncrement = levelOfDetail == 0 ? 1 : levelOfDetail * 2; var numVertsPerLine = meshSettings.numberOfVerticesPerLine; var topLeft = new Vector2(-1, 1) * meshSettings.MeshWorldSize / 2.0f; var meshData = new MeshData(numVertsPerLine, skipIncrement); 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 ax = isVertical ? x : x - dstToMainVertexA; var ay = isVertical ? y - dstToMainVertexA : y; var bx = isVertical ? x : x + dstToMainVertexB; var by = isVertical ? y + dstToMainVertexB : y; var heightMainVertexA = heightMap[ax, ay]; var heightMainVertexB = heightMap[bx, by]; height = (heightMainVertexA * (1 - dstPercentFromAToB)) + (heightMainVertexB * dstPercentFromAToB); var indexA = vertexIndicesMap[ax, ay]; var indexB = vertexIndicesMap[bx, by]; meshData.AddAveragedNormal(vertexIndex, indexA, indexB, dstPercentFromAToB); } meshData.AddVertex(new Vector3(vertexPosition2D.x, height, vertexPosition2D.y), percent, vertexIndex); var createTrianlge = x < numVertsPerLine - 1 && y < numVertsPerLine - 1 && (!isEdgeConnectionVertex || (x != 2 && y != 2)); if (createTrianlge) { 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.BakeNormals(); return(meshData); }
public static MeshData generateTerrainMesh(float[,] heightMap, float heightMultiplier, AnimationCurve meshHeightCurve, int levelDetail) { AnimationCurve reference = new AnimationCurve(meshHeightCurve.keys); int simplificationIncrement = (levelDetail == 0 ? 1 : levelDetail * 2); int borderedSize = heightMap.GetLength(0); //int borderedSize = heightMap.GetLength(1); int meshSize = borderedSize - 2 * simplificationIncrement; int meshSizeUnsimplifies = borderedSize - 2; int verticesPerLine = (meshSize - 1) / simplificationIncrement + 1; /*these two variables help the map spawns in the middle*/ float topLeftX = (meshSizeUnsimplifies - 1) / -2f; float topLeftZ = (meshSizeUnsimplifies - 1) / 2f; MeshData meshData = new MeshData(verticesPerLine); int[,] vertexIndicesMap = new int[borderedSize, borderedSize]; int meshVertexIndex = 0; int borderVertexIndex = -1; //int vertexIndex = 0; for (int y = 0; y < borderedSize; y += simplificationIncrement) { for (int x = 0; x < borderedSize; x += simplificationIncrement) { 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 += simplificationIncrement) { for (int x = 0; x < borderedSize; x += simplificationIncrement) { int vertexIndex = vertexIndicesMap[x, y]; Vector2 percent = new Vector2((x - simplificationIncrement) / (float)meshSize, (y - simplificationIncrement) / (float)meshSize); float height = reference.Evaluate(heightMap[x, y]) * heightMultiplier;//this defines the height of all vertices Vector3 vertexPosition = new Vector3((topLeftX + percent.x * meshSizeUnsimplifies), height, (topLeftZ - percent.y * meshSizeUnsimplifies)); meshData.addVertex(vertexPosition, percent, vertexIndex); if (x < borderedSize - 1 && y < borderedSize - 1) { int a = vertexIndicesMap[x, y]; int b = vertexIndicesMap[x + simplificationIncrement, y]; int c = vertexIndicesMap[x, y + simplificationIncrement]; int d = vertexIndicesMap[x + simplificationIncrement, y + simplificationIncrement]; meshData.addTriangles(a, d, c); meshData.addTriangles(d, a, b); } ; //vertexIndex++; } } meshData.BakeNormals(); //return meshData for multi-threading so the game doesn't freeze when it loads //**we can't create Mesh inside the thread, so you have to do it outside the threading method return(meshData); }