My perlin noise looks like wrong, almost like grey t-shirt material (heather). Why?

2

I tried a quick and dirty translation of the code here.

However, my version outputs noise comparable to grey t-shirt material, or heather if it please you:

#include <fstream>
#include "perlin.h"

double Perlin::cos_Interp(double a, double b, double x)
{
  ft = x * 3.1415927;
  f = (1 - cos(ft)) * .5;

  return a * (1 - f) + b * f;
}

double Perlin::noise_2D(double x, double y)
{
  /*
  int n = (int)x + (int)y * 57;
  n = (n << 13) ^ n;
  int nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;

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

double Perlin::smooth_2D(double x, double y)
{
  corners = ( noise_2D(x - 1, y - 1) + noise_2D(x + 1, y - 1) + noise_2D(x - 1, y + 1) + noise_2D(x + 1, y + 1) ) / 16;
  sides   = ( noise_2D(x - 1, y) + noise_2D(x + 1, y) + noise_2D(x, y - 1) + noise_2D(x, y + 1) ) /  8;
  center  =  noise_2D(x, y) / 4;

  return corners + sides + center;
}

double Perlin::interp(double x, double y)
{
  int x_i = int(x);
  double x_left = x - x_i;

  int y_i = int(y);
  double y_left = y - y_i;

  double v1 = smooth_2D(x_i, y_i);
  double v2 = smooth_2D(x_i + 1, y_i);
  double v3 = smooth_2D(x_i, y_i + 1);
  double v4 = smooth_2D(x_i + 1, y_i + 1);

  double i1 = cos_Interp(v1, v2, x_left);
  double i2 = cos_Interp(v3, v4, x_left);

  return cos_Interp(i1, i2, y_left);
}

double Perlin::perlin_2D(double x, double y)
{
  double total = 0;
  double p = .25;
  int n = 1;

  for(int i = 0; i < n; ++i)
    {
      double freq =  pow(2, i);
      double amp = pow(p, i);

      total = total + interp(x * freq, y * freq) * amp;
    }

  return total;
}

int main()
{
  Perlin perl;
  ofstream ofs("./noise2D.ppm", ios_base::binary);

  ofs << "P6\n" << 512 << " " << 512 << "\n255\n";

  for(int i = 0; i < 512; ++i)
    {
      for(int j = 0; j < 512; ++j)
       {
         double n = perl.perlin_2D(i, j);

          n = floor((n + 1.0) / 2.0 * 255);

          unsigned char c = n;
          ofs << c << c << c;
       }
    }

  ofs.close();

  return 0;
}

I don't believe that I strayed too far from the aforementioned site's directions aside from adding in the ppm image generation code, but then again I'll admit to not fully grasping what is going on in the code.

As you'll see by the commented section, I tried two (similar) ways of generating pseudorandom numbers for noise. I also tried different ways of scaling the numbers returned by perlin_2D to RGB color values. These two ways of editing the code have just yielded different looking t-shirt material. So, I'm forced to believe that there's something bigger going on that I am unable to recognize.

Also, I'm compiling with g++ and the c++11 standard.

EDIT: Here's an example: http://imgur.com/Sh17QjK

c++
random
perlin-noise
ppm
noise-generator
asked on Stack Overflow Jul 19, 2014 by Stumbleine75 • edited Apr 18, 2019 by genpfault

2 Answers

2

To convert a double in the range of [-1.0, 1.0] to an integer in range [0, 255]:

n = floor((n + 1.0) / 2.0 * 255.99);

To write it as a binary value to the PPM file:

ofstream ofs("./noise2D.ppm", ios_base::binary);

...

    unsigned char c = n;
    ofs << c << c << c;
answered on Stack Overflow Jul 19, 2014 by Ross Ridge • edited Jul 22, 2014 by Ross Ridge
0

Is this a direct copy of your code? You assigned an integer to what should be the Y fractional value - it's a typo and it will throw the entire noise algorithm off if you don't fix:

 double Perlin::interp(double x, double y)
 {
     int x_i = int(x);
     double x_left = x - x_i;

     int y_i = int(y);
     double y_left = y = y_i;  //This Should have a minus, not an "=" like the line above

   .....

 }

My guess is if you're successfully generating the bitmap with the proper color computation, you're getting vertical bars or something along those lines?

You also need to remember that the Perlin generator usually spits out numbers in the range of -1 to 1 and you need to multiply the resultant value as such:

value * 127 + 128 = {R, G, B}

to get a good grayscale image.

answered on Stack Overflow Jul 20, 2014 by ThisHandleNotInUse • edited Jul 20, 2014 by ThisHandleNotInUse

User contributions licensed under CC BY-SA 3.0