Perlin Noise 柏林噪音烟雾模拟,基于 p5.js 的实现

最后更新于 2023-05-26

本次教程是一个基于 perlin noise 的烟雾模拟,最核心的部分是基于 perlin noise 来生成不规则的形状,然后让该图形在画布上不停地移动位置,并绘制,当然颜色也是一个非常关键的因素。

## 画一个圆

故事是从一个圆开始的,画一个圆非常简单,我们已经画了数不清的圆了,对吧。

基于 p5.js 的内置函数 circle,可以轻松地画出一个圆,需要注意的是第三个参数是直径。

## 给圆加点料

现在画板上已经有一个圆了,只是看起来很单调,没有颜色,接下来需要给圆形设置颜色,让其看起来更亮丽一点。

## 让圆形动起来

之前的步骤里,圆形绘制的位置是写死的 (width / 2, height / 2) 点,即绘制在画板的中心。为了让圆形动起来,在每一次绘制的时候,改变圆形的位置即可。

这里引入一个变量 xoff,代表横坐标的位置,通过对横坐标 xoff 进行增加,即可实现圆形横向移动效果。当然也可以再加入一个 yoff 变量,对纵坐标做相应的修改。

## 绘制不规则的图形

现在展现在画板上的是一个从左向右不停移动的圆形,如何基于圆形来生成不规则的图形呢,这里就是柏林噪音发挥作用的地方了。

### 基于圆周运动来画圆

通过圆周运动的规律,我们绘制了一些在圆上的点,当绘制的点越来越多时,就拟合成了一个圆形。

### 使用柏林噪声来对圆上的点做随机变化

针对圆上的每一个点,我们计算出它的柏林噪声值,就会得到一个更随机的点,再将这些随机的点连起来,就是一个不规则的图形了。

红色图形是原来的基本圆形,而白色的图形则是经过柏林噪声生成的不规则图形,可以点击运行看看生成的不同形状的图形。

下面来重点介绍一下柏林噪声的运用代码:

  1. for (let i = 0; i < Math.PI * 2; i += 0.2) {

    我们遍历角度 0 到角度 Math.PI * 2,计算出以 (width / 2, height / 2) 为圆心,50 为半径的圆上的点坐标。

  2. 基于圆周运动和三角公式,进行具体的点横坐标 x 和纵坐标 y 的计算,详细介绍可以参考如何让点围绕圆心做圆周运动

    1
    2
    
    let x = width / 2 + 50 * cos(i)
    let y = height / 2 + 50 * sin(i)
  3. const noiseVal = map(noise(x * 0.001, y * 0.001), 0, 1, 0, Math.PI * 2)

    计算出每个点 (x, y) 所对应的柏林噪声值,噪声值的区间为 0 到 1,然后使用 map 函数把该噪声值映射到 0 到 Math.PI * 2 之间的角度

  4. 基于噪声值转换而来的角度,对每个点的半径进行调整,从而得到不同的圆半径,基于不同的圆半径生成新的点。

    1
    2
    3
    4
    5
    
    const xRadius = 50 * cos(noiseVal)
    const yRadius = 50 * sin(noiseVal)
    
    x = width / 2 + xRadius * cos(i)
    y = height / 2 + yRadius * sin(i)

连接生成的这些点,就得到一个不规则的图形了。

### 不规则图形的效果

p5.js 提供了 beginShape、vertex、 endShape 三个函数来实现连点成线的功能,来看看如何使用。

如上面示例所示,一个完整的不规则图形就已经显示出来了。

beginShape 表示开始绘制一个图形,vertex 表示添加一个点到图形中,endShape 表示结束绘制一个图形, endShape 可以传递一个 CLOSE 的参数,意思是让对这个图形进行颜色的填充。在本例中,我们在开始调用了 noFill,所以这里没有看到填充的效果。

## 整合在一起

有了不规则的图形,接下来只需要把前面的圆形换成我们的不规则图形即可。

## 更进一步

本次教程,我们基于柏林噪音和基础的圆形实现了一个烟雾模拟的效果。

接下来,你可以做更多的尝试,比如下面一些可能的点:

  1. 调整柏林噪音的生成规则,和一些数值的修改,看看是不是有惊喜和意外发生。
  2. 将 noFill 去掉,加上图形背景颜色,看看会发生什么效果。

你可以阅读这篇规律之美,圆的文章,进一步了解圆形的使用。