C# Perlin Noise implementation returning negative values

by Simone Bondi   Last Updated January 05, 2018 18:13 PM

i just implemented Perlin Noise in one of my programs by following an explanation of the algorithm and writing my own code: I get negative values from the algorithm resulting in some weird artifacts.

You can see the minimum and maximum values returned by the algorithm in the window title.

Visual representation of the output

And here's the code:

class PerlinNoise
{

    const int TOP_LEFT = 0;
    const int TOP_RIGHT = 1;
    const int BOTTOM_LEFT = 2;
    const int BOTTOM_RIGHT = 3;

    readonly Vector2[] gradientLookup =
    {
        new Vector2(-1f, 1f),
        new Vector2(1f, -1f),
        new Vector2(-1f, -1f),
        new Vector2(1f, -1f)
    };

    Vector2[,] gradientMap;

    int width;
    int height;

    public PerlinNoise(int width, int height)
    {
        if (width < 0 || height < 0)
            throw new ArgumentOutOfRangeException("Size is zero or negative.");


        this.width = width;
        this.height = height;

        gradientMap = new Vector2[width + 1, height + 1];

        // Gradient map initialization

        for(int y = 0; y < height + 1; y++)
        {
            for (int x = 0; x < width + 1; x++)
            {
                gradientMap[x, y] = gradientLookup[Game1.random.Next(gradientLookup.Length)];
            }
        }
    }

    public float GetNoise(float x, float y)
    {
        if (x > width || y > height || y < 0 || x < 0)
            throw new ArgumentOutOfRangeException("Specified point is out of range.");

        int floorX = (int)Math.Floor(x);
        int ceilX = (int)Math.Ceiling(x);

        int floorY = (int)Math.Floor(y);
        int ceilY = (int)Math.Ceiling(y);

        Vector2[] positions = {
            new Vector2(floorX, floorY),
            new Vector2(ceilX, floorY),
            new Vector2(floorX, ceilY),
            new Vector2(ceilX, ceilY)
        };

        Vector2[] gradients =
        {
            gradientMap[floorX, floorY],
            gradientMap[ceilX, floorY],
            gradientMap[floorX, ceilY],
            gradientMap[ceilX, ceilY]
        };


        Vector2 pos = new Vector2(x, y);

        // Calculate the dot products for each corner of the rectangle.
        float[] dotProducts = new float[4];

        for(int i = 0; i < 4; i++)
        {
            Vector2 distance = pos - positions[i];

            dotProducts[i] = Vector2.Dot(distance, gradients[i]);
        }

        // And finally, smoothstep between the value using the local coords as ratios.
        float localX = x - floorX;
        float localY = y - floorY;

        float topLerp = MathHelper.SmoothStep(dotProducts[TOP_LEFT], dotProducts[TOP_RIGHT], localX);
        float bottomLerp = MathHelper.SmoothStep(dotProducts[BOTTOM_LEFT], dotProducts[BOTTOM_RIGHT], localX);

        return MathHelper.SmoothStep(topLerp, bottomLerp, localY);
    }


Related Questions



Determine the startposition for Perlin worms

Updated August 06, 2017 23:13 PM

Where to start with perlin noise?

Updated August 25, 2018 15:13 PM

Zooming in on procedural generated 2D terrain? (LOD)

Updated October 05, 2017 13:13 PM