Search code examples
cnoiseperlin-noise

2D Perlin Noise looking odd


I'm not sure if my Perlin Noise generator is functioning properly, the noise it generates looks very different from the images I see online. Mine looks too homogeneous (these are three different images):

enter image description hereenter image description hereenter image description here

Whereas what I usually see is something like:

enter image description here

My code is basically:

/* Get the coord of the top-left gradient of the grid (y, x) falls in */
int j = floor(x);
int i = floor(y);
/* Get the distance (y, x) is from it */
double dx = x-j;
double dy = y-i;
/* Influence of (g)radient(i)(j) (starting at the top-left one) */
double g00 = dot(grad(hashes, hsize, grads, i, j), dy, dx);
double g01 = dot(grad(hashes, hsize, grads, i, j+1), dy, dx-1);
double g10 = dot(grad(hashes, hsize, grads, i+1, j), dy-1, dx);
double g11 = dot(grad(hashes, hsize, grads, i+1, j+1), dy-1, dx-1);
/* Interpolate the influences using the blending function */
/* Linear interpol the top 2 */
double lt = lerp(g00, g01, fade(dx));
/* Linear interpol the bottom 2 */
double lb = lerp(g10, g11, fade(dx));
/* Linear interpol lb lt, completing the bilienear interpol */
return lerp(lt, lb, fade(dy));

Complete code. It's based mainly on this tutorial. I'm using this script to draw the csv file.

I understand the basics, but after reading several "tutorials" that usually contradict each other and the "reference implementation" which is not very readable I have a few doubts. The (x, y) points being interpolated should be in what interval? As I understand it, it should be [0, GRID_SIZE-1] (e.g. [0, 255] if using a pre-computed table with 256 random values). However, my code only results in reasonably good looking images when (x, y) is mapped to [0, 1], and I see some implementations online that map it to [0, 255] no matter the grid size. I'm also unsure if I'm picking the gradients correctly from the table.


Solution

  • You normalize your pixel coordinates to the whole image. You should normalize it to the size of your simplex grid.

    So instead of your code for the inner loop:

      double x = j/(double)w;
      double y = i/(double)h;
    

    do:

      double x = j / gridsize;
      double y = i / gridsize;
    

    where the grid size is an additional parameter, for example:

      double gridsize = 32.0;
    

    (It should probably be chosen to fit evenly into the image dimensions.)