Skip to content

Instantly share code, notes, and snippets.

@nowl
Created February 15, 2011 19:04
Show Gist options
  • Star 51 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save nowl/828013 to your computer and use it in GitHub Desktop.
Save nowl/828013 to your computer and use it in GitHub Desktop.
Perlin Noise in C
#include <stdio.h>
static int SEED = 0;
static int hash[] = {208,34,231,213,32,248,233,56,161,78,24,140,71,48,140,254,245,255,247,247,40,
185,248,251,245,28,124,204,204,76,36,1,107,28,234,163,202,224,245,128,167,204,
9,92,217,54,239,174,173,102,193,189,190,121,100,108,167,44,43,77,180,204,8,81,
70,223,11,38,24,254,210,210,177,32,81,195,243,125,8,169,112,32,97,53,195,13,
203,9,47,104,125,117,114,124,165,203,181,235,193,206,70,180,174,0,167,181,41,
164,30,116,127,198,245,146,87,224,149,206,57,4,192,210,65,210,129,240,178,105,
228,108,245,148,140,40,35,195,38,58,65,207,215,253,65,85,208,76,62,3,237,55,89,
232,50,217,64,244,157,199,121,252,90,17,212,203,149,152,140,187,234,177,73,174,
193,100,192,143,97,53,145,135,19,103,13,90,135,151,199,91,239,247,33,39,145,
101,120,99,3,186,86,99,41,237,203,111,79,220,135,158,42,30,154,120,67,87,167,
135,176,183,191,253,115,184,21,233,58,129,233,142,39,128,211,118,137,139,255,
114,20,218,113,154,27,127,246,250,1,8,198,250,209,92,222,173,21,88,102,219};
int noise2(int x, int y)
{
int tmp = hash[(y + SEED) % 256];
return hash[(tmp + x) % 256];
}
float lin_inter(float x, float y, float s)
{
return x + s * (y-x);
}
float smooth_inter(float x, float y, float s)
{
return lin_inter(x, y, s * s * (3-2*s));
}
float noise2d(float x, float y)
{
int x_int = x;
int y_int = y;
float x_frac = x - x_int;
float y_frac = y - y_int;
int s = noise2(x_int, y_int);
int t = noise2(x_int+1, y_int);
int u = noise2(x_int, y_int+1);
int v = noise2(x_int+1, y_int+1);
float low = smooth_inter(s, t, x_frac);
float high = smooth_inter(u, v, x_frac);
return smooth_inter(low, high, y_frac);
}
float perlin2d(float x, float y, float freq, int depth)
{
float xa = x*freq;
float ya = y*freq;
float amp = 1.0;
float fin = 0;
float div = 0.0;
int i;
for(i=0; i<depth; i++)
{
div += 256 * amp;
fin += noise2d(xa, ya) * amp;
amp /= 2;
xa *= 2;
ya *= 2;
}
return fin/div;
}
int
main(int argc, char *argv[])
{
int x, y;
for(y=0; y<4000; y++)
for(x=0; x<4000; x++)
perlin2d(x, y, 0.1, 4);
return 0;
}
@leegao
Copy link

leegao commented Feb 15, 2011

hey this is pretty cool, thanks for sharing it

@nowl
Copy link
Author

nowl commented Feb 15, 2011

Sure, no problem. Glad for the interest!

@TimBu63
Copy link

TimBu63 commented Oct 27, 2016

I also found it extremely useful and very cool. Thanks!

@max1220
Copy link

max1220 commented Feb 8, 2018

I hope you minds, but I've created a small Lua C Module from this code! https://github.com/max1220/lua-perlin

@Stolym
Copy link

Stolym commented Feb 26, 2018

You can use that with CSFML, its cool thanks ! if some one ever use for procedural Generation MP me 👍

@deeemmell
Copy link

deeemmell commented Jan 11, 2019

Very nice, thanks for sharing this!

I noticed that your implementation only works with non-negative x/y coordinates, which is a somewhat unnecessary restriction, especially considering how useful noise functions are when it comes to generating infinite maps. Here's a possible fix.

Perlin.h:

#ifndef PERLIN_H
#define PERLIN_H

extern double Perlin_Get2d(double x, double y, double freq, int depth);

#endif  // PERLIN_H

Perlin.c:

#include "Perlin.h"

#include <math.h>

static const int  SEED = 1985;

static const unsigned char  HASH[] = {
    208,34,231,213,32,248,233,56,161,78,24,140,71,48,140,254,245,255,247,247,40,
    185,248,251,245,28,124,204,204,76,36,1,107,28,234,163,202,224,245,128,167,204,
    9,92,217,54,239,174,173,102,193,189,190,121,100,108,167,44,43,77,180,204,8,81,
    70,223,11,38,24,254,210,210,177,32,81,195,243,125,8,169,112,32,97,53,195,13,
    203,9,47,104,125,117,114,124,165,203,181,235,193,206,70,180,174,0,167,181,41,
    164,30,116,127,198,245,146,87,224,149,206,57,4,192,210,65,210,129,240,178,105,
    228,108,245,148,140,40,35,195,38,58,65,207,215,253,65,85,208,76,62,3,237,55,89,
    232,50,217,64,244,157,199,121,252,90,17,212,203,149,152,140,187,234,177,73,174,
    193,100,192,143,97,53,145,135,19,103,13,90,135,151,199,91,239,247,33,39,145,
    101,120,99,3,186,86,99,41,237,203,111,79,220,135,158,42,30,154,120,67,87,167,
    135,176,183,191,253,115,184,21,233,58,129,233,142,39,128,211,118,137,139,255,
    114,20,218,113,154,27,127,246,250,1,8,198,250,209,92,222,173,21,88,102,219
};

static int noise2(int x, int y)
{
    int  yindex = (y + SEED) % 256;
    if (yindex < 0)
        yindex += 256;
    int  xindex = (HASH[yindex] + x) % 256;
    if (xindex < 0)
        xindex += 256;
    const int  result = HASH[xindex];
    return result;
}

static double lin_inter(double x, double y, double s)
{
    return x + s * (y-x);
}

static double smooth_inter(double x, double y, double s)
{
    return lin_inter( x, y, s * s * (3-2*s) );
}

static double noise2d(double x, double y)
{
    const int  x_int = floor( x );
    const int  y_int = floor( y );
    const double  x_frac = x - x_int;
    const double  y_frac = y - y_int;
    const int  s = noise2( x_int, y_int );
    const int  t = noise2( x_int+1, y_int );
    const int  u = noise2( x_int, y_int+1 );
    const int  v = noise2( x_int+1, y_int+1 );
    const double  low = smooth_inter( s, t, x_frac );
    const double  high = smooth_inter( u, v, x_frac );
    const double  result = smooth_inter( low, high, y_frac );
    return result;
}

double Perlin_Get2d(double x, double y, double freq, int depth)
{
    double  xa = x*freq;
    double  ya = y*freq;
    double  amp = 1.0;
    double  fin = 0;
    double  div = 0.0;
    for (int i=0; i<depth; i++)
    {
        div += 256 * amp;
        fin += noise2d( xa, ya ) * amp;
        amp /= 2;
        xa *= 2;
        ya *= 2;
    }
    return fin/div;
}

@max1220
Copy link

max1220 commented Jan 23, 2019

@deeemmell I hope you don't mind, I incorporated your fix into my Lua binding.

@deeemmell
Copy link

@max1220 Quite to the contrary -- glad to hear that!

@EPICPEARS
Copy link

Very Helpful Thanks Very Much @nowl

Is it all good if I incorporate your fix @deeemmell to my project ?

Thanks Very Much
EPICPEARS

@deeemmell
Copy link

Is it all good if I incorporate your fix @deeemmell to my project ?

Absolutely, please feel free to do so. Cheers!

@sherief
Copy link

sherief commented Jun 10, 2021

What's the license for this?

@Whitebrim
Copy link

What's the license for this?
@sherief

"Hippity hoppity your code is now my property"

@alexvitkov
Copy link

this is value noise, not perlin noise - it's way blockier

@motzmartin
Copy link

Hippity hoppity your code is now my property!

@strangeQuark1041
Copy link

Thanks a ton, @nowl and @deeemmell!
This is the only sane code for Perlin Noise I could find on the interwebs.
I used it here.

@Katletos
Copy link

It's not the Perlin noise, it's the value noise. Ken Perlin used random vectors instead of random numbers

@bbbradsmith
Copy link

HASH is very flawed. It only has 163 unique numbers, many repeated more than twice. 245 appears 5 times? This should just be a random permutation of all values from 0 to 255. This drastically reduces the effective randomness of your hashing.

Also, as pointed out above, this isn't Perlin noise, which should be generating a random normal vector at each corner, computing a dot product, and then interpolating that. It does use the smooth-step interpolation and the harmonic/fractal layering that normally comes with Perlin noise, but misses the core property that makes Perlin noise different than other types of noise.

@bbbradsmith
Copy link

One more thing: consider having SEED affect both X and Y in some way. The current implementation just adds it to Y, which means that all seeds are the same, just vertically displaced from each other. I think more ideally your random seed would be used to re-shuffle HASH instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment