从随机到连续
fract(sin(x) * 43758.5) 是着色器里最常见的伪随机哈希:输入相同,输出相同,但相邻输入的结果毫无关系。直接拿来上色只会得到电视雪花。噪声要的是“随机但连续”:在整数网格点上放随机数,格子内部平滑插值。
值噪声与梯度噪声
- 值噪声(value noise):网格角上放随机值,用平滑曲线
f*f*(3-2f)做双线性插值。简单,但能看出方块感。 - 梯度噪声(Perlin 风格):网格角上放随机梯度向量,每个角的贡献是梯度与“角到当前点”向量的点积,再用五次曲线插值。网格感明显更弱。
glsl
float a = dot(hash2(i), f);
float b = dot(hash2(i + vec2(1, 0)), f - vec2(1, 0));把 look 切到 raw,再在两种噪声之间切换,就能看出区别。
分形布朗运动(fBm)
单层噪声太平滑。fBm 把多层噪声叠加起来,每一层(octave)频率乘以 lacunarity(通常 2),振幅乘以 gain(通常 0.5):
glsl
for (int i = 0; i < uOctaves; i++) {
sum += amp * noise(p);
p = R * p * uLacunarity;
amp *= uGain;
}大尺度决定轮廓,小尺度添加细节,这正是山脉、云朵和海岸线的自相似结构。每层再旋转一下(矩阵 R),可以打散网格方向。
域扭曲
Inigo Quilez 的技巧:不直接算 fbm(p),而是先用 fBm 算出一个偏移,把坐标“推歪”再采样:
glsl
vec2 q = vec2(fbm(p), fbm(p + vec2(5.2, 1.3)));
float n = fbm(p + uWarp * q);嵌套两层,就得到烟雾般卷曲流动的图案。偏移随时间变化,云就会缓慢翻涌。
从数值到画面
噪声只是一个数,配色才决定它是什么:云用 smoothstep 映射成密度再混合天空色;大理石用噪声扰动正弦条纹的相位 sin(x + n * 9.0),形成纹理。
每个像素要算 5 次 fBm,开销不小。“render scale”降低渲染分辨率,是实时着色器里最常用的性能旋钮。
核心 API
fractfloormixdotsmoothstepfbmdomain warping动手试试
- 1把 octaves 调到 1,再逐步加到 8,观察细节如何一层层出现。
- 2把 gain 调到 0.7 以上,图案会变得怎样粗糙?
- 3写一个 ridged 版本:把 noise(p) 换成 1.0 - abs(noise(p)),做出山脊线。
还没有输出。console.log 的内容会显示在这里。
运行中