基于Processing的noise随机数做出炫酷的图片


可以做出很多类似这种的图片

内容

  • 前置知识
    • 一维noise函数
    • 二维noise函数
  • 制作思路
  • 代码

一维noise函数

其 $x$ 的取值范围是负无穷到正无穷,且函数本身关于 $y$ 轴对称。返回值是一个 $[0,1]$ 之间的数。需要注意的是,$[0,1]$ 中的每个数出现概率并不相同,其结果类似于正态分布,越接近 $0.5$ 的数出现概率越大,越接近 $0$ 或 $1$ 的数出现概率越低。

与random随机数的区别

random随机数生成的数是均匀分布的,而noise随机数的生成值是接近正态分布的,且noise随机数的值是”确定”的,同一次运行中,调用 $10$ 次 noise(233),每次的返回值都是相同的。

一些性质

  • noise生成的随机数看起来比较”自然”。
  • 连续取值时,间隔越小,生成的数起伏越小,间隔越大,生成的数起伏越大。

二维noise函数

在这里插入图片描述


在这里插入图片描述

如果把值当成高度,分的再细一点的话,就能得到类似于自然中群山的样子。

在这里插入图片描述

如果贴一个模型,再加上光影……实际上,很多游戏中的山都是基于noise生成的。

在这里插入图片描述

noise函数的应用

noise函数得到的随机数,比较”自然”,所以基于它绘制的内容比较有特点。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

那么这张图片是怎么生成的呢?

如果我们在二维noise上画一个圆,并且把得到的值当作一个新的圆的半径:

在这里插入图片描述

然后我们让在noise函数中的圆向右平移,并把得到的圆绘制在另一个图中,并且也向右平移……

最终就能得到这种图了。

代码-变量
1
2
float centerX, centerY, offsetX, offsetY, inc, r, rd;
int segNumber;
  • centerX, centerY:在绘制图中,圆的中心坐标
  • offsetX, offsetY:在noise函数图中,圆的坐标
  • segNumber:把圆分成几个点
  • inc:在noise函数图中圆的半径
  • r, rd:在绘制图中圆的半径
代码-setup部分
1
2
3
4
5
6
7
8
9
10
11
12
void setup() 
{
size(1920, 1080);
background(0);
noFill();
colorMode(HSB);
centerX = 0; centerY = height / 2;
offsetX = offsetY = 0;
inc = 0.725;
segNumber = 500;
r = 0; rd = 350;
}
1
2
3
beginShape();
//通过vertex(x,y)函数画几个节点
endShape(CLOSE);

这个函数负责把在两个函数之间绘制的节点依次连接起来,从而形成一个封闭图形。

代码-怎么绘制一个圆

我们知道单位圆方程 $x^2 + y^2 = 1$,以及 $\cos^2(\alpha)+\sin^2(\alpha)=1$。

我们借助 $\cos^2(\alpha)+\sin^2(\alpha)=1$ 这个方程,对于每个点 $(\cos(\alpha), \sin(\alpha))$,它们都在 $x^2 + y^2 = 1$ 这个圆上。

所以我们在 $[0, 2\pi]$ 中枚举 $\alpha$,就得到了所有单位圆中点的坐标。然后我们把所有坐标都乘上一个数 inc,就得到了任意半径的圆了。

代码-draw部分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void draw() 
{
stroke((frameCount * 0.05) % 255, 180, 255, 64);
beginShape();//画圆
for(int i = 0; i < segNumber; i++) {
float angel = TWO_PI * i / segNumber;
PVector p = new PVector(cos(angel), sin(angel));
float radius = r + rd * noise(offsetX + p.x * inc, offsetY + p.y * inc);
p.mult(radius);
vertex(p.x + centerX, p.y + centerY);
}
endShape(CLOSE);
float offset = 0.00385;//平移
offsetX += offset; offsetY += offset;
centerX += 1;
if(centerX > width) {
centerX = 0;
background(0);
}
}

经过很多次尝试,我发现了最影响图形的两个参数:

  • inc:即noise函数中圆的半径,这个很好理解,在noise中画的圆的大小越大,那么它所得到的值范围就越大,且起伏就越明显,绘制出来的图形棱角就比较多。相反,inc 值越小,画出来的图形就越”圆润”。
  • offset:即在noise函数中每次平移的距离。值越小,noise值变化的就越小,表现出来的结果就是重叠效果越明显;值越大,noise变化就越大,表现出来的结果就是画的圆比较分散。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
float centerX, centerY, offsetX, offsetY, inc, r, rd;
int segNumber;

void setup()
{
size(1920, 1080);
background(0);
noFill();
colorMode(HSB);
centerX = 0; centerY = height / 2;
offsetX = offsetY = 0;
inc = 1;
segNumber = 500;
r = 0; rd = 350;
}

void draw()
{
stroke((frameCount * 0.05) % 255, 180, 255, 64);
beginShape();
for(int i = 0; i < segNumber; i++) {
float angel = TWO_PI * i / segNumber;
PVector p = new PVector(cos(angel), sin(angel));
float radius = r + rd * noise(offsetX + p.x * inc, offsetY + p.y * inc);
p.mult(radius);
vertex(p.x + centerX, p.y + centerY);
}
endShape(CLOSE);
float offset = 0.006;
offsetX += offset; offsetY += offset;
centerX += 1;
if(centerX > width) {
centerX = 0;
background(0);
}
}

参考内容:

https://www.bilibili.com/video/BV1BA411i7t6


Author: BY 水蓝
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source BY 水蓝 !
  TOC