Search code examples
unity-game-engineoffsetterrainperlin-noise

How to implement Offset on Perlin noise?


I need a little help, I have this Perlin noise function, but I don't know how to properly create offsets.

I am using this to create infinite terrain generation and when I use this script it the noise values of individual chunks don't fit together properly. And they create holes.

Is there a way of fixing this ?

  public  float[,] GenerateNoise(int chunkSize, int octaves, string seed, float noiseScale, float persistence, float lacunarity, Vector2 offset)
    {
        
        if (noiseScale <= 0)
        {
            noiseScale = 0.0001f;
        }


        float halfWidth = chunkSize / 2f;
        float halfHeight = chunkSize / 2f;

        float[,] noiseMap = new float[chunkSize, chunkSize];
        System.Random rand = new System.Random(seed.GetHashCode());

        //Octaves offset
        Vector2[] octavesOffset = new Vector2[octaves];
        for (int i = 0; i < octaves; i++)
        {
            float offset_X = rand.Next(-100000, 100000) + offset.x;
            float offset_Y = rand.Next(-100000, 100000) + offset.y;
            octavesOffset[i] = new Vector2(offset_X / chunkSize , offset_Y / chunkSize);
        }

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

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

                
                for (int i = 0; i < octaves; i++)
                {


                    float sampleX = (x - halfWidth) / noiseScale * frequency + octavesOffset[i].x * frequency;
                    float sampleY = (y - halfHeight) / noiseScale * frequency + octavesOffset[i].y * frequency;

                    float noiseValue = Mathf.PerlinNoise(sampleX, sampleY);
                    noiseHeight += noiseValue * amplitude;
                    noiseHeight -= superpositionCompensation;

                    amplitude *= persistence;
                    frequency *= lacunarity;
                    superpositionCompensation = amplitude / 2;

                }

                noiseMap[x, y] = Mathf.Clamp01(noiseHeight); 
                
            }
        }

        return noiseMap;
    }

Solution

  • It is quite simple actually, just add the chunk x,y coordinates to Mathf.PerlinNoise. Taking your code as an example, you can:

    1. Pass chunkPosition as an argument to it:

      public  float[,] GenerateNoise(Vector2 chunkPos, int chunkSize, int octaves, string seed, float noiseScale, float persistence, float lacunarity, Vector2 offset)
      
    2. Add it to Mathf.PerlinNoise invocation:

      float noiseValue = Mathf.PerlinNoise(sampleX + chunkPos.x, sampleY + chunkPos.y);
      

    Then make sure to generate each chunk with an appropriate chunkPos, where chunkPos can be its transform.position or whatever coordinates you have. That's it.