棘手的柏林噪声问题。 Grad 函数如何使用归一化向量?

Tricky Perlin Noise Question. How does the Grad Function Use Normalized Vectors?

我目前正在了解改进的 Perlin 噪声。 我完全理解这个理论,但是,我对其常见实现的一个方面感到困惑,例如 this.

我的问题是,grad() 如何函数 return 归一化向量(梯度和方向)的点积?我的意思是归一化向量的点积的范围是 -1 到 1,这是将所有点积混合(淡化)在一起后 Perlin 噪声的正常输出。但是经过点积的向量没有归一化(none 的梯度函数也不是方向向量)。那么,输出如何落在-1到1的范围内呢?

我唯一的猜测是梯度向量的幅度都为根 2,方向向量的所有轴都在 -1 到 1 的范围内。所以,我假设这就是 Perlin 噪声最终输出的原因落在 -1 到 1 范围内。这是为什么?谁能证明或找到证据?

谢谢大家

the article you linked 中,grad() 函数 returns 两个向量的点积,但我不明白是什么让你说这些向量应该有单位大小.采样位置可以连续在立方体的任何地方。假设一个单位大小的立方体,到采样位置的距离向量的大小可以在 0 和 sqrt(3) 之间。所以,它看起来像||梯度向量|| = sqrt(2) 和 ||距离矢量|| ≤ sqrt(3),将 grad() 的输出限制在 −sqrt(6) 和 +sqrt(6) 之间(≈ 2.45)。

向量未归一化(它们的长度是 sqrt(2),如其他贡献者所述),并且噪声的总输出不是精确的 -1 到 1。如果向量 <1、1, 1> 并且所有符号排列都是可能的,那么我相信最大值就在每个立方体的中心。这将是 dot(grad, offsetFromVertex) = dot(<1, 1, 1>, <0.5, 0.5, 0.5>) = 1.5, /8 对于 0.5^3 在 3 个方向的每个方向上具有一半的插值权重, *8 因为有 8 个顶点所以它取消了。如果向量被归一化,并且它们可以指向每个立方体的中心,那么您将得到 dot(<1, 1, 1>/sqrt(3), <0.5, 0.5, 0.5>) = 1.5/sqrt(3 ) ≈ 0.8660254037844387.

但是,这两种情况都不是这种情况,因此噪声的实际 min/max 值更加复杂。我过去曾 运行 对噪声进行梯度上升,使用您正在查看的梯度集来找到其真正的最大值。最大值略大于 1,并且不在中心。将整个噪声乘以(或等效地预乘 table 中的每个梯度)以校正输出范围的值为 0.964921414852142333984375 .

顺便说一下,如果您还没有通过其他来源发现这一点:Perlin 很好学,但它会产生很多偏向基轴的偏差,并且其特征的角度分布变化不大。良好的 Simplex 类型噪声实现通常会产生更好的结果。如果您要使用 Perlin,我建议选择您的垂直(或时间,或未使用)方向,并在输入坐标上使用以下公式之一。您可以在分形求和之前执行此操作(效率更高),也可以将其放入函数定义的开头(更方便)。一旦你这样做了,它就很棒,并且在正确的情况下使用时看起来比一些 Simplex 类型的噪声实现更好。但请注意,即使您的用例只是 2D,您也需要始终为该技术使用 3D 噪声。

如果 Z 是垂直的、时间的或未使用的:

double xy = x + y;
double s2 = xy * -0.211324865405187;
z *= 0.577350269189626;
x += s2 - z;
y = y + s2 - z;
z += xy * 0.577350269189626;

如果 Y 是垂直的、时间的或未使用的:

double xz = x + z;
double s2 = xz * -0.211324865405187;
y *= 0.577350269189626;
x += s2 - y;
z = z + s2 - y;
y += xz * 0.577350269189626;

之前(很多 45 度和 90 度的零件)

之后(方向偏差基本上不可见)