- 文章作者:AI编写
- 发布时间:2021 年 11 月 1 日
介绍
perlin 是一个可以生成 Perlin 噪声的 npm 包。Perlin 噪声是一种用于生成连续的自然随机图案的算法,被广泛应用于生成自然风景、天空、水波等效果,也可以用于游戏场景的地形、草丛、树木等的生成。本教程将详细介绍 perlin 的使用方式和代码示例,并对其实现原理进行一定的解析,帮助读者深入了解 Perlin 噪声的生成过程。
安装使用
可以通过 npm 安装 perlin:
npm install perlin
或者通过 yarn 安装:
yarn add perlin
在代码中导入 perlin 并使用:
-- -------------------- ---- ------- ------ - ----- - ---- --------- -------- --------------- -- - --- ------- - --- --- --------- - ---- ------- - - -- - - ----- ---- - --- - - ------- - ----- -- -- - ---------- ---------------- - ------ -------- -
函数参数
Perlin 噪声的生成函数为 noise
,它接受三个参数:
noise(x: number, y: number, z: number): number
x
,y
,z
:输入的三个数值,对应于三维空间中的一点的坐标。如果省略y
和z
,则生成二维的噪声。
函数返回的是一个范围在 0 到 1 之间的数值,表示这个坐标点的噪声值。
随机性的实现思路
Perlin 噪声的实现过程基于一多维插值函数(interpolation)和一些列随机梯度向量。其实现步骤如下:
先将输入的坐标点通过一定的方式映射到一个格子中。
对每个格子,生成一个向量,表示这个点上的随机梯度向量。
对于输入的坐标点,先找到它所在的网格顶点,然后计算这个顶点到输入点的距离,从而确定插值中所用的“位置参数”。
将输入点周围的四个顶点与它所在的可以形成“单元”的四个点进行插值运算,得到一个范围在 0 到 1 之间的值。
将这些值按照规定的方式结合在一起,得到最终的 Perlin 噪声值。
下面我们将对这些步骤逐一进行解释。
映射到格子
我们需要将输入的坐标点映射到一个“格”(cell)中,这个格子的大小是根据打算生成的场景而定的,通常是一个整数。
例如,如果我们打算生成一个 100x100 的地形场景,那么我们可以将每个点映射为 $(i, j)$ 的二元组,其中 i 和 j 分别是该点所处的格子的坐标。这时候,输入的坐标点 $(x, y)$ 应当被映射为 $(i, j)$,其中:
i = Math.floor(x / cellSize); j = Math.floor(y / cellSize);
cellSize
就是格子的大小,一般是一个整数。这样做的好处是可以显著地提高计算速度。
随机梯度向量
对于每个顶点,需要生成一个随机梯度向量。这个向量实际上是用一个随机生成器生成的,Perlin 噪声使用的是 1D/2D/3D 梯形噪声(improved Perlin noise)的变种之一。我们这里不对梯形噪声的生成过程作详细介绍。唯一需要指出的是,这些向量必须随机分布,并且方向、模长(长度)都应该随机。这里给出一个 JavaScript 代码,用来生成一个在半径为 radius
的球体上随机分布的向量。
-- -------------------- ---- ------- -------- ---------------------------- - --- -- -- -- -- - - - -------------- - - - --- - - -------------- - - - --- - - -------------- - - - --- - ----- -- - - - - - - - - - - - - -- - - - - - - - - - - - - --------- --- ---- - ------ - ----------- - - - - - - - - - --- ------ - - - ----- - - ----- - - ---- -- -
插值运算
假定我们已经生成了每个顶点上的随机梯度向量,则对于任意一个输入的坐标点 $(x, y)$,我们需要找到在它周围的四个顶点以及与它相邻的四个顶点(如下图),并计算这些点之间的插值。
假定 $(x_i, y_j)$ 是输入的坐标点,$(xi_L, y_j)$、$(xi_R, y_j)$、$(Xi, y_j)$、$(xi, y_j)$ 是周围的四个与之相邻的顶点,水平方向的距离分别为 $dx_L, dx_R, dx_i, dx$。
那么,我们可以采用线性、平方或者立方(cubic)插值来计算 $(x_i, y_j)$ 在这个“单元”内的值。为了简化起见,我们这里只使用线性插值:
-- -------------------- ---- ------- -------- -------------- -- -- - ------ -- - -- - - - - - -- - -------- ---------------- ---- --- --- --- -- - ----- - - --- - --- - --- - ---- ----- - - --- - --- - -- ----- - - -- - --- ----- - - --- ------ - - - - - - - - - - - - - - - - - - -- - -------- ------- ---- --- -- -- - ----- -- - - - --- ----- -- - - - --- ----- ------ - ---------- ---- ----- ------ - --------- - -- ---- ----- ------ - ---------- -- - --- ----- ------ - --------- - -- -- - --- ----- ------ - ---------- -- - -- --- ----- ------ - --------- - -- -- - -- --- ----- ------ - ---------- --- --- ----- ------ - --------- - -- --- --- ----- ------ - ---------- -- - -- --- ----- ------ - --------- - -- -- - -- --- ----- ------ - ---------- --- -- --- ----- ------ - --------- - -- --- -- --- ----- ------ - ---------- -- - -- -- --- ----- ------ - --------- - -- -- - -- -- --- ----- ------ - ---------- --- -- --- ----- ------ - --------- - -- --- -- --- ----- ------- - ---------- -- - -- -- --- ----- ------- - --------- - -- -- - -- -- --- ----- -- - ------------------- ------- ---- ----- -- - ------------------- ------- ---- ----- -- - ------------------- ------- ---- ----- -- - ------------------- ------- ---- ----- -- - --------------- --- ---- ----- -- - --------------- --- ---- ----- ----- - --------------- --- ---------------------------- ----- ------ ----------------- ------- ------- ------- ------- ---------------------------- --- - - -- - ------ - ----------------- ------- ------- ------- ------- ---------------------------- --- --- -
我们输入了一个“单元”内四个顶点的值,和输入点 $(x_i, y_j)$ 到左上角顶点 $(xi_L, y_j)$ 的距离,这个函数会返回按照线性插值计算出的结果。
总结
本文对 Perlin 噪声的生成过程进行了简单的介绍,并且给出了一个使用 npm 包 perlin 的代码样例,这个代码可以用来生成一维或者二维的自然风景、天空、水波等效果,还可以用于游戏场景的地形、草丛、树木等的生成。由于光是一个简单的代码引擎不足以帮助开发者理解 Perlin 噪声算法的工作原理,因此我们在本教程中也介绍了有关 Perlin 噪声算法的一些基础理论。我们希望这些介绍能够有所帮助,启发您实现更好的游戏场景或自然景观。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/5eeda79ccebd9a1b02fbaadb