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 ...

Cairnarvon
  • 25,981
  • 9
  • 51
  • 65
tankyx
  • 87
  • 1
  • 10

2 Answers2

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.

  • What's `noise_hander`? Is it just any function which can give you noise? (In which case, what's a `hander`? Why not just call it `noise_generator`?) – Nic Jul 20 '18 at 04:13
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.

Community
  • 1
  • 1
Aki Suihkonen
  • 19,144
  • 1
  • 36
  • 57
  • I change the line : "n = pow((n << 13), n);" to "n = (n << 13) ^ n" which was a first error. Now I get bar code. How should I adapt the pseudo code of this function, written on the tutorial, to C language, if it under or overflow ? – tankyx May 15 '13 at 16:57
  • The bar code is an indication of the selection of the formula `n=x+y*57`; where when you use (x+1) vs (y+1) one of those changes doesn't change the output much (or at all). (x+1) vs. (y+1)*57 ? – Aki Suihkonen May 15 '13 at 18:15
  • If I change for n = (x*57) + (y * 57), i get some other colors but always bar code, as if I try n = (x + y) * 57. Perlin values are modified, but still draws a cycle ... – tankyx May 15 '13 at 18:31