Generated map based on Perlin Noise

29 Views Asked by At

I'm trying to implement a terrain based on a noise map. The code is from internet so credits to Sebastian Lague. Everything went well, the map is generated fine but i wanted to make it bigger. Considering the fact that Unity doesn't allow more than ~65000 meshes/vertices, i generated the noise map, splitted into 4 mapChunks. The issue is that , eventhough i splitted into 4 , when i try to allign all the chunks in the scene view, a mesh is missing.

enter image description here

I've used the same code to generate the 2DNoiseMaps and they allign perfectly, so it's because the meshes. Is there a way to combine the mapChunk meshes somehow? Noise.cs:

using UnityEngine;
using System.Collections;

public static class Noise
{

public static float[,] GenerateNoiseMap(int mapWidth, int mapHeight, int seed, float scale, int octaves, float persistance, float lacunarity, Vector2 offset)
{
    float[,] noiseMap = new float[mapWidth, mapHeight];

    System.Random prng = new System.Random(seed);
    Vector2[] octaveOffsets = new Vector2[octaves];
    for (int i = 0; i < octaves; i++)
    {
        float offsetX = prng.Next(-100000, 100000) + offset.x;
        float offsetY = prng.Next(-100000, 100000) + offset.y;
        octaveOffsets[i] = new Vector2(offsetX, offsetY);
    }

    if (scale <= 0)
    {
        scale = 0.0001f;
    }

    float maxNoiseHeight = float.MinValue;
    float minNoiseHeight = float.MaxValue;

    float halfWidth = mapWidth / 2f;
    float halfHeight = mapHeight / 2f;


    for (int y = 0; y < mapHeight; y++)
    {
        for (int x = 0; x < mapWidth; x++)
        {

            float amplitude = 1;
            float frequency = 1;
            float noiseHeight = 0;

            for (int i = 0; i < octaves; i++)
            {
                float sampleX = (x - halfWidth) / scale * frequency + octaveOffsets[i].x;
                float sampleY = (y - halfHeight) / scale * frequency + octaveOffsets[i].y;

                float perlinValue = Mathf.PerlinNoise(sampleX, sampleY) * 2 - 1;
                noiseHeight += perlinValue * amplitude;

                amplitude *= persistance;
                frequency *= lacunarity;
            }

            if (noiseHeight > maxNoiseHeight)
            {
                maxNoiseHeight = noiseHeight;
            }
            else if (noiseHeight < minNoiseHeight)
            {
                minNoiseHeight = noiseHeight;
            }
            noiseMap[x, y] = noiseHeight;
        }
    }

    for (int y = 0; y < mapHeight; y++)
    {
        for (int x = 0; x < mapWidth; x++)
        {
            noiseMap[x, y] = Mathf.InverseLerp(minNoiseHeight, maxNoiseHeight, noiseMap[x, y]);
        }
    }

    return noiseMap;
}

}

MeshGenerator & MeshData classes

 public static class MeshGenerator
 {

public static MeshData GenerateTerrainMesh(float[,] heightMap, float heightMultiplier, AnimationCurve _heightCurve, int levelOfDetail)
{
    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);
    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++;
        }
    }

    return meshData;

}
}

 public class MeshData
{
public Vector3[] vertices;
public int[] triangles;
public Vector2[] uvs;

int triangleIndex;

public MeshData(int meshWidth, int meshHeight)
{
    vertices = new Vector3[meshWidth * meshHeight];
    uvs = new Vector2[meshWidth * meshHeight];
    triangles = new int[(meshWidth - 1) * (meshHeight - 1) * 6];
}

public void AddTriangle(int a, int b, int c)
{
    triangles[triangleIndex] = a;
    triangles[triangleIndex + 1] = b;
    triangles[triangleIndex + 2] = c;
    triangleIndex += 3;
}

public Mesh CreateMesh()
{
    Mesh mesh = new Mesh();
    mesh.vertices = vertices;
    mesh.triangles = triangles;
    mesh.uv = uvs;
    mesh.RecalculateNormals();
    return mesh;
}

}

Also the GenerateMap method which will create all the stuff:

 public void GenerateMap()
 {

MapDisplay display = FindObjectOfType<MapDisplay>();
meshHeightCurve = BrokenConstantCurve.GenerateCurveBasedOnBiomes(meshHeightCurve, regions);
meshHeightCurve = BrokenConstantCurve.CreateBrokenConstantCurve(meshHeightCurve);
float[,] noiseMap = Noise.GenerateNoiseMap(mapChunkSize * 2, mapChunkSize * 2, seed, noiseScale, octaves, persistance, lacunarity, offset);
float[,] upperLeft = new float[mapChunkSize, mapChunkSize];
float[,] upperRight = new float[mapChunkSize, mapChunkSize];
float[,] lowerLeft = new float[mapChunkSize, mapChunkSize];
float[,] lowerRight = new float[mapChunkSize, mapChunkSize];
List<float[,]> noiseMapChunks = new List<float[,]>() { upperLeft, upperRight, lowerLeft, lowerRight };
for (var x = 0; x < mapChunkSize; x++)
{
    for (var y = 0; y < mapChunkSize; y++)
        upperLeft[x, y] = noiseMap[x, y];
}
for (var x = mapChunkSize; x < mapChunkSize * 2; x++)
{
    for (var y = 0; y < mapChunkSize; y++)
        try
        {
            upperRight[x - mapChunkSize, y] = noiseMap[x, y];
        }
        catch (Exception ex)
        {

        }
}
for (var x = 0; x < mapChunkSize; x++)
{
    for (var y = mapChunkSize; y < mapChunkSize * 2; y++)
        lowerLeft[x, y - mapChunkSize] = noiseMap[x, y];
}
for (var x = mapChunkSize; x < mapChunkSize * 2; x++)
{
    for (var y = mapChunkSize; y < mapChunkSize * 2; y++)
        lowerRight[x- mapChunkSize, y - mapChunkSize] = noiseMap[x, y];
}
display.ClearMeshes();
for (var chunkIndex = 0; chunkIndex < noiseMapChunks.Count; chunkIndex++)
{

    Color[] colourMap = new Color[mapChunkSize * mapChunkSize];
    for (int y = 0; y < mapChunkSize; y++)
    {
        for (int x = 0; x < mapChunkSize; x++)
        {
            //if (useFalloff)
            //{
            //    chunk[x, y] = Mathf.Clamp01(chunk[x, y] - falloffMap[x, y]);
            //}
            float currentHeight = noiseMapChunks[chunkIndex][x, y];
            for (int j = 0; j < regions.Length; j++)
            {
                if (currentHeight <= regions[j].curveX)
                {
                    colourMap[y * mapChunkSize + x] = regions[j].colour;
                    break;
                }
            }
        }
    }
    
    display.DrawMesh(MeshGenerator.GenerateTerrainMesh(noiseMapChunks[chunkIndex], meshHeightMultiplier, meshHeightCurve, levelOfDetail), TextureGenerator.TextureFromColourMap(colourMap, mapChunkSize, mapChunkSize), chunkIndex);
    //display.DrawTexture(TextureGenerator.TextureFromHeightMap(noiseMapChunks[chunkIndex]), chunkIndex);

    
}

If you need other methods/classes, let me know. Thank you so much, hopefully someone can help after 5 days of investigation :)

0

There are 0 best solutions below