我正在研究一些针对相干噪声的各种实现(我知道有一些库,但这主要是为了我自己的启发和好奇心)以及如何使用它,我对原始的 Perlin 噪声有一个问题.
根据这个经常链接的数学常见问题解答,输出范围将介于-1
和之间1
,但我不明白该值是如何在该范围内的。
据我了解,算法基本上是这样的:每个网格点都有一个相关的随机梯度向量 length 1
。然后,对于每个点,对于所有四个周围的网格点,计算随机梯度和从该网格点出发的向量的点积。然后,您使用精美的缓动曲线和线性插值将其降低到一个值。
但是,这是我的问题:这些点积有时会超出范围[-1, 1]
,并且由于您最终在点积之间进行线性插值,这是否意味着最终值有时会超出范围的范围[-1, 1]
?
例如,假设其中一个随机向量是(sqrt(2)/2, sqrt(2)/2)
(长度为 1)和(0.8, 0.8)
(在单位平方中),您得到的结果大致为1.131
。如果在线性插值中使用该值,则生成的值完全有可能大于1
. 而且,确实,在我的直接实施中,这种情况经常发生。
我在这里错过了什么吗?
作为参考,这是我的 Java 代码。Vec
是一个简单的类来做简单的 2d 矢量算术,fade()
是缓动曲线,lerp()
是线性插值,并gradient(x, y)
为您提供该网格点的梯度作为Vec
. 该gridSize
变量以像素为单位为您提供网格的大小(它的类型为 double):
public double getPoint(int x, int y) {
Vec p = new Vec(x / gridSize, y / gridSize);
Vec d = new Vec(Math.floor(p.x), Math.floor(p.y));
int x0 = (int)d.x,
y0 = (int)d.x;
double d00 = gradient(x0 , y0 ).dot(p.sub(x0 , y0 )),
d01 = gradient(x0 , y0 + 1).dot(p.sub(x0 , y0 + 1)),
d10 = gradient(x0 + 1, y0 ).dot(p.sub(x0 + 1, y0 )),
d11 = gradient(x0 + 1, y0 + 1).dot(p.sub(x0 + 1, y0 + 1));
double fadeX = fade(p.x - d.x),
fadeY = fade(p.y - d.y);
double i1 = lerp(fadeX, d00, d10),
i2 = lerp(fadeX, d01, d11);
return lerp(fadeY, i1, i2);
}
编辑:这是生成随机渐变的代码:
double theta = gen.nextDouble() * 2 * Math.PI;
gradients[i] = new Vec(Math.cos(theta), Math.sin(theta));
gen
一个在哪里java.util.Random
。