Я попробовал быстрый и грязный перевод кода здесь: http://freespace.virgin.net/hugo.elias/models/m_perlin.htm
Тем не менее, моя версия выдает шум, сравнимый с серым материалом футболки или вереском, если вам нравится:
#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;
}
Я не верю, что я слишком далеко отошел от вышеупомянутых указаний сайта, за исключением добавления кода генерации изображений в ppm, но, опять же, я признаю, что не до конца понял, что происходит в коде.
Как вы увидите в разделе с комментариями, я попробовал два (аналогичных) способа генерации псевдослучайных чисел для шума. Я также пробовал разные способы масштабирования чисел, возвращаемых perlin_2D, в значения цвета RGB. Эти два способа редактирования кода привели к разным видам футболок. Поэтому я вынужден верить, что происходит нечто большее, что я не могу распознать.
Кроме того, я компилирую с g ++ и стандартом c ++ 11.
РЕДАКТИРОВАТЬ: Вот пример: http://imgur.com/Sh17QjK
Чтобы преобразовать double
в диапазоне от [-1,0, 1,0] до целого числа в диапазоне [0, 255]:
n = floor((n + 1.0) / 2.0 * 255.99);
Чтобы записать его как двоичное значение в файл PPM:
ofstream ofs("./noise2D.ppm", ios_base::binary);
...
unsigned char c = n;
ofs << c << c << c;
Это прямая копия вашего кода? Вы задали целое число для того, что должно быть дробным значением Y — это опечатка, и если вы не исправите, он отключит весь алгоритм шума:
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
.....
}
Я предполагаю, что если вы успешно генерируете растровое изображение с правильным вычислением цвета, вы получаете вертикальные полосы или что-то подобное?
Вы также должны помнить, что генератор Perlin обычно выплевывает числа в диапазоне от -1 до 1, и вам нужно умножить полученное значение как таковое:
значение * 127 + 128 = {R, G, B}
чтобы получить хорошее изображение в градациях серого.