数值 · 08
随机与噪声
Random and noise · random-noise随机数制造差异;固定种子可复现,插值噪声可连续变化。
每帧重新调用 Math.random() 会抖动,适合故意制造颗粒,却不适合平滑运动。固定种子让同一布局在刷新或截图时一致;按相邻格点插值的值噪声则把零散随机值变成连续曲线。
公式
seeded[i] = mulberry32(seed)()
noise(x) = mix(hash(⌊x⌋), hash(⌊x⌋+1),
smoothstep(fract(x)))参数
| 本页默认 | 成熟实现 | |
|---|---|---|
| seed | 7 | —同种子、同取样顺序,输出序列相同。 |
| scale | 1 | —输入尺度越大,噪声起伏越密。 |
怎样做好
- 布局随机值只生成一次或从索引算出;
portfolio-photographer用索引哈希固定了卡片初始形态。www-motion/rewrite/portfolio-photographer/model.js:2–3 - 连续运动用插值噪声,别每帧抽一个独立值后直接赋位移。
- 真正要制造不规则闪动时,独立抽样是有意的选择;
shape-trail的新形状就从随机旋转开始。www-motion/rewrite/shape-trail/model.js:8
在我们的案例里
random 出现在 35 个案例,noise 出现在 5 个,合并去重后是 36 个。portfolio-photographer 用稳定的索引哈希摆卡片;shape-trail 为新形状抽取随机初始角度。两者都在生成时确定随机值,避免持续运动变成逐帧抖动。
出现在 36 个案例
参考实现 · basics.js
/** mulberry32: a seeded generator, so screenshots and tests are reproducible. */
export function mulberry32(seed = 1) {
let a = seed >>> 0;
return () => {
a = (a + 0x6d2b79f5) >>> 0;
let t = Math.imul(a ^ (a >>> 15), 1 | a);
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};
}
const hash1 = n => { const s = Math.sin(n * 127.1 + 311.7) * 43758.5453; return s - Math.floor(s); };
/** 1D value noise in [0, 1): random values at integers, smoothly interpolated between. */
export function noise1(x, seed = 0) {
const i = Math.floor(x), f = x - i;
const u = f * f * (3 - 2 * f);
return lerp(hash1(i + seed * 101), hash1(i + 1 + seed * 101), u);
}