我尝试仅凭理论自己实现Perlin Noise(遵循flafla2.github.io/2014/08/09/perlinnoise.html)。不幸的是,我无法获得“原始” Perlin Noise的外观。

下面的代码呈现Perlin Noise的块状版本的原因是什么?

我应该改进什么? /更改代码,以便在没有伪像的情况下呈现Perlin噪声?

我怀疑插值方式或grads向量可能存在问题。 grads向量包含(所有晶格点的随机向量)和(大小向量)的点积-所有附近的4个晶格点。 (随机和大小向量在第一个链接中进行了描述。)

GLSL沙箱:http://glslsandbox.com/e#32663.0



float fade(float t) { return t * t * t * (t * (t * 6. - 15.) + 10.); }
vec2 smooth(vec2 x) { return vec2(fade(x.x), fade(x.y)); }

vec2 hash(vec2 co) {
    return fract (vec2(.5654654, -.65465) * dot (vec2(.654, 57.4), co));
}

float perlinNoise(vec2 uv) {
    vec2 PT  = floor(uv);
    vec2 pt  = fract(uv);
    vec2 mmpt= smooth(pt);

    vec4 grads = vec4(
        dot(hash(PT + vec2(.0, 1.)), pt-vec2(.0, 1.)),   dot(hash(PT + vec2(1., 1.)), pt-vec2(1., 1.)),
        dot(hash(PT + vec2(.0, .0)), pt-vec2(.0, .0)),   dot(hash(PT + vec2(1., .0)), pt-vec2(1., 0.))
    );

    return 5.*mix (mix (grads.z, grads.w, mmpt.x), mix (grads.x, grads.y, mmpt.x), mmpt.y);
}

float fbm(vec2 uv) {
    float finalNoise = 0.;
    finalNoise += .50000*perlinNoise(2.*uv);
    finalNoise += .25000*perlinNoise(4.*uv);
    finalNoise += .12500*perlinNoise(8.*uv);
    finalNoise += .06250*perlinNoise(16.*uv);
    finalNoise += .03125*perlinNoise(32.*uv);

    return finalNoise;
}

void main() {
    vec2 position = gl_FragCoord.xy / resolution.y;
    gl_FragColor = vec4( vec3( fbm(3.*position) ), 1.0 );
}


#1 楼

插值看起来很好。这里的主要问题是您使用的哈希函数不是很好。如果我只看一个八度音阶,并通过输出hash(PT).x可视化散列结果,则会得到类似以下内容的结果: ,但是您可以看到它有很多对角线图案(看起来像棋盘格),因此它不是一个非常随机的哈希,这些图案将显示在它产生的噪声中。

另一个问题是您的哈希仅返回[0,1]中的梯度矢量,而它们应位于[−1,1]中以获取所有方向的梯度。该部分很容易通过重新映射来解决。

要解决这些问题,我切换了代码以使用此哈希函数(这是我从Mikkel Gjoel那里学到的,可能是由于WJJ Rey的论文):

vec2 hash(vec2 co) {
    float m = dot(co, vec2(12.9898, 78.233));
    return fract(vec2(sin(m),cos(m))* 43758.5453) * 2. - 1.;
}


请注意,由于使用了trig函数,它会比您的版本贵一些。但是,它可以大大改善所产生的噪声的外观:



评论


$ \ begingroup $
非常感谢您的解释。这也许是题外话,但我还是会问。在一些计算噪声的源代码中,人们使用向量vec3(1,57,113)来计算具有当前坐标的点积(我想目的也是为了获得哈希值)。为什么选择这种特定的常数(57以度为单位约1个弧度,133 =以度为单位约2 *弧度)?是否由于触发功能的周期性?我无法用谷歌搜索。
$ \ endgroup $
–萨拉斯瓦蒂
16年5月15日在18:55

$ \ begingroup $
@sarasvati我不太确定,但猜测是选择了57和113,因为它们是素数。 (113是质数; 57不是,但它是3 * 19,所以还是有点质素……如果是这样的话。)将质数乘以或乘积会混淆一些位,所以这并不罕见哈希中的成分。
$ \ endgroup $
–内森·里德(Nathan Reed)
16年5月15日在19:15

$ \ begingroup $
@cat我怀疑GLSL是否具有PRNG,因为GLSL程序是确定性的。
$ \ endgroup $
–user253751
16年5月15日在22:20

$ \ begingroup $
该注释线程中似乎有几个潜在的新问题...
$ \ endgroup $
– trichoplax
16年5月16日在0:22

$ \ begingroup $
我有那些工件,并且这个rand()函数修复了它。问题是,当我在地形上行走了2公里后,像OP一样的文物开始再次出现。它在此处使用哈希函数:amindforeverprogramming.blogspot.com/2013/07/…导致伪像消失(除了距离不远的100 km,不精确的公元前,但那没关系,我只需要拆分成块并得到通过对两个值进行哈希运算来工作,这将使perlin噪声几乎无限期地运行)。因此,我将在此处保留此内容,以帮助遇到相同问题的任何人。
$ \ endgroup $
–尼古拉斯·皮皮托尼
19-10-27在20:01