Why is my diamond-square implementation returning weird results?

I’ve been trying to put together a really minimal implementation of diamond-square I can use to generate some coarse terrain. About half of the time, my current setup returns nice, jagged terrain, but the other half it returns a flat or nearly flat plane with minimal elevation; I’ve stared at this for hours, but it looks right to me; am I missing something obvious?

    public float[,] ExecuteDiamondSquare(int size)
    {
        heights = new float[size, size];
        float average, range =  0.5f;
        int sideLength, halfSide, x, y;

        for (sideLength = size - 1; sideLength > 1; sideLength /= 2)
        {
            halfSide = sideLength / 2;

            //Diamond Step
            for (x = 0; x < size - 1; x += sideLength)
            {
                for (y = 0; y < size - 1; y += sideLength)
                {
                    average = heights[x, y];
                    average += heights[x + sideLength, y];
                    average += heights[x, y + sideLength];
                    average += heights[x + sideLength, y + sideLength];
                    average /= 4.0f;

                    average += (Random.value * (range * 2.0f)) - range;
                    heights[x + halfSide, y + halfSide] = average;
                }
            }

            //Square Step
            for (x = 0; x < size - 1; x += halfSide)
            {
                for (y = (x + halfSide) % sideLength; y < size - 1; y += sideLength)
                {
                    average = heights[(x - halfSide + size - 1) % (size - 1), y];
                    average += heights[(x + halfSide) % (size - 1), y];
                    average += heights[x, (y + halfSide) % (size - 1)];
                    average += heights[x, (y - halfSide + size - 1) % (size - 1)];
                    average /= 4.0f;

                    average += (Random.value * (range * 2.0f)) - range;

                    heights[x, y] = average;

                    // Wrap if this is an edge
                    if (x == 0)
                    {
                        heights[size - 1, y] = average;
                    }

                    if (y == 0)
                    {
                        heights[x, size - 1] = average;
                    }
                }
            }

            // Lower the random value range
            range -= range * 0.5f * roughness;
        }

        // Debug terrain config
        data.SetHeights(0, 0, heights);
       
        return heights;
    }

Your coordinate-wrapping modulo operators on lines 33 to 36… don’t those have to be modulo size and not modulo (size - 1)?

The time you would use (size - 1) would be if you were using the bitwise-AND operator (&) to constrain it (and enforcing it being a power of two), but your code is using modulo (%).

Ooh hey, thank you!! I don’t know how I missed that.

1 Like