Перлин шум, блочный, с ++

0

Хорошо, в первую очередь, я пытаюсь реализовать алгоритм шума Perlin, и мне удалось добиться чего-то странного, и я не могу найти решение. Я использую matlab для визуализации результатов, которые я уже проверял на этот вопрос:

"Блочный" шум Перлина

Я делаю это с этого сайта:

http://freespace.virgin.net/hugo.elias/models/m_perlin.htm

И еще один сайт, который я не могу найти прямо сейчас, но я обновлю, как только смогу.

Итак, вот несколько фотографий о проблеме:

Это проблема, если увеличить масштаб 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;
}
  • 0
    Просто предложение, но посмотрите на Simplex Noise для улучшенной версии перлин-шума. 6by9.net/simplex-noise-for-c-and-python
Теги:
noise
perlin-noise

2 ответа

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)) приведет к разрыву ячейки.

  • 0
    Большое спасибо! Это идеальный пример, чтобы не Ctrl + C Ctrl + V: D
0

Не обнаруживая математической ошибки в вашей реализации, я подозреваю, что это проблема с числовым форматом.

Такие шаблоны блоков создаются, когда значения точек сетки на самом деле не одинаковы при извлечении с разных сторон - когда rand2(floor(n) +1 ,y) != rand2(floor(n+1) ,y)

Чтобы исправить это, объявите floorX как int или long вместо этого, и передайте его как таковое для smoothNoise() и rand2().

Это может произойти из-за ошибки с плавающей запятой в представлении значений Integer floorX, floorX + 1. Эпсилон величины ulp или менее может иметь либо знак. результаты добавления [floor (n) + 1] и напольного покрытия непосредственно [floor (n +1)] связаны друг от друга кодом, и поэтому не нужно использовать шаблон выбора, с какой стороны следует ошибаться. Когда результаты ошибочны на разных сторонах, тип типа type отличает полосы 0.99999999999 и 0.0000000001 одинаково, рассматривая математически эквивалентные числа как разные.

  • 0
    К сожалению, кажется, что это не работает или, может быть, я снова делаю что-то не так. Я изменил double floorX = (double)floor(x); для int floorX = floor(x); и без изменений, тогда я также изменил это для floorY , все еще без результата, а затем я изменил s = smoothNoise(floorX+1,floorY); etc. для s = smoothNoise(floor(x+1),floorY); и сочетание всего вышеперечисленного и ни сработало. Возможно, у генератора случайностей тоже есть проблемы.
  • 0
    double Perlin::rand2(int x, int y) выполняет роль псевдослучайной хэш-функции. Это может быть что-то еще.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню