噪声函数
14 / 15
学习和实现 GLSL 中常用的噪声函数,如随机噪声、值噪声和梯度噪声(如Perlin噪声的简化版),用于生成各种程序化纹理和效果。
程序化噪声的核心是「随机但连续」——相邻的像素值接近,整体有平滑的起伏。值噪声(Value Noise)是实现这一点的最基础方法:
值噪声是怎么工作的
把平面分成均匀的格子,每个格点(整数坐标)分配一个伪随机值。当前像素落在某个格子里,取格子四个角的随机值,用平滑曲线在它们之间插值——这就是值噪声。
floor(st) 取格点(整数部分),fract(st) 取像素在格子内的位置(0–1)。
为什么用 ff(3-2f) 而不用直接插值
直接用 f(线性插值)会在格点处产生可见的折痕,因为导数不连续。
f * f * (3.0 - 2.0 * f) 是「平滑阶跃函数」(smoothstep 的多项式等价),它在 0 和 1 处导数都是 0,过渡非常平滑,不会出现折痕。这是值噪声的关键。
画面里有三种噪声对比
- 左侧:随机噪声(
random(pos * 10.0))——像素之间完全独立,看起来像电视雪花 - 中间:值噪声(
valueNoise(pos))——平滑连续的斑块,相邻像素相关 - 右侧:梯度噪声(
perlinNoise(pos))——比值噪声更自然,对比度更均匀
试着改一改
| 改动 | 效果 |
|---|---|
pos * 5.0 改为 pos * 10.0 | 噪声频率翻倍,斑块变小 |
pos * 5.0 改为 pos * 2.0 | 噪声频率减半,斑块变大 |
u_time * 0.5 改为 u_time * 2.0 | 噪声流动速度加快 |
把 f*f*(3.0-2.0*f) 改回 f | 值噪声边缘出现折痕,对比平滑差异 |
练习
尝试在 valueNoise 函数中把 vec2 u = smoothstep(0.0, 1.0, f); 改为等价的多项式写法 f * f * (3.0 - 2.0 * f),观察结果是否相同。
答案解析
smoothstep(0.0, 1.0, f) 和 f * f * (3.0 - 2.0 * f) 数学上完全等价——smoothstep 内部就是这个多项式。两者都在 f=0 和 f=1 处导数为 0,产生平滑过渡。
直接写多项式的优势是:代码更直观地表明了「我在做平滑插值」,而不依赖 GPU 实现的 smoothstep 细节。实际项目中两者均可使用。
试着把值噪声结果做两次叠加:valueNoise(pos) * 0.5 + valueNoise(pos * 2.0) * 0.25,体验手动 FBM 的效果。