噪声函数

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 的效果。

GLSL 代码编辑器

正确代码预览

当前代码预览