分形布朗运动:一层噪声不够,就叠八层
Fractional Brownian Motion
先回到波
「噪声」这个词在音乐、通信、宇宙学里意思各不相同。书里先退一步,回到最基本的波:一条正弦波有两个参数,振幅(多高)和频率(多密)。
让振幅随时间变,叫调幅 (AM);让频率随时间变,叫调频 (FM)。几条波还可以叠加:不同振幅、不同频率的正弦加在一起,形状会大变,有的地方互相抵消,有的地方互相增强。
直接改上面的表达式就能重画:x 是 0 到 1 的横坐标,可以用 sin、pow、smoothstep 等函数。
音乐里,音高按八度 (octave) 组织:高一个八度,频率翻一倍。噪声也可以这样叠。单独一层 Perlin 噪声的频率比较集中,振幅也比较稳定,但又不像正弦那么规则。所以只要叠少数几层,结果就已经很像随机了;要用正弦去伪装随机,往往得叠上一大堆。
fBm 的配方
分形布朗运动 (fractional Brownian motion,简称 fBm),也叫分形噪声,就是一个循环:
- 从一层低频、大振幅的噪声开始;
- 每叠一层,频率乘以空隙度 (lacunarity),通常是 2;
- 振幅乘以增益 (gain),通常是 0.5。
下面这个绘图器把层数、空隙度和增益都做成了滑块。把层数从 1 慢慢加到 10:
直接改上面的表达式就能重画:x 是 0 到 1 的横坐标,可以用 sin、pow、smoothstep 等函数。
二维:地形、云和石头
二维的 fBm 也是同样的循环,只是把一维噪声换成二维噪声。它常用来生成程序化地形,因为真实的地貌经过侵蚀,在很多尺度上都是自相似的:远看是山脉,近看是山坡上的沟壑。
fBm 还有几个常见的「家族成员」,区别只在每一层叠上去之前怎么处理那一层噪声:
- 湍流 (turbulence):先对有符号的噪声取绝对值,再按 fBm 叠。噪声穿过 0 的地方都变成了尖锐的谷。
- 山脊 (ridge):把湍流的尖谷翻上来,
n = offset - abs(n),再平方让脊更锐利。 - 还可以让各层相乘,或者让后一层的缩放依赖前一层的结果。这样就离开了严格的分形定义,进入了多重分形 (multifractal),在商业地形软件里很常见。
也可以直接改右边的代码:停手约 0.3 秒会自动重新运行;改坏了点「还原代码」。
域扭曲:用噪声扭曲噪声
最后一招最有意思:不直接看 fBm 的值,而是用一层 fBm 去推开另一层 fBm 的采样坐标。Íñigo Quilez 写过一篇文章讲这件事,像是「梦中梦」:
vec2 q = vec2(fbm(st), fbm(st + 偏移1)); // 第一层:一个偏移向量
vec2 r = vec2(fbm(st + k * q + 偏移2), fbm(st + k * q + 偏移3)); // 用 q 推开坐标,再算一层
float f = fbm(st + k * r); // 用 r 推开坐标,得到最终的值
温和地扭曲,能得到像云、像大理石一样的纹理,而且依然保留自相似:
也可以直接改右边的代码:停手约 0.3 秒会自动重新运行;改坏了点「还原代码」。
除了用噪声的值,也可以用噪声的导数(解析梯度或有限差分)去推开坐标。Perlin 和 Neyret 的 flow noise 就建立在梯度的思路上;现代的一些 Perlin 噪声实现可以同时返回值和解析梯度。
在游戏里怎么用
取舍与常见的坑
小结与练习
- fBm = 一层层叠噪声:频率按空隙度升高,振幅按增益衰减;叠几层就有了跨尺度的自相似细节。
- 湍流取绝对值得到尖谷,山脊再翻转平方得到锐脊;让各层相乘就进入了多重分形。
- 域扭曲用 fBm 推开另一层 fBm 的坐标,做出流动的云和大理石。
练习:用 fBm 做一张俯视的岛屿地图:fBm 的值低于某个阈值是海,稍高一点是沙滩,再高是草地,最高处用山脊噪声画出山脉。
分形布朗运动 (fBm) / 分形噪声:把多「八度 (octave)」噪声叠加——频率按空隙度 (lacunarity) 步进升高,振幅按增益 (gain) 衰减——得到跨尺度自相似细节。变体包括湍流(绝对值尖谷)、脊状噪声、乘性/多重分形,以及用噪声扭曲采样坐标的域扭曲 (domain warping)。
从波到噪声叠加
噪声一词在音乐、通信、宇宙学里含义各异;BoS 先回到波的振幅与频率。一维正弦可调参;用塑形函数让振幅/频率随时间变,即 AM / FM。波可叠加(叠加原理):多路不同振幅频率的正弦相加,外观大变——可对消或相长。
音乐中音高与频率按八度(频率加倍/减半)组织。Perlin 噪声单层的「中心频率」较窄、振幅相对稳定,但不如正弦那么规则;叠少层噪声就足以显得随机,而要用正弦伪装随机往往需要很多谐波。
fBm 的标准配方
依次增加迭代次数(octave),频率按 lacunarity 升高,振幅按 gain 降低:
- 八度从 1→2→4→8→10:曲线细节变密,并出现自相似——放大局部仍像整体;
- 真数学分形要无限项;图形有像素分辨率下限,有限项即可「看起来像分形」。
二维同理,常用于程序化地貌:侵蚀在多尺度上自相似。进阶阅读:Íñigo Quilez 论高级噪声;Musgrave《Texturing and Modeling: a Procedural Approach》第 3 版第 16 章(地形;勿买缺地形内容的第 1 版 PDF)。
家族成员
湍流 (turbulence):对有符号噪声取绝对值再按 fBm 叠,形成尖锐谷:
value += amplitude * abs(snoise(st));
st *= 2.;
amplitude *= .5;
脊 (ridge):把尖谷翻上来再平方锐化:
n = abs(n);
n = offset - n;
n = n * n;
还可把各层相乘,或让后层缩放依赖前层结果——离开严格分形定义,进入多重分形 (multifractal);商业地形软件很常见。
域扭曲
用一层 fBm 去扭曲另一层 fBm 的采样域(Quilez「梦中梦」式文章)。温和用法可做出云状纹理且仍带自相似。亦可用噪声导数(解析梯度或有限差分)排开坐标;Perlin & Neyret 的 flow noise 即建立在梯度思想上。现代 Perlin 实现有时可同时返回值与解析梯度。
在游戏开发中的意义
- 高度图、洞穴、云层密度、风噪声相位;
- 参数:八度换细节与成本;lacunarity/gain 换粗糙度;湍流/脊换视觉风格;
- 与 地形渲染、天空与云渲染 衔接;运行时多层噪声贵时预烘焙或 LOD 减层。
工具箱:LYGIA generative。
原书问题
- ch.13 两处将 Íñigo Quilez 写作「Inigo Quiles」(缺 z);域名仍为 iquilezles.org。本页按正确拼写引用。