public void RequestMesh(HeightMap heightMap, MeshSettings meshSettings) { hasRequestedMesh = true; ThreadedDataRequester.RequestData( () => MeshGenerator.GenerateTerrainMesh(heightMap.values, meshSettings, lod), OnMeshDataReceived); }
public TerrainChunk(Vector2 coords, HeightMapSettings heightMapSettings, MeshSettings meshSettings, LODInfo[] detailLevels, int colliderLODIndex, Transform parent, Transform viewer, Material material) { this.coord = coords; this.heightMapSettings = heightMapSettings; this.meshSettings = meshSettings; this.detailLevels = detailLevels; this.colliderLODIndex = colliderLODIndex; this.viewer = viewer; maxViewDist = detailLevels[detailLevels.Length - 1].visibleDistThreshold; sampleCenter = coords * meshSettings.meshWorldSize / meshSettings.meshScale; Vector2 position = coord * meshSettings.meshWorldSize; bounds = new Bounds(sampleCenter, Vector2.one * meshSettings.meshWorldSize); meshObject = new GameObject("Terrain Chunk"); meshRenderer = meshObject.AddComponent <MeshRenderer>(); meshCollider = meshObject.AddComponent <MeshCollider>(); meshFilter = meshObject.AddComponent <MeshFilter>(); meshRenderer.material = material; meshObject.transform.position = new Vector3(position.x, 0, position.y); meshObject.transform.SetParent(parent, false); SetVisible(false); lodMeshes = new LODMesh[detailLevels.Length]; for (int i = 0; i < lodMeshes.Length; ++i) { lodMeshes[i] = new LODMesh(detailLevels[i].lod); lodMeshes[i].updateCallback += UpdateTerrainChunk; if (i == colliderLODIndex) { lodMeshes[i].updateCallback += UpdateCollisionMesh; } } }
public static MeshData GenerateTerrainMesh(float[,] heightMap, MeshSettings meshSettings, int levelOfDetail) { // can support LODs of (NumSupportedLODs - 1) int skipIncrement = (levelOfDetail == 0) ? 1 : levelOfDetail * 2; int numVertsPerLine = meshSettings.NumVertsPerLine; Vector2 topLeft = new Vector2(-1, 1) * meshSettings.meshWorldSize * .5f; 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) { continue; } 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 distToMainVertexA = (isVertical ? y - 2 : x - 2) % skipIncrement; int distToMainVertexB = skipIncrement - distToMainVertexA; float distPercentFromAToB = distToMainVertexA / (float)skipIncrement; float heightMainVertexA = heightMap[isVertical ? x : x - distToMainVertexA, isVertical ? y - distToMainVertexA : y]; float heightMainVertexB = heightMap[isVertical ? x : x + distToMainVertexB, isVertical ? y + distToMainVertexB : y]; height = heightMainVertexA * (1 - distPercentFromAToB) + heightMainVertexB * distPercentFromAToB; } 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.FinalizeNormals(); return(meshData); }