2D perlin noise in C

2

I followed this tutorial.

When I implement it in my code (Raytracing), and apply it on a sphere, I get a uni-color sphere, with one stripe of darker pixel on it. When I change the random float generator, I got the basic linear noise, which isn't my goal. Can you explain what I missed?

Here is my code:

#include    <stdlib.h>
#include    <math.h>

float       noise(int x, int y)
{
  int       n;

  n = x + y * 57;
  n = pow((n << 13), n);
  return (1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
}

float       interpolate(float a, float b, float x)
{
  float     pi_mod;
  float     f_unk;

  pi_mod = x * 3.1415927;
  f_unk = (1 - cos(pi_mod)) * 0.5;
  return (a * (1 - f_unk) + b * x);
}

float       smooth_noise(int x, int y)
{
  float     corners;
  float     center;
  float     sides;

  corners = (noise(x - 1, y - 1) + noise(x + 1, y - 1) +
         noise(x - 1, x + 1) + noise(x + 1, y + 1)) / 16;
  sides = (noise(x - 1, y) + noise(x + 1, y) + noise(x, y - 1) +
       noise(x, y + 1)) / 8;
  center = noise(x, y) / 4;
  return (corners + sides + center);
}

float       noise_handler(float x, float y)
{
  int       int_val[2];
  float     frac_val[2];
  float     value[4];
  float     res[2];

  int_val[0] = (int)x;
  int_val[1] = (int)y;
  frac_val[0] = x - int_val[0];
  frac_val[1] = y - int_val[1];
  value[0] = smooth_noise(int_val[0], int_val[1]);
  value[1] = smooth_noise(int_val[0] + 1, int_val[1]);
  value[2] = smooth_noise(int_val[0], int_val[1] + 1);
  value[3] = smooth_noise(int_val[0] + 1, int_val[1] + 1);
  res[0] = interpolate(value[0], value[1], frac_val[0]);
  res[1] = interpolate(value[2], value[3], frac_val[0]);
  return (interpolate(res[0], res[1], frac_val[1]));
}

float       perlin_two(float x, float y)
{
  float     total;
  float     per;
  float     amp;
  int       hz;
  int       i;
  int       octave;

  total = 0.0;
  per = 0.5;
  octave = 10;
  i = 0;
  while (i < octave)
    {
      hz = pow(2, i);
      amp = pow(per, (float)i);
      total += noise_handler(x * (float)hz, y * (float)hz) * amp;
      i += 1;
    }
  return (total);
}

EDIT: I spot an error in the Noise function (I consider the XOR operand like a power function ... Now I get a barcode, as if the y parameter was ignored in the operations ...

c
algorithm
asked on Stack Overflow May 15, 2013 by tankyx • edited May 15, 2013 by Cairnarvon

2 Answers

3

Had to implement this in C recently and this post helped get me started. One fix for the noise function as previously stated.

float noise(int x, int y) {
    int n;

    n = x + y * 57;
    n = (n << 13) ^ n;
    return (1.0 - ( (n * ((n * n * 15731) + 789221) +  1376312589) & 0x7fffffff) / 1073741824.0);
}

Most importantly, is that Fractal Brownian Motion is really important when implementing Perlin Noise for use in a height map. Instead of following the pseudo code by Hugo Elias, I used this Google Code Snippet.

float perlin_two(float x, float y, float gain, int octaves, int hgrid) {
    int i;
    float total = 0.0f;
    float frequency = 1.0f/(float)hgrid;
    float amplitude = gain;
    float lacunarity = 2.0;

    for (i = 0; i < octaves; ++i)
    {
        total += noise_handler((float)x * frequency, (float)y * frequency) * amplitude;         
        frequency *= lacunarity;
        amplitude *= gain;
    } 

    return (total);
}

Before I did this, I'd had the same issue with uniform 'stripping' or just complete random looking height maps.

answered on Stack Overflow Feb 4, 2015 by BlastingKap • edited Jul 31, 2019 by BlastingKap
0

You got to debug & rework probably all your variable types; do the math in pen & paper or in a debugger and check the range of the values. e.g. here

noise(int x, int y) {
      int n = x + y * 57;
      n = pow((n << 13), n);  ...
}

n will either underflow or overflow for almost all non-zero values. Good random values can't be produced with any random method, which is what these formulas look like.

Check also this topic for some reference code.

answered on Stack Overflow May 15, 2013 by Aki Suihkonen • edited May 23, 2017 by Community

User contributions licensed under CC BY-SA 3.0