Perlin噪声,块状,c++

Perlin noise, blocky,c++

本文关键字:c++ 块状 Perlin 噪声      更新时间:2023-10-16

好吧,首先,我正在尝试实现Perlin噪声算法,但我设法实现了一些奇怪的东西,但我找不到解决方案。我正在使用matlab可视化结果,我已经检查了这个问题:

"Blocky";珀林噪声

我在这个网站上做这件事:

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

还有另一个网站,我现在找不到,但我会尽快更新。

下面是一些关于这个问题的图片:

如果增加缩放,这就是问题所在https://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声明为intlong,并将其原样传递给smoothNoise()和rand2()。

这可能是由于整数值floorXfloorX + 1的表示中的浮点错误而发生的。ulp或更小的ε可以有任意一个符号。加法结果[floor(n)+1]和直接加法结果[fFloor(n+1)]由不同的代码绑定,因此不需要共享选择在哪一边出错的模式。当结果在不同的一边出错时,int型cast会相等地去除0.99999999999和0.0000000001,将数学上等价的数字视为不同。