第 8 课:噪声与随机
“随机”先要稳定
程序化纹理、云、火焰、地形和木纹,都需要看起来有变化的数值。但片元 Shader 没有可持久修改的随机数状态:每个片元独立运行。同一输入应给出同一输出,才能让画面稳定。常见办法是对网格编号做确定性哈希:
float hash(vec2 p) {
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);
}
这不是密码学随机数,只是便于教学的伪随机散列。floor(vUv*12.0) 给每格一个整数编号,同格片元读同一值,刷新后分布仍相同。若把 floor(uTime*18.0) 加到编号中,每秒换 18 次随机图案,就得到电视雪花;不用 floor 时值会连续变化,视觉上更像闪动云,而不是一帧一帧的噪点。
从硬方格到连续噪声
大块马赛克只对 floor(p) 采样,格子边界会突变。Value Noise 在位置 p 所在格子的四个角各取一个 hash 值,再按格内小数坐标插值。先沿 X mix(a,b,w.x) 与 mix(c,d,w.x),再沿 Y 混合两条结果。权重 w=f*f*(3-2*f) 在格子边缘斜率趋近零,邻格连接更平滑。若直接用 f,颜色仍连续,但接缝处斜率可能可见。
噪声的输入坐标控制尺度。valueNoise(vUv*8.0) 比 *4.0 有更多细节,却不会凭空增加几何顶点。片元计算仍按画布像素数执行;把噪声用于顶点地形时,则按网格顶点数执行。根据效果选择阶段,不要把只需在少量顶点算一次的高度函数放进片元中重复几十万次。
多层噪声与 FBM
分形布朗运动(FBM)把几种尺度的噪声相加:低频负责大形状,高频负责细节,频率通常每层翻倍,权重每层减半。第 5 题先只叠加两层,便于看出各层贡献;后面云、火焰等练习使用四层。它是常见视觉合成方法,不代表真实流体或自然过程。
| 效果 | 公式中的关键变化 | 视觉结果 |
|---|---|---|
| 火焰 | FBM 扰动左右边界,噪声坐标随时间向下移动 | 轮廓向上窜动 |
| 云雾 | FBM 后用 smoothstep 选出较亮区域 |
柔和云团漂移 |
| 地形明暗 | 高度图相邻采样的差分构造近似法线 | 朝光方向的坡面更亮 |
| 大理石 | FBM 扰动正弦波相位 | 原本笔直的条带弯曲 |
| 木纹 | 中心半径与扰动相位生成周期环 | 不规则同心年轮 |
第 8 题用 h(vUv+εx)-h(vUv) 与 h(vUv+εy)-h(vUv) 估算坡度,再组成法线与光方向点乘。这只改变着色,平面的轮廓仍然平;真实三维地形需像第 7 课一样移动顶点。差分步长过大使细节被平均,过小则容易受浮点精度和采样分辨率影响。示例使用 0.004 UV 单位,适合当前正方形预览。
数据流、性能与兼容性
JS 建立覆盖预览区域的平面。顶点 uv attribute 传到 vUv,经光栅化插值后,每个片元用它计算 hash、value noise、FBM 和最终颜色。动画题另由 JS 每帧以秒更新 uTime uniform。ShaderMaterial 示例使用 Three.js 的输出颜色空间片段,所有混色都在 Shader 内计算。
单次 hash 很便宜,但 value noise 每次读取四个 hash;四层 FBM 至少做四次 value noise,地形差分又会把 FBM 调用三遍。即使代码只有一行 fbm(...),也可能包含几十次数学运算。高分辨率全屏效果、移动端和多重后处理要测 GPU 时间;可降低层数、缩小渲染分辨率、缓存成纹理,或使用预制噪声贴图。sin 哈希在不同精度/驱动下不保证逐像素完全一致;需要跨设备一致的离线图案时,优先使用固定纹理或 CPU 生成的数据。
常见故障
噪声成整块纯色时,先输出 vUv 确认坐标在变,再检查是否过早 floor;格子数量不对时,区分 UV 乘数和画布像素尺寸;动画跳变时,检查 floor(uTime*rate) 是否本来就用于离散帧;火焰形状消失时,单独把遮罩输出成灰度,确认宽度与扰动项的值域。
练习
| 难度 | 题目 | 可见验收 |
|---|---|---|
| ⭐ | 确定性的伪随机函数 | 刷新后相同的灰度方格 |
| ⭐ | 逐帧变化的随机雪花 | 雪花持续闪烁 |
| ⭐⭐ | Floor 分块马赛克噪声 | 硬边随机块 |
| ⭐⭐ | Mix 双线性 Value Noise | 连续灰度过渡 |
| ⭐⭐ | 两层噪声叠加 FBM | 大小尺度兼有 |
| ⭐⭐⭐ | 噪声塑形的动态火焰 | 火焰向上流动 |
| ⭐⭐⭐ | 多层 FBM 漂浮云雾 | 云团缓慢漂移 |
| ⭐⭐⭐ | 噪声高度图与近似光照 | 明暗坡面 |
| ⭐⭐⭐⭐ | 噪声扭曲的大理石纹 | 弯曲矿脉 |
| ⭐⭐⭐⭐ | 带扰动的木纹年轮 | 不规则年轮 |