用代码描述自然系统-使用柏林噪声生成平滑随机数
本篇博文介绍使用粒子系统和柏林噪声,构造基于平滑随机数的粒子游走模型。
柏林噪声
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 角放大,就可以得到一个新的封闭图形,这将是一个流动的画报,可以 点击这里 查看示例。