|

用代码描述自然系统-使用柏林噪声生成平滑随机数

本篇博文介绍使用粒子系统和柏林噪声,构造基于平滑随机数的粒子游走模型。

柏林噪声

Perlin 噪声 (Perlin noise) 指由 Ken Perlin 发明的自然噪声生成算法,该算法可以产生比较平滑的随机数,即下一次的随机值基于上一次的随机结果产生,所以柏林噪声被被大量用于生成模拟自然系统的场景。

柏林噪声的基本介绍参考知乎 [Nature of Code] 柏林噪声,以下介绍节选自该文章:

噪声(Noise)实际上就是一个随机数生成器,当然,这是一种伪随机。柏林噪声基于随机,并在此基础上利用缓动曲线进行平滑插值,使得最终得到噪声效果更加趋于自然。基于不同的采样空间,柏林噪声可以分为一维、二维和三维。维度不同,但其基本原理是相同,都主要经过以下三个步骤:

  • 初始化相关数据,包括排列表(Permutation Table)和梯度表(Gradient Table)等;
  • 建立采样空间。对于一维柏林噪声,采样空间为一个一维的坐标轴,轴上整数坐标位置均有一个点。而对应二维柏林噪声,采样空间为一个二维坐标系,坐标系中横纵坐标为整数的地方均有一点,三维柏林噪声同理;
  • 对于不同类型的噪声,对采样点在不同空间中,根据最近的参考点的梯度和缓动曲线进行插值计算;

本篇博文主要使用二维噪声。

p5 中提供了生成柏林噪声的 noise 函数,函数原型:

noise(x, [y], [z])
参数 类型 描述
x 数字 噪声空间的 x 坐标
y 数字 噪声空间的 y 坐标
z 数字 噪声空间的 z 坐标

返回值是一个浮点数字,介于 0 到 1 之间。

基于粒子系统的随机游走模型

随意游走模型其实是最容易实现的模型,使用粒子系统可以增强模型的表现,再加上柏林噪声,可以说更是强强结合,可以让模型有更优秀的表现。

本篇博文使用的例子系统与前文的没有什么区别,这也可以看出,一个基本粒子系统知识定义了粒子对受力的响应,而如何施加受力,不同的系统可以有不同的规则。

在我们即将实现的粒子游走模型系统中,我们使用二维柏林噪声产生一个平滑随机数,然后使用极坐标方程将这个随机值转换成向量,最后将向量转化为受力,施加到粒子上。

先看最终的实现效果:

最终的效果如封面所示,可以 点击这里 查看完整示例。

粒子系统的生成:

// ...
const count = 300;
// ...
function setup() {
  createCanvas(PWidth, PHeight);
  background(21, 8, 50);
  for (let i = 0; i < count; i++) {
    const particle = new Particle(random(1, 4));
    particle.setVelocity(createVector(0, 0));
    // 随机颜色
    particle.setColor(color(255, random(255), random(255), 200));
    particles.push(particle);
  }
}
// ...

我们的 draw 函数实现如下(Particle 类省略):

// ...
const scale = 200;
// ...
function draw() {
  particles.forEach(particle => {
    // 使用 noise 函数生成 theta 角
    const theta = noise(particle.position.x / scale, particle.position.y / scale) * TWO_PI;
    // 将 theta 转换为 x, y 坐标
    const x = cos(theta);
    const y = sin(theta);
    // 使用 x, y 生成受力
    particle.addForce(createVector(x, y));
    particle.update();
    particle.display();
  });
}

如果将 theta 角放大,就可以得到一个新的封闭图形,这将是一个流动的画报,可以 点击这里 查看示例。

类似文章