
【免费下载链接】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 章13/README-ua.md 乌克兰语版对应英文原文 13/README.md为主线系统讲解 GLSL 片段着色器Fragment Shader中分数布朗运动fractal Brownian Motion简称 fBm的完整知识链从一维正弦波的振幅/频率与叠加原理出发过渡到 Perlin 噪声再深入 fBm 的三大控制参数octaves、lacunarity、gain并延伸到湍流turbulence、山脊ridge、多重分形与域扭曲domain warping等派生技术。读完本篇你将能读懂并亲手调优仓库中 13/2d-fbm.frag、13/clouds.frag 等真实示例掌握用几行 GLSL 生成云朵、山脉等程序化纹理的完整方法。起点从正弦波理解振幅、频率与叠加fBm 的思想源头是波。作者在书中指出不同领域对噪声的理解完全不同音乐家想到刺耳的声响通信工程师想到干扰天体物理学家想到宇宙微波背景辐射——但这些概念都指向同一件事世界中的随机性。而理解随机噪声最扎实的起点是比它更基础、更简单的对象波。波是某种物理量随时间发生的波动。声波是空气压力的波动电磁波是电场与磁场的波动。描述一个波有两个关键特征振幅amplitude波动的幅度大小频率frequency波动的快慢。一维简谐波的方程只有一行float amplitude 1.; float frequency 1.; y amplitude * sin(x * frequency);在本书网页版中这段代码会被simpleFunction容器渲染成可交互的实时函数绘图其底层渲染由 src/main.js 中定义的preFunction/postFunctionGLSL 前缀/后缀拼装而成见 src/main.js#L7-L107。作者建议你动手做三个实验改变frequency与amplitude的取值观察曲线行为用第 5 章的整形函数shaping functions让振幅随时间变化用整形函数让频率随时间变化。做完后两项你就完成了对正弦波的调制前者是 AM振幅调制后者是 FM频率调制。波的另一个迷人性质是叠加superposition多个波相加会产生全新的整体形态。下面这段可交互代码把 5 条不同频率、不同振幅的正弦波叠在一起并引入了时间变量u_time让它们各自漂移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;配套练习是三个非常直观的问题调整各分量波的频率与振幅观察总和曲线的变化能否构造出两条相互抵消的波那会是什么样子能否让叠加后的波互相增强音乐中的音阶也遵循同样的频率逻辑频率翻倍或减半对应一个八度octave的跳跃。这个八度概念正是 fBm 中 octaves八度/倍频程一词的来源。从正弦波到 Perlin 噪声为什么不用一堆正弦波拼随机既然叠加正弦波能产生复杂形态为什么还要引入噪声作者的解释很关键Perlin 噪声在基本形态上与正弦波看起来、感觉起来非常相似——它的振幅比较稳定频率被限制在中心频率附近的狭窄区间内。但与正弦波不同它不那么规则因此只需叠加少数几个缩放版本就能轻易制造出随机的外观。而如果只用正弦波来假装随机你需要非常非常多的不同频率的波才能掩盖它们固有的周期性与规律性。这就是 Perlin 噪声在程序化生成中不可替代的原因。仓库中 13/1d-fbm.frag 注释掉了三行正好对比三种画法y random(st.x*0.001u_time)纯随机、y noise(st.x*3.u_time)单层值噪声、y fbm(st.x*3.0u_time)fBm取消注释即可直观对比三者的视觉差异。fBm 核心octaves、lacunarity 与 gain把不同迭代次数的噪声叠加起来每次迭代按固定倍数提高频率称为 lacunarity隙度、按固定比例降低振幅称为 gain增益就能在噪声中获得更细的颗粒度与更多细节。这项技术就叫fractal Brownian MotionfBm分数布朗运动也叫分形噪声。书中给出的一维 fBm 最小实现如下// 属性 const int octaves 1; // 八度迭代次数 float lacunarity 2.0; // 隙度每次迭代频率的倍增系数 float gain 0.5; // 增益每次迭代振幅的衰减系数 // 初始值 float amplitude 0.5; float frequency 1.; // 按八度循环 for (int i 0; i octaves; i) { y amplitude * noise(frequency * x); frequency * lacunarity; amplitude * gain; }三个参数的作用可归纳为下表参数含义常见取值影响octaves噪声叠加的迭代层数110超过 4 后细节收益递减层数越多曲线/纹理细节越丰富lacunarity相邻两层频率的倍增系数典型值 2.0控制细节层的频率间距1 时高频细节越拉越开gain相邻两层振幅的衰减系数典型值 0.5控制高频细节的贡献权重越小高频越弱配套实验建议把octaves从 1 依次增加到 2、4、8、10观察细节如何逐层变多当层数超过 4 后改变lacunarity的值观察频率结构变化当层数超过 4 后改变gain的值观察高频细节强弱变化。自相似性与真正的分形书中强调随着八度增加曲线会呈现出自相似性self-similarity放大曲线的任意一小段看起来与整体差不多每一段与其他段都大同小异。这是数学分形的重要属性而 fBm 循环正是对这一属性的模拟。但严格来说fBm不是真正的分形因为循环在有限次迭代后停止了。理论上如果让循环无限持续、叠加无穷多个噪声分量就会得到真正的数学分形。不过在实际计算机图形学中我们永远受限于可分辨的最小细节——当物体小过一个像素时再叠加无穷项就没有意义了。结论是有时需要很多项但永远不需要无限项。二维 fBm 实战逐行解读 2d-fbm.frag仓库 13/2d-fbm.frag 给出了二维 fBm 的完整可运行实现代码结构非常清晰① 随机函数基于点积正弦的经典哈希式随机float random (in vec2 st) { return fract(sin(dot(st.xy, vec2(12.9898,78.233)))* 43758.5453123); }② 值噪声取整数格点floor与小数部分fract对正方形四角的随机值做平滑插值插值因子用平滑曲线f * f * (3.0 - 2.0 * f)即 smoothstepfloat noise (in vec2 st) { vec2 i floor(st); vec2 f fract(st); float a random(i); float b random(i vec2(1.0, 0.0)); float c random(i vec2(0.0, 1.0)); float d random(i vec2(1.0, 1.0)); vec2 u f * f * (3.0 - 2.0 * f); return mix(a, b, u.x) (c - a)* u.y * (1.0 - u.x) (d - b) * u.x * u.y; }③ fBm 主体默认 6 个八度振幅从 0.5 起步、每层减半坐标每层翻倍#define OCTAVES 6 float fbm (in vec2 st) { float value 0.0; float amplitude .5; float frequency 0.; for (int i 0; i OCTAVES; i) { value amplitude * noise(st); st * 2.; amplitude * .5; } return value; }④ 主函数校正宽高比后放大坐标st*3.0再送入 fBm得到分形灰度图案void main() { vec2 st gl_FragCoord.xy/u_resolution.xy; st.x * u_resolution.x/u_resolution.y; vec3 color vec3(0.0); color fbm(st*3.0); gl_FragColor vec4(color,1.0); }文档给出的三个调参练习直接对应源码行号将第 37 行的#define OCTAVES 6改小如 14观察细节减少修改第 47 行st * 2.;改变 lacunarity修改第 48 行amplitude * .5;改变 gain。补充更精细的一维动画版本 13/1d-fbm.frag 和覆盖 1D/2D/3D 三种维度的 13/noise.frag 也值得阅读——后者对 2D 噪声引入了旋转矩阵mat2 rot mat2(cos(0.5), sin(0.5), -sin(0.5), cos(0.50));来消除轴向偏差axial bias并对每层坐标加入shift vec2(100.0)偏移以避免晶格对齐。fBm 与程序化地形为什么山脉天生自相似fBm 最常见的应用是程序化景观生成procedural landscape。作者指出fBm 的自相似性对山脉建模近乎完美原因是真实山脉由侵蚀过程塑造而侵蚀在极大范围的尺度上都会留下自相似的外观——大山的轮廓与山体上的一块岩石有统计上的相似结构。这正是 fBm 输出特性的天然匹配。若对此方向感兴趣书中推荐阅读 Inigo Quiles 关于高级噪声的文章《advanced noise》。湍流turbulence对噪声取绝对值制造尖谷用几乎相同的循环但对带符号的噪声取绝对值就得到湍流效果——本质是 fBm但通过abs()把负值翻折成正在函数上形成尖锐的谷sharp valleysfor (int i 0; i OCTAVES; i) { value amplitude * abs(snoise(st)); st * 2.; amplitude * .5; }仓库中的完整实现位于 13/turbulence.frag它基于 Ian McEwan 与 Ashima Arts 的 GLSL 2D simplex noisesnoise见文件头注释与 13/turbulence.frag#L27-L84主循环即上述三段式逻辑默认#define OCTAVES 3。下图是效果来自 13/turbulence-long.png山脊ridge把尖谷倒转成尖峰同一算法家族的另一位成员是山脊把尖锐的谷倒扣过来变成尖锐的脊。书中给出核心三行n abs(n); // 制造褶皱 n offset - n; // 把褶皱倒转尖谷变尖脊 n n * n; // 进一步锐化褶皱仓库 13/ridge.frag 把这三行封装成ridge(h, offset)函数并在ridgedMF中做真正的多重分形叠加除了标准的freq * lacunarity; amp * gain;之外还引入了prev——用上一八度的输出缩放当前八度sum n*amp*prev;这正是文档所说的让后续噪声函数基于循环中先前项的结果进行缩放。其效果图见 13/ridge-long.png多重分形multifractals乘法叠加与依赖前层的缩放当不再严格逐层累加而是把噪声分量相乘或者用依赖于循环中先前项的量来缩放后续噪声函数时我们就离开了严格分形的定义进入了数学上尚未严格定义的多重分形领域。不过定义模糊并不妨碍它在图形学中的实用性——多重分形模拟在现代商业地形生成软件中非常普遍。ridge.frag中的ridgedMFridged multifractal正是这种思路的实例它既对每层做了abs → offset - n → n²的整形又把前一层输出prev乘入本层贡献。想要深入书中推荐 Kenton Musgrave 所著《Texturing and Modeling: a Procedural Approach》第 3 版第 16 章该书已绝版但图书馆与二手市场仍有流通注意网上出售的是 1994 年第 1 版的 PDF不含任何地形建模内容不值得购买。域扭曲Domain Warping用 fBm 扭曲 fBm 的空间用 fBm 的输出作为坐标偏移量再去采样另一个 fBm就是domain warping域扭曲/空间扭曲——Inigo Quiles 称之为用 fBm 扭曲 fBm 的空间如同《盗梦空间》里梦中之梦。下图是f(p) fbm(p fbm(p fbm(p)))的效果来自 13/quiles.jpg仓库中的温和版实现是 13/clouds.frag用两级扭曲生成云状纹理。其核心逻辑是vec2 q vec2(0.); q.x fbm( st 0.00*u_time); // 第一层 fBm 作为 x 偏移 q.y fbm( st vec2(1.0)); // 第一层 fBm 作为 y 偏移 vec2 r vec2(0.); r.x fbm( st 1.0*q vec2(1.7,9.2) 0.15*u_time ); // 第二层用 q 扭曲坐标 r.y fbm( st 1.0*q vec2(8.3,2.8) 0.126*u_time); float f fbm(str); // 第三层采样随后用多层mix在深青、暖灰、深蓝、亮青之间插值并乘以(f*f*f .6*f*f .5*f)的幂次整形得到带自相似性的云朵纹理。注意vec2 shift vec2(100.0);与旋转矩阵的使用13/clouds.frag#L42-L52与noise.frag的防偏差处理一脉相承。书中对域扭曲的评价非常中肯它极有用、极有趣但也极难精通——需要相当的经验才能用好。一个实用的技巧是用噪声的导数梯度来位移坐标。Perlin 与 Fabrice Neyret 的经典论文《Flow Noise》2001正是基于这一思想一些现代 Perlin 噪声实现会同时计算函数值与其解析梯度若某个程序化函数拿不到真实梯度也可以用有限差分近似只是精度较低、计算量更大。工具推荐与总结章节末尾为读者工具箱推荐了LYGIA 的 generative 函数库——一组可复用的 GLSL 程序化生成函数专为可复用性、性能与灵活性设计可轻松接入任意项目与框架是学习用随机与噪声做生成艺术的优质资源。本章动手清单速览用simpleFunction交互块调制正弦波的振幅与频率AM/FM再做波的叠加与抵消实验将 13/1d-fbm.frag 中注释掉的random/noise/fbm三行依次启用对比三种信号将 13/2d-fbm.frag 第 37 行的OCTAVES从 6 逐级降到 1观察细节退化的梯度在 4 个八度下分别调整 2d-fbm 的 lacunarity第 47 行与 gain第 48 行对比 13/turbulence.frag 与 13/ridge.frag前者对snoise取绝对值后者做abs → offset - n → n²并乘以前层输出用 13/clouds.frag 体会三层 fBm 嵌套扭曲坐标、把灰度噪声变成云朵的完整过程。从一条正弦波到云海与山脉fBm 的全部秘密就藏在八度叠加、频率倍增、振幅衰减这一个循环里而湍流、山脊、多重分形与域扭曲都只是对这个循环的微小变奏。掌握它们你就拿到了程序化纹理生成的核心钥匙。赞分享【免费下载链接】thebookofshadersStep-by-step guide through the abstract and complex universe of Fragment Shaders.项目地址https://gitcode.com/gh_mirrors/th/thebookofshaders点击查看免费下载相关推荐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渲染图像处理用 p5.js 实现叠加波Additive Waves从正弦波类到多波叠加动画用 p5.js 实现叠加波Additive Waves从正弦波类到多波叠加动画 在《Nature of Code》第三章振荡系列的 3.7 节中Co教程文档示例工程上一篇OI-wiki 最小生成树MST全解从 Kruskal、Prim、Borůvka 到次小生成树与 Kruskal 重构树下一篇OpenJarvis LLM-Guided Spec Search 实战指南本地-云端协作的 Agent 配置自搜索与验收创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考