内容
- 前置知识
- 一维noise函数
- 二维noise函数
- 制作思路
- 代码
一维noise函数![(img-xsIXsB8G-1646966451620)(1dnose.png)]](https://i-blog.csdnimg.cn/blog_migrate/0fce201a9dda8c9674e9e1a89e2b9a50.png)
其
x
x
x的取值范围是负无穷到正无穷,且函数本身关于
y
y
y轴对称。返回值是一个
[
0
,
1
]
[0,1]
[0,1]之间的数。
需要注意的是,
[
0
,
1
]
[0,1]
[0,1]中的每个数出现概率并不相同,其结果类似于正态分布,越接近
0.5
0.5
0.5的数出现概率越大,越接近
0
,
1
0,1
0,1的数出现概率越低。
与random随机数的区别
randow随机数生成的数是均匀分布的,而noise随机数的生成值是接近正态分布的,且noise随机数的值是“确定“的,同一次运行中,调用 10 10 10次noise(233),每次的返回值都是相同的。
一些性质
- noise生成的随机数看起来比较“自然”。
- 连续取值时,间隔越小,生成的数起伏越小,间隔越大,生成的数起伏越大。
二维noise函数
如果把值当成高度,分的再细一点的话,就能得到类似于自然中群山的样子。
如果贴一个模型,再加上光影…
实际上,很多游戏中的山都是基于noise生成的。
noise函数的应用
noise函数得到的随机数,比较“自然”,所以基于它绘制的内容比较有特点。
那么这张图片是怎么生成的呢?
如果我们在二维noise上画一个圆,并且把得到的值当作一个新的圆的半径:
然后我们让在noise函数中的圆向右平移,并把得到的圆绘制在另一个图中,并且也向右平移…
最终就能得到这种图了。
代码-变量
float centerX, centerY, offsetX, offsetY, inc, r, rd;
int segNumber;
c
e
n
t
e
r
X
,
c
e
n
t
e
r
Y
centerX,centerY
centerX,centerY是在绘制图中,圆的中心坐标
o
f
f
s
e
t
X
,
o
f
f
s
e
t
Y
offsetX, offsetY
offsetX,offsetY是在noise函数图中,圆的坐标。
s
e
g
N
u
m
b
e
r
segNumber
segNumber把圆分成几个点
i
n
c
inc
inc是在noise函数图中圆的半径
r
,
r
d
r,rd
r,rd是在绘制图中圆的半径
代码-setup部分
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;
}
beginShape();
//通过vertex(x,y)函数画几个节点
endShape(CLOSE);
这个函数负责把在两个函数之间绘制的节点依次连接起来,从而形成一个封闭图形。
代码-怎么绘制一个圆
我们知道单位圆方程
x
2
+
y
2
=
1
x^2 + y^2=1
x2+y2=1
以及
c
o
s
2
(
α
)
+
s
i
n
2
(
α
)
=
1
cos^2(\alpha)+sin^2(\alpha)=1
cos2(α)+sin2(α)=1
我们借助
c
o
s
2
(
α
)
+
s
i
n
2
(
α
)
=
1
cos^2(\alpha)+sin^2(\alpha)=1
cos2(α)+sin2(α)=1这个方程,
对于每个点
(
c
o
s
(
α
)
,
s
i
n
(
α
)
)
(cos(\alpha),sin(\alpha))
(cos(α),sin(α)),它们都在
x
2
+
y
2
=
1
x^2 + y^2=1
x2+y2=1这个圆上。
所以我们枚举在 [ 0 , 2 π ] [0,2\pi] [0,2π]中枚举 α \alpha α,就得到了所有单位圆中点的坐标。然后我们把所有坐标都乘上一个数 i n c inc inc,就得到了任意半径的圆了。
代码-draw部分
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);
}
}
经过很多次尝试,我发现了最影响图形的的两个参数:
- i n c inc inc:即noise函数中圆的半径,这个很好理解,在noise中画的圆的大小越大,那么它所得到的值范围就越大,且起伏就越明显,绘制出来的图形棱角就比较多。相反, i n c inc inc值越小,画出来的图形就越"圆润"。
- o f f s e t offset offset:即在noise函数中每次平移的距离。值越小,noise值变化的就越小,表现出来的结果就是重叠效果越明显;值越大,noise变化就越大,表现出来的结果就是画的圆比较分散。
代码
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