Мой перлин-шум выглядит неправильно, почти как серый материал для футболок (вереск). Зачем?

Я попробовал быстрый и грязный перевод кода здесь: 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

2

Решение

Чтобы преобразовать 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;
2

Другие решения

Это прямая копия вашего кода? Вы задали целое число для того, что должно быть дробным значением 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}

чтобы получить хорошее изображение в градациях серого.

0

По вопросам рекламы [email protected]