我读过一些关于perlin噪声的文章,但每一篇文章似乎都有自己的实现方式:
-
在本文中,梯度函数返回一个双值。
-
在本文中,梯度被生成为3D向量。
-
在本文中,生成了随机梯度矢量的静态256阵列,并使用排列表选择了一个随机梯度矢量,然后讨论了球形梯度的更复杂的细节。
这些只是我看到的几篇文章。对于同一算法的所有这些变体,我应该使用哪一个,或者哪一个适用于什么目的?
我已经用每种技术生成了地形和高度图,它们各自的输出在各自的方式上大不相同,我不知道我做得是否正确,因为我不知道在输出中寻找什么(因为最后只是随机值)
我只是在寻找一些关于何时使用的上下文,所以任何见解都将是非常有用的
实现同一算法有多种方法,有些比其他方法更快或更慢,有些更容易或更难理解。Ken Perlin的原始实现单看它就很难理解。所以你链接的一些文章(包括我写的#2,耶!),试着简化实现,让它更容易理解。
但最终,它的算法完全相同:
- 输入,计算包含输入点的正方形(对于2D Perlin噪波,或立方体,如果使用3D版本)的4个角的坐标
- 为所有4个值计算一个随机值(首先为每个值分配一个随机梯度向量(2D中有4种可能性:(+1,+1)、(-1,+1),(-1,-1)和(+1,-1)),然后计算该随机梯度向量与从正方形角到输入点的向量之间的点积)
- 最后,在这4个随机值之间平滑插值,得到最终值
在文章#1中,grad函数直接返回点积,而在文章#2中,创建了向量对象,并调用了点积函数来明确正在执行的操作(这可能比其他实现慢一点,因为每次运行算法时都会创建并短暂使用大量向量对象)。
两个实现是否会生成相同的地形/高度图取决于它们是否为正方形/立方体的每个角生成相同的随机值(点积的结果)。如果两种算法为网格上的每个整定点(所有可能的正方形/立方体的所有角点)生成相同的随机值,那么它们将产生相同的结果。Ken Perlin的原始实现和这3篇文章都使用一个整数数组为每个角生成一个随机梯度向量(从4个可能的选择中选择)来计算点积。所以在理论上,如果数组是相同的,那么它们应该会产生相同的结果。(除非某些实现使用另一种方法来生成随机向量。)
我真的不确定这是否能回答你的问题,所以不要犹豫,可以问其他问题:)
编辑:
通常,您不会单独使用Perlin噪波。因此,对于您想要的每个最终值(例如,高度贴图纹理中的单个像素),您将多次调用噪波函数(八度)。例如:
float finalValue = 0.0f;
float amplitude = 1.0f;
float frequency = 1.0f;
int octaveCount = 8;
for (int octave = 0; octave < octaveCount; ++octave) {
finalValue += amplitude * noise(x * frequency, y * frequency, z * frequency);
amplitude *= 0.5f;
frequency *= 2.0f;
}
// Do something fun with 'finalValue'
频率、振幅和八度音阶数是最常见的参数,可以用来产生不同的值。
比如说,如果你正在生成一个地形,你会想要很多八度音阶。第一个将产生山脉的粗略形状,因此您需要高振幅(示例代码中为1.0)和低频(上述代码中也是1.0)。但仅仅是这个八度音阶就可以得到非常平滑的地形,没有任何细节。对于这些小细节,你会想要更多的八度音阶,但频率更高(因此在输入(x,y,z)的相同范围内,你会有更多的Perlin噪声值的起伏),振幅更低(你想要小细节,因为如果你要保持与第一个八度音阶相同的振幅(在示例代码中为1.0),会有很多起伏,非常接近,非常高,这会导致一个非常粗糙的山(想象一下,你每走几米就会有100米80度的落差和斜坡)
您可以使用这些参数来获得不同的结果。还有一种叫做";域扭曲";或";扭曲噪声";你可以抬头看看。基本上,您可以调用噪波函数作为噪波函数的输入。喜欢而不是调用:
float result = noise(x, y, z);
你可以称之为:
// The numbers used are arbitrary values, you can just play around until you get something cool
float result = noise(noise(x * 1.7), 0.5 * noise(y * 4.1), noise(z * 2.3));
这可以产生非常有趣的结果