Created
December 9, 2015 01:16
-
-
Save jessevanherk/e5c2faa9d4d6a594a69f to your computer and use it in GitHub Desktop.
direct implementation of simplex and perlin noise in C, no optimizations, allowing for speed comparison.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <math.h> | |
int grad3[12][3] = {{1,1,0},{-1,1,0},{1,-1,0},{-1,-1,0}, | |
{1,0,1},{-1,0,1},{1,0,-1},{-1,0,-1}, | |
{0,1,1},{0,-1,1},{0,1,-1},{0,-1,-1}}; | |
int p[] = {151,160,137,91,90,15, | |
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23, | |
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33, | |
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166, | |
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244, | |
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196, | |
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123, | |
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42, | |
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9, | |
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228, | |
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107, | |
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, | |
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180}; | |
int perm[512]; | |
/* This method is a *lot* faster than using (int)Math.floor(x) */ | |
int fastfloor(double x) { | |
return x>0 ? (int)x : (int)x-1; | |
} | |
double dot2d(int g[3], double x, double y) { | |
return g[0]*x + g[1]*y; | |
} | |
double dot3d(int g[3], double x, double y, double z) { | |
return g[0]*x + g[1]*y + g[2]*z; | |
} | |
double mix(double a, double b, double t) { | |
return (1-t)*a + t*b; | |
} | |
double fade(double t) { | |
return t*t*t*(t*(t*6-15)+10); | |
} | |
/* Classic Perlin noise, 3D version */ | |
double classic_noise(double x, double y, double z) { | |
/* Find unit grid cell containing point */ | |
int X = fastfloor(x); | |
int Y = fastfloor(y); | |
int Z = fastfloor(z); | |
/* Get relative xyz coordinates of point within that cell */ | |
x = x - X; | |
y = y - Y; | |
z = z - Z; | |
/* Wrap the integer cells at 255 (smaller integer period can be introduced here) */ | |
X = X & 255; | |
Y = Y & 255; | |
Z = Z & 255; | |
/* Calculate a set of eight hashed gradient indices */ | |
int gi000 = perm[X+perm[Y+perm[Z]]] % 12; | |
int gi001 = perm[X+perm[Y+perm[Z+1]]] % 12; | |
int gi010 = perm[X+perm[Y+1+perm[Z]]] % 12; | |
int gi011 = perm[X+perm[Y+1+perm[Z+1]]] % 12; | |
int gi100 = perm[X+1+perm[Y+perm[Z]]] % 12; | |
int gi101 = perm[X+1+perm[Y+perm[Z+1]]] % 12; | |
int gi110 = perm[X+1+perm[Y+1+perm[Z]]] % 12; | |
int gi111 = perm[X+1+perm[Y+1+perm[Z+1]]] % 12; | |
/* The gradients of each corner are now: | |
* g000 = grad3[gi000]; | |
* g001 = grad3[gi001]; | |
* g010 = grad3[gi010]; | |
* g011 = grad3[gi011]; | |
* g100 = grad3[gi100]; | |
* g101 = grad3[gi101]; | |
* g110 = grad3[gi110]; | |
* g111 = grad3[gi111]; */ | |
/* Calculate noise contributions from each of the eight corners */ | |
double n000= dot3d(grad3[gi000], x, y, z); | |
double n100= dot3d(grad3[gi100], x-1, y, z); | |
double n010= dot3d(grad3[gi010], x, y-1, z); | |
double n110= dot3d(grad3[gi110], x-1, y-1, z); | |
double n001= dot3d(grad3[gi001], x, y, z-1); | |
double n101= dot3d(grad3[gi101], x-1, y, z-1); | |
double n011= dot3d(grad3[gi011], x, y-1, z-1); | |
double n111= dot3d(grad3[gi111], x-1, y-1, z-1); | |
/* Compute the fade curve value for each of x, y, z */ | |
double u = fade(x); | |
double v = fade(y); | |
double w = fade(z); | |
/* Interpolate along x the contributions from each of the corners */ | |
double nx00 = mix(n000, n100, u); | |
double nx01 = mix(n001, n101, u); | |
double nx10 = mix(n010, n110, u); | |
double nx11 = mix(n011, n111, u); | |
/* Interpolate the four results along y */ | |
double nxy0 = mix(nx00, nx10, v); | |
double nxy1 = mix(nx01, nx11, v); | |
/* Interpolate the two last results along z */ | |
double nxyz = mix(nxy0, nxy1, w); | |
return nxyz; | |
} | |
/* 2D simplex noise */ | |
double simplex_noise_2d(double xin, double yin) { | |
double n0, n1, n2; | |
/* Noise contributions from the three corners */ | |
/* Skew the input space to determine which simplex cell we're in */ | |
double F2 = 0.5*(sqrt(3.0)-1.0); | |
double s = (xin+yin)*F2; | |
/* Hairy factor for 2D */ | |
int i = fastfloor(xin+s); | |
int j = fastfloor(yin+s); | |
double G2 = (3.0-sqrt(3.0))/6.0; | |
double t = (i+j)*G2; | |
double X0 = i-t; | |
/* Unskew the cell origin back to (x,y) space */ | |
double Y0 = j-t; | |
double x0 = xin-X0; | |
/* The x,y distances from the cell origin */ | |
double y0 = yin-Y0; | |
/* For the 2D case, the simplex shape is an equilateral triangle.*/ | |
/* Determine which simplex we are in. */ | |
int i1, j1; | |
/* Offsets for second (middle) corner of simplex in (i,j) coords */ | |
if(x0>y0) {i1=1; j1=0;} | |
/* lower triangle, XY order: (0,0)->(1,0)->(1,1) */ | |
else {i1=0; j1=1;} | |
/* upper triangle, YX order: (0,0)->(0,1)->(1,1) */ | |
/* A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and */ | |
/* a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where */ | |
/* c = (3-sqrt(3))/6 */ | |
double x1 = x0 - i1 + G2; | |
/* Offsets for middle corner in (x,y) unskewed coords */ | |
double y1 = y0 - j1 + G2; | |
double x2 = x0 - 1.0 + 2.0 * G2; | |
/* Offsets for last corner in (x,y) unskewed coords */ | |
double y2 = y0 - 1.0 + 2.0 * G2; | |
/* Work out the hashed gradient indices of the three simplex corners */ | |
int ii = i & 255; | |
int jj = j & 255; | |
int gi0 = perm[ii+perm[jj]] % 12; | |
int gi1 = perm[ii+i1+perm[jj+j1]] % 12; | |
int gi2 = perm[ii+1+perm[jj+1]] % 12; | |
/* Calculate the contribution from the three corners */ | |
double t0 = 0.5 - x0*x0-y0*y0; | |
if(t0<0) n0 = 0.0; | |
else { | |
t0 *= t0; | |
n0 = t0 * t0 * dot2d(grad3[gi0], x0, y0); | |
/* (x,y) of grad3 used for 2D gradient */ | |
} | |
double t1 = 0.5 - x1*x1-y1*y1; | |
if(t1<0) n1 = 0.0; | |
else { | |
t1 *= t1; | |
n1 = t1 * t1 * dot2d(grad3[gi1], x1, y1); | |
} | |
double t2 = 0.5 - x2*x2-y2*y2; | |
if(t2<0) n2 = 0.0; | |
else { | |
t2 *= t2; | |
n2 = t2 * t2 * dot2d(grad3[gi2], x2, y2); | |
} | |
/* Add contributions from each corner to get the final noise value. */ | |
/* The result is scaled to return values in the interval [-1,1]. */ | |
return 70.0 * (n0 + n1 + n2); | |
} | |
/* 3D simplex noise */ | |
double simplex_noise_3d(double xin, double yin, double zin) | |
{ | |
double n0, n1, n2, n3; | |
/* Noise contributions from the four corners */ | |
/* Skew the input space to determine which simplex cell we're in */ | |
double F3 = 1.0/3.0; | |
double s = (xin+yin+zin)*F3; | |
/* Very nice and simple skew factor for 3D */ | |
int i = fastfloor(xin+s); | |
int j = fastfloor(yin+s); | |
int k = fastfloor(zin+s); | |
double G3 = 1.0/6.0; | |
/* Very nice and simple unskew factor, too */ | |
double t = (i+j+k)*G3; | |
double X0 = i-t; | |
/* Unskew the cell origin back to (x,y,z) space */ | |
double Y0 = j-t; | |
double Z0 = k-t; | |
double x0 = xin-X0; | |
/* The x,y,z distances from the cell origin */ | |
double y0 = yin-Y0; | |
double z0 = zin-Z0; | |
/* For the 3D case, the simplex shape is a slightly irregular tetrahedron. */ | |
/* Determine which simplex we are in. */ | |
int i1, j1, k1; | |
/* Offsets for second corner of simplex in (i,j,k) coords */ | |
int i2, j2, k2; | |
/* Offsets for third corner of simplex in (i,j,k) coords */ | |
if(x0>=y0) { | |
if(y0>=z0) | |
{ i1=1; j1=0; k1=0; i2=1; j2=1; k2=0; } | |
/* X Y Z order */ | |
else if(x0>=z0) { i1=1; j1=0; k1=0; i2=1; j2=0; k2=1; } | |
/* X Z Y order */ | |
else { i1=0; j1=0; k1=1; i2=1; j2=0; k2=1; } | |
/* Z X Y order */ | |
} | |
else { | |
/* x0<y0 */ | |
if(y0<z0) { i1=0; j1=0; k1=1; i2=0; j2=1; k2=1; } | |
/* Z Y X order */ | |
else if(x0<z0) { i1=0; j1=1; k1=0; i2=0; j2=1; k2=1; } | |
/* Y Z X order */ | |
else { i1=0; j1=1; k1=0; i2=1; j2=1; k2=0; } | |
/* Y X Z order */ | |
} | |
/* A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z), */ | |
/* a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and */ | |
/* a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where */ | |
/* c = 1/6. */ | |
double x1 = x0 - i1 + G3; | |
/* Offsets for second corner in (x,y,z) coords */ | |
double y1 = y0 - j1 + G3; | |
double z1 = z0 - k1 + G3; | |
double x2 = x0 - i2 + 2.0*G3; | |
/* Offsets for third corner in (x,y,z) coords */ | |
double y2 = y0 - j2 + 2.0*G3; | |
double z2 = z0 - k2 + 2.0*G3; | |
double x3 = x0 - 1.0 + 3.0*G3; | |
/* Offsets for last corner in (x,y,z) coords */ | |
double y3 = y0 - 1.0 + 3.0*G3; | |
double z3 = z0 - 1.0 + 3.0*G3; | |
/* Work out the hashed gradient indices of the four simplex corners */ | |
int ii = i & 255; | |
int jj = j & 255; | |
int kk = k & 255; | |
int gi0 = perm[ii+perm[jj+perm[kk]]] % 12; | |
int gi1 = perm[ii+i1+perm[jj+j1+perm[kk+k1]]] % 12; | |
int gi2 = perm[ii+i2+perm[jj+j2+perm[kk+k2]]] % 12; | |
int gi3 = perm[ii+1+perm[jj+1+perm[kk+1]]] % 12; | |
/* Calculate the contribution from the four corners */ | |
double t0 = 0.6 - x0*x0 - y0*y0 - z0*z0; | |
if(t0<0) n0 = 0.0; | |
else { | |
t0 *= t0; | |
n0 = t0 * t0 * dot3d(grad3[gi0], x0, y0, z0); | |
} | |
double t1 = 0.6 - x1*x1 - y1*y1 - z1*z1; | |
if(t1<0) n1 = 0.0; | |
else { | |
t1 *= t1; | |
n1 = t1 * t1 * dot3d(grad3[gi1], x1, y1, z1); | |
} | |
double t2 = 0.6 - x2*x2 - y2*y2 - z2*z2; | |
if(t2<0) n2 = 0.0; | |
else { | |
t2 *= t2; | |
n2 = t2 * t2 * dot3d(grad3[gi2], x2, y2, z2); | |
} | |
double t3 = 0.6 - x3*x3 - y3*y3 - z3*z3; | |
if(t3<0) n3 = 0.0; | |
else { | |
t3 *= t3; | |
n3 = t3 * t3 * dot3d(grad3[gi3], x3, y3, z3); | |
} | |
/* Add contributions from each corner to get the final noise value. */ | |
/* The result is scaled to stay just inside [-1,1] */ | |
return 32.0*(n0 + n1 + n2 + n3); | |
} | |
int main( int argc, char *argv[] ) { | |
int num_points = 500; /* how many points to calculate, in each direction! */ | |
int i, j, k; | |
int noise_type = 1; /* default to 3d simplex. */ | |
if ( argc != 2 ) { | |
printf( "usage: %s <noise_type>\n noise types: \n\t1 -> classic noise\n\t2 -> 2d simplex\n\t3 -> 3d simplex \n", argv[ 0 ] ); | |
return 1; | |
} | |
else { | |
noise_type = *argv[ 1 ]; | |
} | |
/* To remove the need for index wrapping, double the permutation table length */ | |
for ( i = 0; i < 512; i++) { | |
perm[ i ] = p[ i & 255 ]; | |
} | |
if ( noise_type == '1' ) { /* classic 3d perlin noise. */ | |
for ( k = 0; k < num_points; k++ ) { | |
for ( j = 0; j < num_points; j++ ) { | |
for ( i = 0; i < num_points; i++ ) { | |
double noise = classic_noise( i / 8.0, j / 8.0, k / 8.0 ); | |
noise = noise * 1.0; /* dummy noop to avoid compile warning. */ | |
} | |
} | |
} | |
} | |
else if ( noise_type == '2' ) { /* 2d simplex noise. */ | |
for ( j = 0; j < num_points * num_points; j++ ) { /* make up for being in a 2d plane by doing more */ | |
for ( i = 0; i < num_points; i++ ) { | |
double noise = simplex_noise_2d( i / 8.0, j / 8.0 ); | |
noise = noise * 1.0; /* dummy noop to avoid compile warning. */ | |
} | |
} | |
} | |
else if ( noise_type == '3' ) { /* 3d simplex noise. */ | |
for ( k = 0; k < num_points; k++ ) { | |
for ( j = 0; j < num_points; j++ ) { | |
for ( i = 0; i < num_points; i++ ) { | |
double noise = simplex_noise_3d( i / 8.0, j / 8.0, k / 8.0 ); | |
noise = noise * 1.0; /* dummy noop to avoid compile warning. */ | |
} | |
} | |
} | |
} | |
else { | |
printf( "unknown noise type.\n" ); | |
return 2; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment