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

问题描述

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

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

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

谢谢各位

解决方法

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

但是,这两种情况都不是,因此噪声的实际最小值/最大值更为复杂。我过去曾在噪声上运行梯度上升,使用您正在查看的梯度集,以找到其真正的最大值。最大值略大于1,不在中心。乘以整个噪声(或等效地预乘表中的每个梯度)以校正输出范围的值为 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 度零件)

Un-domain-rotated 3D Perlin

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

Domain-rotated 3D Perlin

,

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