Хорошо, во-первых, я пытаюсь реализовать алгоритм шума Перлина, и мне удалось добиться чего-то странного, и я не могу найти решение. Я использую matlab для визуализации результатов. Я уже проверил этот вопрос:
Я делаю это с этого сайта:
И еще один веб-сайт, который я не могу найти прямо сейчас, но обновлю, как только смогу.
Итак, вот несколько фотографий о проблеме:
Это проблема, если увеличить зум
http://i.stack.imgur.com/KkD7u.png
А вот и .cpp-s:
//perlin.cpp
#include "Perlin_H.h"#include <stdlib.h>
#include <math.h>
#include <iostream>
#include <random>
using namespace std;
double Perlin::interp1(double a, double b, double x) {
double ft = x * 3.1415927;
double f = (1.0-cos(ft)) * 0.5;
//return (b-x > b-1/2) ? b-x : a+x;
return a * (1.0-f) + b * f;
}
double Perlin::smoothNoise(double x,double y) {
double corners = ( rand2(x-1, y-1)+rand2(x+1, y-1)+rand2(x-1, y+1)+rand2(x+1, y+1) ) / 16;
double sides = ( rand2(x-1, y) +rand2(x+1, y) +rand2(x, y-1) +rand2(x, y+1) ) / 8;
double center = rand2(x,y)/4;
return corners + sides +center;
}double Perlin::lininterp1(double a,double b, double x) {
return a*(1-x) + b * x;
}
double Perlin::rand2(double x, double y) {
int n = (int)x + (int)y*57;
//n=pow((n<<13),n);
n=(n<<13)^n;
return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
}
double Perlin::noise(double x, double y) {
double floorX = (double)floor(x);
double floorY = (double)floor(y);
double s,t,u,v;
s = smoothNoise(floorX,floorY);
t = smoothNoise(floorX+1,floorY);
u = smoothNoise(floorY,floorY+1);
v = smoothNoise(floorX+1,floorY+1);
double int1 = interp1(s,t,x-floorX);
double int2 = interp1(u,v,x-floorX);
return interp1(int1,int2,y-floorY);
}
//main.cpp
#include "Perlin_H.h"#include <stdlib.h>
#include <math.h>
#include <iostream>
#include <fstream>;
using namespace std;
int main() {
const int h=64,w=64,octaves=2;
double p=1/1;
double zoom = 30;
Perlin perlin;
double map[h][w];
ofstream output;
output.open("map.txt");
for(int i = 0; i < h ; i++) {
for(int j = 0; j < w ; j++) {
map[i][j] = 0;
}
}
double freq = 2;for(int i = 0; i < h ; i++) {for(int j = 0; j < w ; j++) {
double getnoise = 0;
for(int a=0; a < octaves; a++) {double freq = pow(2,a);
double amp = pow(p,a);
getnoise = perlin.noise((((double)i)*freq)/zoom-(a*10),
((((double)j))*freq)/zoom+(a*10))*amp;
int color = (int)((getnoise * 128.0) + 128.0);
if(color > 255) color = 255;
if(color < 0) color = 0;
map[i][j] = color;}
output << map[i][j] << "\t";
}
output << "\n";
}output.close();system("PAUSE");
return 0;
}
Это опечатка!
s = smoothNoise(floorX,floorY); t = smoothNoise(floorX+1,floorY); u = smoothNoise(floorY,floorY+1); v = smoothNoise(floorX+1,floorY+1);
Пытаться:
u = smoothNoise(floorX, floorY +1)
Это объясняет, почему диагональ не имела блочного вида (где x = y), и почему многие из общих элементов формы слегка отклонены зеркальным и искаженным образом.
Так как обычно очевидно, что rand2 (floor (y), floor (y) +1)! = Rand2 (floor (x), floor (y + 1)) приведет к разрыву ячейки.
Не обнаружив математической ошибки в вашей реализации, я подозреваю, что это проблема числового формата.
Такие шаблоны блоков создаются, когда значения точек сетки на самом деле не одинаковы при выборке с разных сторон — когда rand2(floor(n) +1 ,y) != rand2(floor(n+1) ,y)
Чтобы исправить это, объявите floorX как int
или же long
вместо этого, и передайте его как таковой smoothNoise () и rand2 ().
Это может произойти из-за ошибки с плавающей запятой при представлении целочисленных значений. floorX
, floorX + 1
, Эпсилон величины ulp или меньше может иметь любой знак. результаты сложения [floor (n) + 1] и покрытия пола непосредственно [floor (n + 1)] связаны другим кодом, и поэтому нет необходимости использовать шаблон выбора, на какой стороне ошибиться. Если результаты на разных сторонах ошибочны, приведение типа int разделяет 0.99999999999 и 0.0000000001 одинаково, обрабатывая математически эквивалентные числа как разные.