1
\$\begingroup\$

For a project I am working on, I am making infinitely generating terrain, similar to the way Minecraft terrain is generated.

This means I am generating chunks of 16*16. Because I need to know if the blocks on the side of the chunk needs to generate their sides, I give the chunk an 18*18 array where only the middle 16*16 get generated in the chunk. This way I can check the height of the border blocks of the chunks around the chunk I am working with.

Now, the issue I am having is is kind of hard to explain. But the issue happens when 2 chunks are bordering each other. In some occasions, the side of a block bordering another block would not be shown, as seen in the example bellow.

I have selected the chunk where the issue is generated, giving a clear view of where the chunk is at.

I have tried to narrow it down where the issue comes from and I have narrowed it down to come from the octave for-loop which can be found inside the x and y for-loop's (which can easily be found by the comment half-way of the code.

I decided to run a Debug.Log() inside of this loop to find out where exactly this issue is generated. I found out that the sampleY is different in the second loop, while being the same in the first, third, fourth and fifth loop, while the parameters are exactly the same for the position. This gives a slight change in the PerlinNoise parameters and therefor generates a different value from in the other chunk.

This different values happen in every chunk, always in the second loop. The reason it is not visible every time is because in most cases the difference in value is too small for any effect to appear.

But anyway, this is the input of the GenerateNoiseMap function:

seed = 0;
scale = 25;
octaves = 5;
lacunarity = 0.5f;
offset = 0, 0;

And here is the output of the Debug.Log():

enter image description here

The values of which there is no duplicate (with the (1) behind it should be duplicates of eachother).

Last but not least, my code:

public static Dictionary<Vector2, int> GenerateNoiseMap (Vector2 startPos, Vector2 endPos, int seed, float scale, int octaves, float lacunarity, Vector2 offset) {
    float [,] tempNoiseMap = new float[18, 18];

    System.Random rng = new System.Random (seed);
    Vector2[] octaveOffsets = new Vector2[octaves];

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

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

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

            float frequency = 1;
            float noiseHeight = 0;

//Issue is inside this for-loop, on the second loop
            for (int o = 0; o < octaves; o++) {
                float sampleX = x / scale * frequency + octaveOffsets[o].x;
                float sampleY = y / scale * frequency + octaveOffsets[o].y;

                sampleX += (16 / scale * frequency) * (startPos.x / 16);
                sampleY += (16 / scale * frequency) * (startPos.y / 16);

                float perlinValue = Mathf.PerlinNoise (sampleX, sampleY);
                noiseHeight += perlinValue;
                frequency *= lacunarity;

                if (startPos.x + x == 108 && startPos.y + y == 8) {
                    Debug.Log (sampleX + ", " + sampleY + ": " + perlinValue);
                }
            }
            if (noiseHeight > maxNoiseHeight) {
                maxNoiseHeight = noiseHeight;
            } else if (noiseHeight < minNoiseHeight) {
                minNoiseHeight = noiseHeight;
            }

            tempNoiseMap[x, y] = noiseHeight;
        }
    }

    Dictionary<Vector2, int> noiseMap = new Dictionary<Vector2, int>();

    for (int y = 0; y < 18; y++) {
        for (int x = 0; x < 18; x++) {
            noiseMap.Add(new Vector2(x, y), Mathf.RoundToInt (tempNoiseMap[x, y] * 16 - 12));
        }
    }

    return noiseMap;
}

Note: Very important to know is that, if I change

Debug.Log (sampleX + ", " + sampleY + ": " + perlinValue);

to

Debug.Log (sampleX * 100 + ", " + sampleY * 100 + ": " + perlinValue);

The output changes to this: enter image description here

Here it is very clear the value of sampleY is different in the second loop.

Note 2: I have changed the log to:

Debug.Log(sampleY * 100 + 6975180);

and the results are insteresting:

enter image description here

\$\endgroup\$
  • \$\begingroup\$ What is o in your code? \$\endgroup\$ – Jay Jan 28 '18 at 1:44
  • \$\begingroup\$ @Jay I accidentally removed the for-loop. The code is correct now \$\endgroup\$ – FlorisdG Jan 28 '18 at 1:56
  • \$\begingroup\$ Remember that floating point precision falls off the further the numbers get from zero. In the vicinity of 70 000, you have precision only to within 2^-5 or about 0.03. If your sampling points aren't well aligned to the representable values, then calculating the same coordinate through different intermediates can lead to different rounding errors. \$\endgroup\$ – DMGregory Jan 28 '18 at 2:56
  • \$\begingroup\$ @DMGregory that is exactly what I thought the problem was. But how would I be able to fix it? \$\endgroup\$ – FlorisdG Jan 28 '18 at 10:00

Your Answer

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

Browse other questions tagged or ask your own question.