首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Perlin噪声算法似乎不产生梯度噪声。

Perlin噪声算法似乎不产生梯度噪声。
EN

Stack Overflow用户
提问于 2016-05-29 10:44:36
回答 1查看 2.5K关注 0票数 4

我试图在c++中实现Perlin噪声。

首先,问题(我认为)是产出不是我所期望的。目前,我只在灰度图像中使用生成的Perlin噪声值,这是我得到的结果:

然而,根据我的理解,它看起来更像是:

也就是说,我现时所产生的噪音,似乎更接近“标准”不规则噪音。

这是我到目前为止实现的Perlin噪声算法:

代码语言:javascript
复制
float perlinNoise2D(float x, float y)
{
    // Find grid cell coordinates
    int x0 = (x > 0.0f ? static_cast<int>(x) : (static_cast<int>(x) - 1));
    int x1 = x0 + 1;
    int y0 = (y > 0.0f ? static_cast<int>(y) : (static_cast<int>(y) - 1));
    int y1 = y0 + 1;

    float s = calculateInfluence(x0, y0, x, y);
    float t = calculateInfluence(x1, y0, x, y);
    float u = calculateInfluence(x0, y1, x, y);
    float v = calculateInfluence(x1, y1, x, y);

    // Local position in the grid cell
    float localPosX = 3 * ((x - (float)x0) * (x - (float)x0)) - 2 * ((x - (float)x0) * (x - (float)x0) * (x - (float)x0));
    float localPosY = 3 * ((y - (float)y0) * (y - (float)y0)) - 2 * ((y - (float)y0) * (y - (float)y0) * (y - (float)y0));

    float a = s + localPosX * (t - s);
    float b = u + localPosX * (v - u);

    return lerp(a, b, localPosY);
}

函数calculateInfluence为当前网格单元的一个角点生成随机梯度矢量和距离向量,并返回这些点的点积。它的实施方式是:

代码语言:javascript
复制
float calculateInfluence(int xGrid, int yGrid, float x, float y)
{
    // Calculate gradient vector
    float gradientXComponent = dist(rdEngine);
    float gradientYComponent = dist(rdEngine);

    // Normalize gradient vector
    float magnitude = sqrt( pow(gradientXComponent, 2) + pow(gradientYComponent, 2) );
    gradientXComponent = gradientXComponent / magnitude;
    gradientYComponent = gradientYComponent / magnitude;
    magnitude = sqrt(pow(gradientXComponent, 2) + pow(gradientYComponent, 2));

    // Calculate distance vectors
    float dx = x - (float)xGrid;
    float dy = y - (float)yGrid;

    // Compute dot product
    return (dx * gradientXComponent + dy * gradientYComponent);
}

在这里,dist是来自C++11的随机数生成器:

代码语言:javascript
复制
std::mt19937 rdEngine(1);
std::normal_distribution<float> dist(0.0f, 1.0f);

lerp被简单地实现为:

代码语言:javascript
复制
float lerp(float v0, float v1, float t)
{
    return ( 1.0f - t ) * v0 + t * v1;
}

为了实现该算法,我主要使用了以下两个资源:

Perlin噪声常见问题 Perlin噪声伪码

我很难准确地指出我似乎在搞砸的地方。这可能是我不正确地生成梯度向量,因为我不太确定它们应该有什么样的分布。我尝试了一个统一的分布,但是这似乎会在纹理中产生重复的模式!

同样,我可能是不正确地将影响值平均化。从Perlin噪声FAQ的文章中,很难准确地看出它应该如何做。

有人对代码可能有什么问题有任何提示吗?:)

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-05-29 11:44:03

似乎你只产生一个八度的佩林噪音。要获得如图所示的结果,需要生成多重八度并将它们相加在一起。在一系列的八度音阶中,每个八度的网格单元尺寸应该是最后一个的两倍。

要产生多倍频程噪声,请使用类似的方法:

代码语言:javascript
复制
float multiOctavePerlinNoise2D(float x, float y, int octaves)
{
    float v = 0.0f;
    float scale = 1.0f;
    float weight = 1.0f;
    float weightTotal = 0.0f;
    for(int i = 0; i < octaves; i++)
    {
        v += perlinNoise2D(x * scale, y * scale) * weight;
        weightTotal += weight;
        // "ever-increasing frequencies and ever-decreasing amplitudes"
        // (or conversely decreasing freqs and increasing amplitudes)
        scale *= 0.5f; 
        weight *= 2.0f;
    }
    return v / weightTotal;
}

对于额外的随机性,您可以使用一个不同的种子随机发生器为每个八度。此外,给每个八度的权重可以改变,以调整噪音的审美品质。如果权重变量没有在每次迭代中进行调整,那么上面的例子就是“粉红噪音” (频率的每一倍都具有相同的权重)。

另外,您需要使用一个随机数生成器,它每次为给定的xGrid,yGrid对返回相同的值。

票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37508938

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档