【免费下载链接】thebookofshadersStep-by-step guide through the abstract and complex universe of Fragment Shaders.项目地址https://gitcode.com/gh_mirrors/th/thebookofshaders点击查看免费下载《The Book of Shaders》第 13 章以“Fractal Brownian MotionfBm分形布朗运动”为核心讲解如何从最基础的正弦波出发通过叠加多个不同频率与振幅的噪声迭代八度在片元着色器中生成具有自相似细节的程序化纹理——这是地形、云层、湍流等自然现象生成的基础技术。读完本文你将掌握 fBm 的三个核心参数octaves、lacunarity、gain及其在仓库源码中的实际写法并能动手实现 turbulence湍流、ridge山脊与 domain warping域扭曲等进阶变体。从波的叠加到噪声fBm 的起点“噪声”在不同领域有不同含义音乐家想到的是干扰音通信工程师想到的是信号干扰天体物理学家想到的则是宇宙微波背景辐射。本章选择从更基础也更简单的概念入手——波。波是某个物理量随时间的涨落声波是气压的涨落电磁波是电场与磁场的涨落。描述一列简谐波只需要两个关键特征振幅amplitude波动的幅度大小频率frequency波动的快慢。一维简谐波的方程写作float amplitude 1.; float frequency 1.; y amplitude * sin(x * frequency);这是本章提供的第一个交互实验。通过调整frequency与amplitude可以直观感受两个参数对波形的影响。随后文档给出了两个进阶练习使用 shaping functions塑形函数见第 5 章随时间改变振幅使用 shaping functions 随时间改变频率。完成这两个练习后你就完成了对正弦波的“调制”前者是AMamplitude modulated调幅波后者是FMfrequency modulated调频波。波的叠加superposition波的另一个有趣性质是可叠加性——多个波相加仍是一个波。仓库文档给出了一个叠加了 5 条正弦波的交互示例其中每条波都有独立的频率倍数与相位偏移float amplitude 1.; float frequency 1.; y sin(x * frequency); float t 0.01*(-u_time*130.0); y sin(x*frequency*2.1 t)*4.5; y sin(x*frequency*1.72 t*1.121)*4.0; y sin(x*frequency*2.221 t*0.437)*5.0; y sin(x*frequency*3.1122 t*4.269)*2.5; y * amplitude*0.06;这里t由u_time驱动为每条波引入不同的随时间变化的相位从而产生动态效果。文档建议的实验包括修改各附加波的频率与振幅尝试让两条波相互抵消相位相反时观察效果尝试让两条波相互增强相位相同时观察效果。音乐中每个音符对应一个频率音符频率的排列形成音阶频率加倍或减半对应跨越一个八度octave。这个概念随后将直接迁移到 fBm 的参数命名上——每一次噪声迭代也被称为一个“八度”。核心概念八度、间隙度与增益正弦波虽然规则但它的周期性过于明显。Perlin 噪声在基本形态上与正弦波有相似的“观感”振幅大致稳定频率围绕一个中心频率在较窄范围内波动但远不如正弦波规则——这使它对“随机感”的模拟更容易。当然若干正弦波相加也能伪造出随机感但要掩盖其周期性规律需要非常多条波。fBmfractal Brownian Motion分形布朗运动的做法是叠加多次噪声迭代每次迭代频率按固定步长递增lacunarity间隙度同时振幅递减gain增益。这样就能在噪声中获得更细的颗粒度与更丰富的细节其最简单的形式如下// Properties参数 const int octaves 1; float lacunarity 2.0; float gain 0.5; // // Initial values初始值 float amplitude 0.5; float frequency 1.; // // Loop of octaves八度循环 for (int i 0; i octaves; i) { y amplitude * noise(frequency*x); frequency * lacunarity; amplitude * gain; }三个参数的含义与建议取值范围参数含义默认值调参效果octaves参与叠加的噪声迭代次数八度数1建议逐步调至 2、4、8、10越多细节越丰富但计算量线性增长lacunarity相邻八度之间的频率倍增因子2.0决定高频细节的“间距”典型值为 2.0gain相邻八度之间的振幅衰减因子0.5决定高频细节对最终结果的贡献权重典型值为 0.5文档给出的实验路径是先把八度数从 1 逐步增加到 2、4、8、10观察曲线细节的增多当八度数超过 4 后再分别修改lacunarity与gain体会二者对高频细节密度与强度的不同影响。仓库源码剖析一维与二维 fBm 的 GLSL 实现仓库的 13/ 目录下存放了本章所有可直接运行与编辑的着色器源码。其中 1d-fbm.frag 将上述思路落地为一维曲线核心实现如下#define NUM_OCTAVES 5 float fbm ( in float x) { float v 0.0; float a 0.5; float shift float(100.0); for (int i 0; i NUM_OCTAVES; i) { v a * noise(x); x x * 2.0 shift; a * 0.5; } return v; }注意这里比“教科书版”多了一个细节x x * 2.0 shift。每次迭代不仅把坐标频率翻倍还加上一个较大的位移量shift 100.0避免各八度因对齐而产生规则的伪影。main()中通过y fbm(st.x*3.0u_time)驱动时间动画并用plot()函数把一维曲线绘制在画布上。二维版本 2d-fbm.frag 则直接生成一张“看起来像分形”的图案#define OCTAVES 6 float fbm (in vec2 st) { // Initial values float value 0.0; float amplitude .5; float frequency 0.; // // Loop of octaves for (int i 0; i OCTAVES; i) { value amplitude * noise(st); st * 2.; amplitude * .5; } return value; }该文件底部用color fbm(st*3.0)输出到gl_FragColor。文档特别标出了三个可以直接实验的修改点与源码行号一一对应第 37 行#define OCTAVES 6修改八度数第 47 行st * 2.;这里的乘数 2.0 即 lacunarity可改为其他值第 48 行amplitude * .5;这里的乘数 0.5 即 gain可改为其他值。文件上半部分的random()与noise()实现的是基于 Morgan McGuire 思路的值噪声在整数格点取伪随机值用f * f * (3.0 - 2.0 * f)平滑的 Hermite 插值在四角之间混合。如果想对比不同噪声基底同一章还有 noise.frag它提供了 1D、2D、3D 三套random()/noise()与对应的fbm()重载而第 11 章的 2d-snoise.fragSimplex 噪声来自 Ashima Arts 的 webgl-noise 实现与 2d-pnoise.fragStefan Gustavson 的经典 Perlin 噪声及其周期变体可作为不同噪声基底的替代来源。自相似性与“够用的分形”为什么有限迭代即可随着八度增加曲线细节不断增多同时出现明显的自相似性self-similarity放大曲线任意局部看到的形态与整体大致相似且不同局部之间也彼此相似。这是数学分形的关键性质fBm 正是通过在循环中模拟这一性质。严格来说叠加有限个八度得到的不是真正的分形——只有让循环无限延续、累加无穷多个噪声分量理论上才会得到真正的数学分形。但在计算机图形学中可解析的最小细节存在硬性上限当对象比单个像素还小时继续累加已经无法被渲染出来。因此不需要无限求和来制造分形外观——有时需要很多项但永远不会是无穷项。这一论断与片元着色器的实际执行模型吻合每个片元只做有限次浮点运算过高的八度数只会浪费 GPU 周期而不增加可见细节。实战应用程序化地形fBm 最广泛的应用之一是程序化地形生成。fBm 的自相似性对山脉尤其合适真实山脉由侵蚀作用形成而侵蚀过程天然具备跨大尺度范围的自相似性——放大一座山的局部其起伏统计特征与整座山相似。这正是文档引用丹·霍兹沃思Dan Holdsworth作品《Blackout》的原因——holdsworth.jpg 所呈现的层叠山体轮廓与 fBm 叠加噪声的视觉逻辑同源。关于此方向的进阶阅读文档推荐了 Inigo Quiles 关于高级噪声的文章深入讨论了多噪声变体在程序化纹理中的应用其思想在仓库第 13 章 notes.md 中也有收录。变体一Turbulence 湍流噪声利用几乎相同的技术只需把噪声取绝对值即可得到turbulence湍流效果它本质上是 fBm但使用有符号噪声signed noise的绝对值来构造函数中的尖锐谷底。for (int i 0; i OCTAVES; i) { value amplitude * abs(snoise(st)); st * 2.; amplitude * .5; }仓库中的 turbulence.frag 是完整实现。其前半部分内嵌了 Ian McEwan / Ashima Arts 的 2D Simplex 噪声函数snoise()#define OCTAVES 3返回范围约在 [-1, 1]turbulence()对snoise(st)取绝对值后再按八度累加从而把噪声的负半周“折叠”成尖锐的谷地纹理#define OCTAVES 3 float turbulence (in vec2 st) { float value 0.0; float amplitude .5; float frequency 0.; for (int i 0; i OCTAVES; i) { value amplitude * abs(snoise(st)); st * 2.; amplitude * .5; } return value; }变体二Ridge 山脊噪声ridge山脊噪声属于该算法家族的另一个成员把湍流中尖锐的谷底上下翻转变成尖锐的山脊。核心变换只有三行n abs(n); // 制造谷底 n offset - n; // 翻转谷底使其位于顶部成为山脊 n n * n; // 锐化山脊仓库中的 ridge.frag 给出了完整实现并更进一步实现了带增益的山脊多重分形ridged multifractal。其核心函数ridgedMF()的特别之处在于每个八度不仅叠加ridge()的输出还用上一八度的输出prev来缩放当前项sum n*amp*prev; prev n;这正是“基于前项缩放后续噪声”思想的一个具体实例float ridgedMF(vec2 p) { float lacunarity 2.0; float gain 0.5; float offset 0.9; float sum 0.0; float freq 1.0, amp 0.5; float prev 1.0; for(int i0; i OCTAVES; i) { float n ridge(snoise(p*freq), offset); sum n*amp; sum n*amp*prev; // 用上一八度缩放 prev n; freq * lacunarity; amp * gain; } return sum; }文件注释明确标注了该算法的出处Texturing Modeling, A Procedural Approach第 12 章即 Ken Musgrave 的经典著作。变体三Multifractal 与进一步探索除了取绝对值、翻转fBm 家族还有更多变体乘法组合把各八度的噪声相乘而非相加可以产生截然不同的纹理变化依赖前项的缩放用循环中前一项的值来缩放后续噪声函数如上面ridgedMF()中的prev。当采用这类做法时就脱离了严格的数学分形定义进入相对少为人知的multifractal多重分形领域。多重分形在数学上没有严格定义但丝毫不影响其在图形学中的价值——事实上多重分形模拟在现代商业地形生成软件中非常常见。想深入研究文档推荐 Kenton Musgrave 参与编写的《Texturing and Modeling: a Procedural Approach》第 3 版第 16 章。该书的 1 版 PDF 虽然可在线购买但内容停留在 1994 年缺少第 3 版的地形建模内容文档特意提示不必购买。域扭曲 Domain Warping用噪声扭曲噪声Inigo Quiles 有一篇著名的文章讲述如何用 fBm 去扭曲另一个 fBm 的空间——即“梦境中的梦境”。经典公式写作f(p) fbm( p fbm( p fbm( p ) ) )仓库中的 clouds.frag 是该思想的温和版示例用多层 fBm 的输出作为坐标偏移逐级扭曲纹理坐标最终生成类似云朵的纹理且结果仍保留自相似性。关键代码如下vec2 q vec2(0.); q.x fbm( st 0.00*u_time); q.y fbm( st vec2(1.0)); vec2 r vec2(0.); r.x fbm( st 1.0*q vec2(1.7,9.2) 0.15*u_time ); r.y fbm( st 1.0*q vec2(8.3,2.8) 0.126*u_time); float f fbm(str);流程可以概括为三步用 fBm 计算第一层偏移q用st q作为输入再次计算偏移r第二层扭曲最终用st r采样 fBm 得到f再配合q、r的长度信息做多层颜色混合。main()中随后用三次mix()将f*f、length(q)、length(r.x)映射到不同颜色区间最后以(f*f*f.6*f*f.5*f)*color作为输出。NUM_OCTAVES 5的 fBm 内部还加入了一个 0.5 弧度的旋转矩阵mat2 rot来降低轴向偏差axial bias这也是 noise.frag 中 2D fBm 的通用技巧。文档对域扭曲的评价十分中肯用它扭曲纹理坐标非常有用、非常有趣但也极其难以驾驭——这是强大的工具需要大量经验才能用好。进阶梯度位移与 flow noise域扭曲的一种实用变体是用噪声的导数梯度来位移坐标。Ken Perlin 与 Fabrice Neyret 的著名论文“flow noise”正建立在这一思想之上。一些现代 Perlin 噪声实现会同时计算函数值与解析梯度如果某个程序化函数没有现成的“真梯度”则可以用有限差分相邻像素之间的差值来近似不过这样精度较低、计算量也更大。如何在本仓库中运行与实验仓库是一个 PHP 驱动的站点每个章节目录下的 index.php 会根据?lan参数加载对应的多语言 README 并通过 Parsedown 渲染成页面而文档中的div classcodeAndCanvas data2d-fbm.frag/div与simpleFunction交互块以及edit.php#13/turbulence.frag这类链接指向的是基于 glslEditor 的在线 GLSL 编辑器见 edit.php它通过new GlslEditor(...)初始化编辑器画布支持canvas_draggable、multipleBuffers、watchHash等配置。推荐的实验路径打开 2d-fbm.frag按文档提示修改第 37、47、48 行的OCTAVES、st * 2.、amplitude * .5观察细节密度变化对照 turbulence.frag 与 ridge.frag理解abs(snoise())与offset - n; n n * n;如何把同一噪声基底塑造成截然不同的纹理在 clouds.frag 中调整各层 fBm 的偏移系数如1.0*q与时间缩放体会域扭曲的“失控”边界若要更换噪声基底可把第 11 章 2d-snoise.frag、2d-pnoise.frag 等实现移植进 fBm 循环中对比效果。此外本章英文原版还推荐了 LYGIA 的 generative functions 工具库——一组可复用的 GLSL 图案生成函数颗粒度细、面向复用与性能便于接入任意项目与框架是学习“随机 噪声 → 生成艺术”的补充资源。小结fBm 的核心思想极其简洁用“越来越高频、越来越微弱”的多层噪声叠加逼近自然界无处不在的自相似细节。从正弦波与叠加原理出发本章及仓库 13/ 目录完整演示了 fBm 的 1D/2D 实现、三个核心参数的调优方法以及 turbulence、ridge、multifractal、domain warping 四条经典变体路径。掌握这些代码与参数直觉就掌握了程序化纹理生成领域最基础、也最具生产力的一把钥匙——无论目标是生成山脉、云层、水流还是抽象的生成艺术它们几乎都从这层“分形布朗运动”开始。赞分享【免费下载链接】thebookofshadersStep-by-step guide through the abstract and complex universe of Fragment Shaders.项目地址https://gitcode.com/gh_mirrors/th/thebookofshaders点击查看免费下载相关推荐The Book of Shaders 实战fBm 分数布朗运动——从正弦波叠加到程序化分形噪声The Book of Shaders 实战fBm 分数布朗运动——从正弦波叠加到程序化分形噪声 本篇技术指南以《The Book of Shaders》第Material Maker FBM 节点完全指南分形布朗运动噪声的生成原理与参数实战Material Maker FBM 节点完全指南分形布朗运动噪声的生成原理与参数实战 本文以 Material Maker 的 FBM 节点为核心完整讲解桌面应用图形学3D渲染图像处理Material Maker TEX3D FBM 节点完全指南3D 分形布朗运动噪声的原理、参数与 Godot 着色器实现Material Maker TEX3D FBM 节点完全指南3D 分形布朗运动噪声的原理、参数与 Godot 着色器实现 本文基于 Material Mak桌面应用图形学3D渲染图像处理上一篇openEuler热补丁调试指南使用debuginfo包进行热补丁故障排查的3种方法下一篇eulerfs统一分配器设计内容无关的内存管理优化方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考