Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I have a perlin noise generator as shown below.

public class ImprovedNoise
{
    private const int GradientSizeTable = 256;
    private readonly Random _random;
    private readonly double[] _gradients = new double[GradientSizeTable * 3];
    /* Borrowed from Darwyn Peachey (see references above).
       The gradient table is indexed with an XYZ triplet, which is first turned
       into a single random index using a lookup in this table. The table simply
       contains all numbers in [0..255] in random order. */
    private readonly byte[] _perm = new byte[] {
          225,155,210,108,175,199,221,144,203,116, 70,213, 69,158, 33,252,
            5, 82,173,133,222,139,174, 27,  9, 71, 90,246, 75,130, 91,191,
          169,138,  2,151,194,235, 81,  7, 25,113,228,159,205,253,134,142,
          248, 65,224,217, 22,121,229, 63, 89,103, 96,104,156, 17,201,129,
           36,  8,165,110,237,117,231, 56,132,211,152, 20,181,111,239,218,
          170,163, 51,172,157, 47, 80,212,176,250, 87, 49, 99,242,136,189,
          162,115, 44, 43,124, 94,150, 16,141,247, 32, 10,198,223,255, 72,
           53,131, 84, 57,220,197, 58, 50,208, 11,241, 28,  3,192, 62,202,
           18,215,153, 24, 76, 41, 15,179, 39, 46, 55,  6,128,167, 23,188,
          106, 34,187,140,164, 73,112,182,244,195,227, 13, 35, 77,196,185,
           26,200,226,119, 31,123,168,125,249, 68,183,230,177,135,160,180,
           12,  1,243,148,102,166, 38,238,251, 37,240,126, 64, 74,161, 40,
          184,149,171,178,101, 66, 29, 59,146, 61,254,107, 42, 86,154,  4,
          236,232,120, 21,233,209, 45, 98,193,114, 78, 19,206, 14,118,127,
           48, 79,147, 85, 30,207,219, 54, 88,234,190,122, 95, 67,143,109,
          137,214,145, 93, 92,100,245,  0,216,186, 60, 83,105, 97,204, 52};

    private static ImprovedNoise instance;
    public static ImprovedNoise Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new ImprovedNoise((int)DateTime.Now.Ticks);
            }
            return instance;
        }
    }

    private ImprovedNoise(int seed)
    {
        _random = new Random(seed);
        InitGradients();
    }

    public double Noise(double x, double y, double z)
    {
        /* The main noise function. Looks up the pseudorandom gradients at the nearest
           lattice points, dots them with the input vector, and interpolates the
           results to produce a single output value in [0, 1] range. */

        int ix = (int)System.Math.Floor(x);
        double fx0 = x - ix;
        double fx1 = fx0 - 1;
        double wx = Smooth(fx0);

        int iy = (int)System.Math.Floor(y);
        double fy0 = y - iy;
        double fy1 = fy0 - 1;
        double wy = Smooth(fy0);

        int iz = (int)System.Math.Floor(z);
        double fz0 = z - iz;
        double fz1 = fz0 - 1;
        double wz = Smooth(fz0);

        double vx0 = Lattice(ix, iy, iz, fx0, fy0, fz0);
        double vx1 = Lattice(ix + 1, iy, iz, fx1, fy0, fz0);
        double vy0 = Lerp(wx, vx0, vx1);

        vx0 = Lattice(ix, iy + 1, iz, fx0, fy1, fz0);
        vx1 = Lattice(ix + 1, iy + 1, iz, fx1, fy1, fz0);
        double vy1 = Lerp(wx, vx0, vx1);

        double vz0 = Lerp(wy, vy0, vy1);

        vx0 = Lattice(ix, iy, iz + 1, fx0, fy0, fz1);
        vx1 = Lattice(ix + 1, iy, iz + 1, fx1, fy0, fz1);
        vy0 = Lerp(wx, vx0, vx1);

        vx0 = Lattice(ix, iy + 1, iz + 1, fx0, fy1, fz1);
        vx1 = Lattice(ix + 1, iy + 1, iz + 1, fx1, fy1, fz1);
        vy1 = Lerp(wx, vx0, vx1);

        double vz1 = Lerp(wy, vy0, vy1);
        return Lerp(wz, vz0, vz1);
    }

    private void InitGradients()
    {
        for (int i = 0; i < GradientSizeTable; i++)
        {
            double z = 1f - 2f * _random.NextDouble();
            double r = System.Math.Sqrt(1f - z * z);
            double theta = 2 * System.Math.PI * _random.NextDouble();
            _gradients[i * 3] = r * System.Math.Cos(theta);
            _gradients[i * 3 + 1] = r * System.Math.Sin(theta);
            _gradients[i * 3 + 2] = z;
        }
    }

    private int Permutate(int x)
    {
        const int mask = GradientSizeTable - 1;
        return _perm[x & mask];
    }

    private int Index(int ix, int iy, int iz)
    {
        // Turn an XYZ triplet into a single gradient table index.
        return Permutate(ix + Permutate(iy + Permutate(iz)));
    }

    private double Lattice(int ix, int iy, int iz, double fx, double fy, double fz)
    {
        // Look up a random gradient at [ix,iy,iz] and dot it with the [fx,fy,fz] vector.
        int index = Index(ix, iy, iz);
        int g = index * 3;
        return _gradients[g] * fx + _gradients[g + 1] * fy + _gradients[g + 2] * fz;
    }

    private double Lerp(double t, double value0, double value1)
    {
        // Simple linear interpolation.
        return value0 + t * (value1 - value0);
    }

    private double Smooth(double x)
    {
        /* Smoothing curve. This is used to calculate interpolants so that the noise
          doesn't look blocky when the frequency is low. */
        return x / 1.25; //* x * (3 - 2 * x);
    }
}

I use this algorithm by doing threshold detection (at specific values, it will generate tiles, at other values it won't). However, the results I have right now are not as I intend them to.

I would like more "space" between the "walls". Scaling is not an option, because I like the size of the tiles now.

See my attached screenshot below.

enter image description here

share|improve this question
    
I guess it is optimisiation by definition, but its misleading, 'tweaking' might be a better title. –  Daniel Aug 5 '11 at 22:20
add comment

3 Answers

up vote 5 down vote accepted

The easiest way I can think of is simply adjusting the threshold parameter, a smaller value would result in thicker walls, while a higher value would result in thinner walls (or vice versa, depending on your threshold test)

share|improve this answer
add comment

I would like more "space" between the "walls". Scaling is not an option, because I like the size of the tiles now.

If you want to change the scale of your noise, rather than scaling your tiles up or down, you can scale the coordinates where you sample the noise. So, instead of sampling the noise at Noise(tile.x, tile.y, z), sample at Noise(tile.x * scaleX, tile.y * scaleY, z). You can also change the threshold value for deciding what's a wall if you want to make the walls thicker or thinner with the same scale noise.

share|improve this answer
add comment

The following approach doesn't rely on (or benefit from) your use of Perlin noise.

If you have a black-and-white image and want to thicken-up (or thin-down) the filled areas, a way to handle this in a graphics application using common filters would be...

  1. Apply a gaussian blur, converting the image to greyscale.
  2. Apply a threshold, so that the darker greys become black and the lighter greys become white.

Depending on the radius of the blur and the threshold value used, you tend to get larger (or smaller) filled areas. And of course there's lots of variations by applying alternative filters in place of the blur, giving effects other than simple thickening/thining.

The gaussian blur is basically a 2D moving weighted average. If you're coding this yourself, each pixel can do this blur calculation and threshold in one step.

The gaussian-blur based pattern of weights can be something else - any kind of 2D pattern can be used. And the thresholds can even be varied, based on the co-ordinates. This is very similar to the algorithms for dithering in images with limited colour palettes. Floyd-Steinberg is a well-known approach, but remember that your goals are different.

One way you could vary these weights is to have higher thresholds nearer some marker points, and lower thresholds near others. In that way, you could thicken the walls in some areas and thin them in others.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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