Perlin Noise instead of Simplex Noise

Jul 6, 2011 at 2:32 AM

It is to my knowledge that the Techcraft engine current utilizes Simplex Noise.

I don't know if the private rewrite uses Simplex too, but I would highly suggest switching over the Perlin Noise, simply because at 2 and 3 dimensions, Perlin Noise is faster than Simplex.  The computation cost for Perlin Noise is 2^i, while Simplex Noise is i^2.  While there is no performance gain at two dimensions, at three dimensions, Perlin noise is 8, while Simplex noise is 9.

Also, Perlin Noise apparently fits block games better, I forget why, but I remember it has something to do with the algorithm it uses, and how Simplex uses triangles.

I've created a class based on Ken Perlin's actual implementation of Improved Noise (http://mrl.nyu.edu/~perlin/noise/)

 

public class PerlinNoise 
    { 
        private int[] permutations = new int[512]; 
           
        private Random random; 
 
        public PerlinNoise() 
            : this(Environment.TickCount) 
        { } 
 
        public PerlinNoise(int seed) 
        { 
            random = new Random(seed); 
 
            for (int i = 0; i < 256; i++) 
            { 
                permutations[i] = i; 
            } 
 
            for (int i = 0; i < 256; i++) 
            { 
                int k = random.Next(256 - i) + i; 
 
                int l = permutations[i]; 
 
                permutations[i] = permutations[k]; 
                permutations[k] = l; 
                permutations[i + 256] = permutations[i]; 
            } 
        } 
 
        private int fastfloor(float x) 
        { 
            return x > 0 ? (int)x : (int)x - 1; 
        } 
 
        private float fade(float t) 
        { 
            return t * t * t * (t * (t * 6 - 15) + 10); 
        } 
 
        private float lerp(float t, float a, float b) 
        { 
            return a + t * (b - a); 
        } 
 
        public float grad(int hash, float x, float y, float z) 
        { 
            int h = hash & 15; 
 
            float u = h < 8 ? x : y, 
                v = h < 4 ? y : h == 12 || h == 14 ? x : z; 
 
            return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); 
        } 
 
        public float noise3d(float x, float y, float z) 
        { 
            int X = fastfloor(x) & 0xff, 
                Y = fastfloor(y) & 0xff, 
                Z = fastfloor(z) & 0xff; 
 
            x -= fastfloor(x); 
            y -= fastfloor(y); 
            z -= fastfloor(z); 
 
            float u = fade(x); 
            float v = fade(y); 
            float w = fade(z); 
 
            int A = permutations[X] + Y, AA = permutations[A] + Z, AB = permutations[A + 1] + Z, 
                B = permutations[X + 1] + Y, BA = permutations[B] + Z, BB = permutations[B + 1] + Z; 
 
            return lerp(w, lerp(v, lerp(u, grad(permutations[AA], x, y, z), 
                                     grad(permutations[BA], x - 1, y, z)), 
                             lerp(u, grad(permutations[AB], x, y - 1, z), 
                                     grad(permutations[BB], x - 1, y - 1, z))), 
 
                             lerp(v, lerp(u, grad(permutations[AA + 1], x, y, z - 1), 
                                     grad(permutations[BA + 1], x - 1, y, z - 1)), 
                             lerp(u, grad(permutations[AB + 1], x, y - 1, z - 1), 
                                     grad(permutations[BB + 1], x - 1, y - 1, z - 1)))); 
        } 
 
        public float noise2d(float x, float y) 
        { 
            return noise3d(x, y, 0f); 
        } 
    } 

It outputs 0.0F all the time, and I have no idea why.  Hopefully you guys can successfully implement this in the next commit. :)

Coordinator
Jul 6, 2011 at 3:17 AM

Good to hear from one of our old IRC mates ;) 

Thats definitely worth investigating ! But not now, we are already overwhelmed by all our own super secret gameplay additions and all the bugs they introduce in our engine ;)

By the way, followers of the opensource techcraft will be the first to know when we will release something !

Developer
Jul 6, 2011 at 10:22 AM

Hi Tony,

The newtake.model.terrain namespace has a 3d simplex method:

public static float noise(float xin, float yin, float zin)

In your code the noise2d method parses a zero float for z. Is that what you refer to as returning 0.0f from the noise3d method?

 

Jul 6, 2011 at 6:46 PM

Enomi: Can't wait for the day you guys announce them. :)

Jacoo: Not exactly.  At first, I just decided that I'd just use 3d noise for my 2d noise, but just setting the z value to 0.  However, when that failed (it outputted 0), I decided to see if the noise3d function even worked.  When I tried noise3d(args[0]...), it still put out 0.  So I'm really confused about this. :P

Developer
Jul 6, 2011 at 10:17 PM

Hi,

im just curious but did you try replacing the randomness in the permutations with ken's array, just to see if it makes a difference?

Jul 6, 2011 at 10:20 PM
Edited Jul 6, 2011 at 10:22 PM

Yup, I did.

Still 0. :(

 

I've also tried the old fashioned 

for(int i = 0; i < 256; i++)
    permutations[i] = permuations[i + 256] = i;
 

Developer
Mar 19, 2012 at 1:43 PM

that could be related to that normal perlin noise returns 0 for int values. More information over; http://www.programmersheaven.com/2/perlin

Another disadvantage that might not be obvious is that the noise function always returns 0 at integer values. Although this is not noticable on static images it is very apparent on animated images. I made a 3D perlin noise function and rendered it on a 2D texture map while moving along the z-axis, this had the effect of a pulsating map. This because every time the z value was integer there where many values around 0, while the z where between integer values there where more randomness.

Developer
Mar 19, 2012 at 2:01 PM

and I'm really not sure if perlin noise is better in complexity (even in lower dimensions) - http://en.wikipedia.org/wiki/Simplex_noise