首页 > 解决方案 > 棘手的柏林噪声问题。Grad 函数如何使用归一化向量?

问题描述

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

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

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

多谢你们

标签: mathvectornoise

解决方案


向量没有被归一化(它们的长度是 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。

但是,这两种情况都不是这样,因此噪声的实际最小/最大值更加复杂。过去,我使用您正在查看的梯度集对噪声进行梯度上升,以找到其真正的最大值。最大值略大于 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 度零件)

非域旋转 3D Perlin

之后(方向偏差在很大程度上是不可见的)

域旋转的 3D Perlin


推荐阅读