2
\$\begingroup\$

Why am I getting this kind of results with my perlin noise ? The terrain is wide or elongated or straight at the variations of the noise function. Elongated and straight terrain

This is the way I generate terrain:

    public void GenTerrain()
    {
        for (int x = 0; x < this.size.x; x++)
        {
            for (int y = 0; y < this.size.y; y++)
            {
                float xCoord = (float)(x + offsetMirror + origin.x) / this.size.x * scale;
                float yCoord = (float)(y + offsetMirror + origin.y) / this.size.y * scale;
                float noise = Mathf.PerlinNoise(xCoord, yCoord);

                if (noise > 0.6f)
                {
                    this[x, y].terrainType = TerrainType.Grass;
                }
                else if(noise > 0.5f)
                {
                    this[x, y].terrainType = TerrainType.Sand;
                }
            }
        }
    }

This is the way I add chunks of terrain

    void Start()
    {
        maps = new Dictionary<Vector2Int, Map>();

        Res.LoadMaterials();

    }

    void AddNeighbours(Vector2Int position)
    {
        int length = 32;
        for(int x = -length; x <= length; x++)
        {
            for(int y = -length; y <= length; y++)
            {
                Vector2Int addPos = new Vector2Int((x * size) + position.x, (y * size) + position.y);
                CheckAndAddMap(addPos);
            }
        }

    }

    void CheckAndAddMap(Vector2Int addPos)
    {
        if (!maps.ContainsKey(addPos))
        {
            AddMap(addPos);
        }
    }

    void AddMap(Vector2Int origin)
    {
        Map map = new Map(new Vector2Int(size, size), origin);
        maps.Add(origin, map);
        MapMesh mapMesh = new MapMesh(map);

        foreach (KeyValuePair<TerrainType, MeshData> kv in mapMesh.meshes)
        {
            MeshData meshData = kv.Value;
            TerrainType terrainType = kv.Key;

            GameObject go = new GameObject("Mesh");
            go.transform.SetParent(this.transform);
            go.transform.localPosition = new Vector3(mapMesh.map.origin.x, mapMesh.map.origin.y, -(int)kv.Key);
            MeshFilter meshFilter = go.AddComponent<MeshFilter>();
            meshFilter.mesh = meshData.mesh;

            MeshRenderer mr = go.AddComponent<MeshRenderer>();
            mr.material = Res.mats[terrainType.ToString()];
        }
    }

    // Update is called once per frame
    void Update()
    {
        Vector2Int playerPosition = ConvertPlayerPositionToTiles(ShootBehaviour.PlayerInstance.transform.position);
        AddNeighbours(playerPosition * size);
    }

    private Vector2Int ConvertPlayerPositionToTiles(Vector3 position)
    {
        Vector2Int result = new Vector2Int();
        result.x = (int)position.x / size;
        result.y = (int)position.y / size;

        return result;
    }

\$\endgroup\$
2
  • 1
    \$\begingroup\$ What are the values of this.size.x and this.size.y? \$\endgroup\$ – Philipp Dec 10 '20 at 16:01
  • \$\begingroup\$ The values of this.size.x and this.size.y are the size of the chunk. They are set to 16*16. Scale is set to 1. Is there a way to debug perlin noise ? \$\endgroup\$ – kyu Dec 10 '20 at 16:20
2
\$\begingroup\$

That's what a single octave of Perlin Noise looks like.

In particular, you've chosen to highlight the ugliest part of this noise function with the thresholds you picked for the sand.

Perlin noise works by taking a grid of square cells, and computing a pseudo-random gradient from each corner, then blending those gradients along the edges/interiors of the cells. That means that Perlin noise must touch or cross 0 at every corner of the square grid, giving it a noticeable anisotropy - especially when slicing it along values very close to 0.

Unity's convenience method remaps that 0 value to 0.5, so it sits in the middle of the 0...1 range of the function. And that's exactly where you put your sand cutoff, so it highlights this ugly artifact of the noise algorithm.

You can ameliorate this a little my moving your threshold above or below 0.5 - but it'll still look like a single octave of Perlin Noise (ie. almost never what we actually want).

To get good-looking terrain, we usually sum together multiple octaves of noise at different frequencies and amplitudes. This masks the artifacts of any one layer of noise, and gives us a more complicated pattern with detail across multiple scales, better mimicking what we might see in natural phenomena.

If you need to use just a single octave, split exactly halfway through its range, then you can switch to another noise algorithm that's somewhat more isotropic, like simplex noise.

\$\endgroup\$
4
  • \$\begingroup\$ Very true. I'll add to this and say just go ahead and use Simplex. There's almost no convenience factor that's worth using Perlin for, IMO, if you aren't doing anything to hide the square bias (e.g. taking 2D slices of domain-rotated 3D Perlin). Unity is probably causing more problems than it solves by including Mathf.PerlinNoise without any Mathf.SimplexNoise or documentation to steer developers to the latter, but that's a separate issue that warrants its own discussion. \$\endgroup\$ – KdotJPG Dec 23 '20 at 16:58
  • \$\begingroup\$ If you're placing the threshold right at the center of its value distribution, then ordinary Simplex might not look great either, but if you use a large kernel variety of simplex (see OpenSimplex2S/SuperSimplex or 2014 OpenSimplex) then it's much better. And in either case, the features will be aligned along a wider distribution of angles. \$\endgroup\$ – KdotJPG Dec 23 '20 at 16:58
  • \$\begingroup\$ A noise library that I contributed to and recommend, is FastNoiseLite. It supports two simplex type noises, one being the larger kernel variety and both using good gradient tables to reduce diagonal artifacts. It even supports that domain rotation trick I talked about. Note that its output range is -1 to 1 instead of 0 to 1, but that's easy to account for. github.com/Auburn/FastNoise \$\endgroup\$ – KdotJPG Dec 23 '20 at 16:58
  • \$\begingroup\$ Also, I should add that the grid corners being zero by definition definitely contributes to its anisotropy, but I believe the square grid itself is the primary reason for it. Value noise with cubic interpolation suffers from a similar tendency to produce mostly 45 and 90 degree features, even though the corners can be any value. \$\endgroup\$ – KdotJPG Dec 23 '20 at 17:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.