中EN
精修课概念页

分形布朗运动:一层噪声不够,就叠八层

Fractional Brownian Motion

更新于 2026-10-15 约 18 分钟fBm分形噪声湍流域扭曲GLSL

先回到波

「噪声」这个词在音乐、通信、宇宙学里意思各不相同。书里先退一步,回到最基本的波:一条正弦波有两个参数,振幅(多高)和频率(多密)。

让振幅随时间变,叫调幅 (AM);让频率随时间变,叫调频 (FM)。几条波还可以叠加:不同振幅、不同频率的正弦加在一起,形状会大变,有的地方互相抵消,有的地方互相增强。

振幅、频率与叠加

直接改上面的表达式就能重画:x 是 0 到 1 的横坐标,可以用 sin、pow、smoothstep 等函数。

依次是:一条正弦;调幅,振幅随时间变;调频,频率随时间变;两条不同频率的正弦叠加。

音乐里,音高按八度 (octave) 组织:高一个八度,频率翻一倍。噪声也可以这样叠。单独一层 Perlin 噪声的频率比较集中,振幅也比较稳定,但又不像正弦那么规则。所以只要叠少数几层,结果就已经很像随机了;要用正弦去伪装随机,往往得叠上一大堆。

fBm 的配方

分形布朗运动 (fractional Brownian motion,简称 fBm),也叫分形噪声,就是一个循环:

  1. 从一层低频、大振幅的噪声开始;
  2. 每叠一层,频率乘以空隙度 (lacunarity),通常是 2;
  3. 振幅乘以增益 (gain),通常是 0.5。
第 1 层×1第 2 层×2第 3 层×4第 4 层×8加起来
每往下一层,频率翻倍、振幅减半。最下面是四层加起来的结果:大的起伏还在,上面又长出了一层层越来越细的小起伏。

下面这个绘图器把层数、空隙度和增益都做成了滑块。把层数从 1 慢慢加到 10:

一维 fBm

直接改上面的表达式就能重画:x 是 0 到 1 的横坐标,可以用 sin、pow、smoothstep 等函数。

层数越多,细节越密;增益越大,细小的起伏越明显,曲线就越「毛」。

二维:地形、云和石头

二维的 fBm 也是同样的循环,只是把一维噪声换成二维噪声。它常用来生成程序化地形,因为真实的地貌经过侵蚀,在很多尺度上都是自相似的:远看是山脉,近看是山坡上的沟壑。

fBm 还有几个常见的「家族成员」,区别只在每一层叠上去之前怎么处理那一层噪声:

原始噪声 nabs(n):湍流(0.6 − |n|)²:脊
同一段以 0 为中心的噪声 n。取绝对值后,原来穿过 0 的地方都变成了尖尖的谷,这就是湍流;再用一个偏移量减去它、平方,谷就翻成了锐利的山脊。
  • 湍流 (turbulence):先对有符号的噪声取绝对值,再按 fBm 叠。噪声穿过 0 的地方都变成了尖锐的谷。
  • 山脊 (ridge):把湍流的尖谷翻上来,n = offset - abs(n),再平方让脊更锐利。
  • 还可以让各层相乘,或者让后一层的缩放依赖前一层的结果。这样就离开了严格的分形定义,进入了多重分形 (multifractal),在商业地形软件里很常见。
fBm、湍流和山脊0.0s
改一改

也可以直接改右边的代码:停手约 0.3 秒会自动重新运行;改坏了点「还原代码」。

模式 0 是普通 fBm,像云;1 是湍流,暗色的谷连成网;2 是山脊,亮色的脊像闪电或山脉的分水岭。

域扭曲:用噪声扭曲噪声

最后一招最有意思:不直接看 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.0s
改一改

也可以直接改右边的代码:停手约 0.3 秒会自动重新运行;改坏了点「还原代码」。

扭曲为 0 时就是一张普通的 fBm 云图;往右拖,云开始被拉成一缕缕,像流动的颜料。

除了用噪声的值,也可以用噪声的导数(解析梯度或有限差分)去推开坐标。Perlin 和 Neyret 的 flow noise 就建立在梯度的思路上;现代的一些 Perlin 噪声实现可以同时返回值和解析梯度。

在游戏里怎么用

取舍与常见的坑

小结与练习

  • fBm = 一层层叠噪声:频率按空隙度升高,振幅按增益衰减;叠几层就有了跨尺度的自相似细节。
  • 湍流取绝对值得到尖谷,山脊再翻转平方得到锐脊;让各层相乘就进入了多重分形。
  • 域扭曲用 fBm 推开另一层 fBm 的坐标,做出流动的云和大理石。

练习:用 fBm 做一张俯视的岛屿地图:fBm 的值低于某个阈值是海,稍高一点是沙滩,再高是草地,最高处用山脊噪声画出山脉。

  1. The Book of Shaders: Fractal Brownian Motion
  2. thebookofshaders.com/13

相关页面

图形学噪声函数Noise FunctionsKen Perlin 为电影《电子世界争霸战》(Tron) 设计的噪声,解决「看起来随机却不像电视雪花」的程序纹理问题。入门路径是值噪声 (value noise):格子角点取伪随机,格内用平滑曲线插值;进阶有梯度噪声 (gradient noise)、五次插值改进版,以及用单纯形网格降复杂度的 Simplex Noise。图形学细胞噪声Cellular NoiseSteven Worley(1996)《A Cellular Texture Basis Function》——书中注明约在 Perlin 原始噪声发表十六年之后、其 Simplex Noise(2001)五年之前——把程序纹理建立在「到最近特征点的距离」上,即细胞噪声 / Worley 噪声。GPU 上用格子 + 邻域搜索代替「对全体点求最小距离」;再多存最近特征点身份即可得到 Voronoi 图。后续有 2×2 邻域加速、精确边界与「voro-noise」等变体。图形学着色器伪随机Shader Pseudorandom片元着色器里没有真正的「每次调用都不同」的随机:rand(x) 必须是确定性伪随机——同一输入永远同一输出。常用手法是 fract(sin(x)大数);二维则用 dot 把 vec2 压成标量再喂给同一套路。把空间 floor 成格子后,格子共享一个随机值,就能在秩序与混沌之间做生成设计。图形学塑形函数Shaping Functions塑形函数把归一化到 [0,1] 的一维输入弯成可控制的曲线,是片元着色器里混合颜色、画边、做动画缓动的「基本功」。GLSL 的 pow/step/smoothstep/sin 等多为硬件加速;掌握一维再扩展到二维空间。图形学地形渲染Terrain Rendering地形渲染(游戏、Google Earth、开源大世界引擎 Cesium 等)要在巨大高度场上按距离分配细节,同时控制内存、绘制调用和 LOD 之间的裂缝与跳变。主流 GPU 友好方案有:类似纹理 clipmap 的几何 clipmap、按瓦片复用顶点缓冲只换索引缓冲的分块方案、基于四叉树和屏幕空间误差的 chunked LOD、预存所有过渡索引缓冲的受限四叉树,以及 GPU 细分和压缩等补充手段。任何方案都可叠加分形噪声以在拉近时提供细节,许多系统也在加载时程序化生成地形。图形学天空与云渲染Sky & Cloud Rendering天空颜色和空气透视来自空气分子的瑞利散射,太阳周围的光晕来自近地大颗粒的米氏散射。实时方案有解析拟合模型和基于预计算透射率/散射查找表的物理模型;云则从全景贴图、粒子发展到用程序化噪声构建、光线步进的参与介质层,并以倍频程近似多次散射(RTR4 14.4 节)。

输入关键词开始搜索

滚轮或双指缩放 · 拖动平移 · 双击放大 / 还原