分形布朗运动

「噪声的艺术(一)」中我们学习了 Value Noise, Gradient Noise 以及 Simplex Noise 这三种创建噪声的方法。随后我们又在「噪声的艺术(二)」中学到了基于网格的生成方法。是时候将这些技法融入真正的艺术效果中了。

以下内容来自「the book of shaders」分形布朗运动一章。

线性波

正弦波拥有频率和振幅两个特征值,收音机上的 AM(调幅)和 FM(调频)更改的就是这两个特征值。

float amplitude = 1.;
float frequency = 1.;
y = amplitude * sin(x * frequency);

大学里学过的傅立叶变换让我们知道波是可以叠加的。

从音乐理论上说,每个音符都和一个特定的频率相关联。这些音符和频率的关系遵从一定的模式,也就是我们所说的音阶,一个八度(octave)对应着频率上的加倍或减半。

叠加噪声

还记得在「噪声的艺术(一)」中我们学到的 Perlin 噪声的模拟过程吗?既然波是可以叠加的,噪声也可以。

通过在循环(循环次数为 octaves,一次循环为一个八度)中叠加噪声,并以一定的倍数(lacunarity,间隙度)连续升高频率,同时以一定的比例(gain,增益)降低 噪声 的振幅,最终的结果会有更好的细节。这项技术叫“分形布朗运动(fractal Brownian Motion)”(fBM),或者“分形噪声(fractal noise)”

比如下面的例子中,我们叠加了 6 个八度:

const int octaves = 6;
float lacunarity = 2.0;
float gain = 0.5;

float amplitude = 0.5;
float frequency = 1.;

for (int i = 0; i < octaves; i++) {
	y += amplitude * noise(frequency*x);
	frequency *= lacunarity;
	amplitude *= gain;
}

效果如下,可见初始 Perlin 噪声的特征已经被隐藏了:

值得注意的是,虽然 Perlin 噪声计算量不如使用网格生成方式的算法例如 Voronoi,看似效果较差,但是经过 fbm,其实效果已经很好了。

注意,随着我们一个八度接一个八度地往上叠加,曲线看起来有越来越多的细节,同时,自相似性也越来越明显。如果你放大看看,曲线的局部和整体看起来很相似,并且,任选两段不同的部分看起来也多少有些相似。这是一个数学上的分形的重要性质,我们在上面的循环中模拟了这个性质。

模拟自然界效果

这项技术被广泛地应用于构造程序化风景。fBm 的自相似性能够很完美地模拟山脉,因为山脉形成过程中的腐蚀形成了这种不同尺度上的自相似性。

山脊

IQ 大神的作品,希望自己有一天能完全弄懂生成的原理。

完全通过下面的 texture 生成,包含了光照,阴影,摄像机运动等等。

流动的气体

又是 IQ 大神带来的一种华丽效果,他称之为 domain warping。 大致思想是递归调用 fbm:

f(p) = fbm( p + fbm( p + fbm( p ) ) ) 

比如选取一些特殊的参数,再加上 u_time 带上运动效果:

vec2 q = vec2(0.);
q.x = fbm( st + 0.00*u_time);
q.y = fbm( st + vec2(1.0));

vec2 r = vec2(0.);
r.x = fbm( st + 1.0*q + vec2(1.7,9.2)+ 0.15*u_time );
r.y = fbm( st + 1.0*q + vec2(8.3,2.8)+ 0.126*u_time);

float f = fbm(st+r);

最终可以实现类似雾气的流动效果:

总结

「the book of shaders」也只更新到这一章,希望后续章节能够继续更新吧。