欢迎继续一起踏上 The Journey of Chaos, 关于 Shader 生成技术的一些基础性学习。噪声会分为以下几篇内容学习
- 随机函数与白噪声
- 值噪声 ValueNoise
- 柏林噪声 Gradient Noise
- 多维柏林噪声
- 柏林噪声优化 Simplex Noise
- Cell Noise
- SmoothVoronoi 与VoroNoise
- Simplex Noise变种PsrdNoise
- PsrdNoise 应用 FlowNoise
- CurlNoise 与 Streamline Shaders
- CurlNoise调节与边界
- 2D湍流 (本篇)
- FBM深入
最近 Twitter@Xordev 在 shadertoy中火力全开,他在 2025.03.18 发表了一篇关于 湍流 生成技术的文章 mini.gmshaders.com/p/turbulenc… 。 然后基于此技术做出了一堆让人哇塞的shader, 比如 下面的幽灵和天使两个 shader weixin.qq.com/sph/AAL11I9…
他的代码我完全看不懂,都非常短,也就是 20 行。但我觉得其核心就是他这第一篇文章,以下内容是我的学习的一些记录和对相关内容的一个补充理解。另外内容中还有大量的 psrdnoise的作者(60 岁的大叔)三天前出的一本新书《Noise is Beautiful》。 这位大叔认为自己的这本书填补了 程序化生成技术几十年来的空白。 因为我还刚入门,所以不清楚说的对不对。
地火水气都是湍流
湍流/漩涡 是流体流动中出现的一种复杂且视觉有趣的现象,本质上是一种混动效应。 当湍流被看到的时候其实已经发生了很久。例如我们可以看到水的波纹,而实际上风吹动的水波从小小涟漪开始,以自下而上的方式继续能量, 小涟漪随着时间的推移组合成大浪。另一方面,湍流将能量转移到另一个方向:向一个方向旋转的大漩涡与不移动的介质部分相遇,这耗尽了它们的动能,并产生了较小的漩涡向相反的方向旋转。这些较小的漩涡反过来又产生更小的漩涡,这个过程一直持续到由于流体的粘力使最小的漩涡消散为热量。对于水中的湍流,这种情况发生在厘米级。空气中的湍流粘度比水低得多,可以持续到亚毫米级。
实际上,湍流是我们周围经典“四要素”的大部分视觉细节的原因:水、气、火和土。湍流既发生在水的内部,也发生在水的表面,大多数水波都是由湍流引起的。 火也是一种湍流现象,燃烧和热膨胀会产生大量的内部运动。空气几乎在任何地方都有自然湍流,包括缓慢的速度和巨大的规模。 巨大的规模产生的现象就是为“天气”。 而土壤、沙子、岩石和地面的一般含义中,是由空气和水的侵蚀形成的,而土与空气/水的相互作用就是湍流的形成过程
水和空气等透明介质中的湍流并不总是直接可见的,但它可能会产生相当惊人的次要影响。下图是一些例子。烟雾或水漩涡在几秒钟内产生,天气模式需要几天才能形成,岩石的侵蚀需要数百万年,但它们都是由湍流引起的。
湍流难解
尽然 火,水,尘,风,雾,烟,云这些都深受湍流影响,那么有没有什么数学方法描述这个现象,然后通过解方程的方法完成模拟呢? 答案是有的!而且价值 一百万美金。 这个方程是 navier-stokes 方程
有兴趣获取奖金的,可以访问这个Guardian 链接 www.theguardian.com/science/blo…
正因为湍流计算的复杂性 Xor准备 Fake it。 他提出了一种独创性的方法,能够一定程度模拟湍流,计算代价非常小
波,波,波
总的来说,xor做的事情就是通过 sin函数增加了需要多坐标的变形。 同时在 分型的过程中,增加旋转以去除网格的秩序感。
从一个波开始
pos.x += WAVE_AMP * sin(pos.y * freq) / freq;
这个 WAVE_AMP可以是[0, 1]的一个值,不要超过 1. 你知道的。。。 超过 1 shader就不好处理了。 同时在不同的分型层级对坐标增加一个旋转角度, 具体角度不重要,只要能够打破 方格的秩序感就可以了
//Scroll along the rotated y coordinate
float phase = freq * (pos * rot).y + WAVE_SPEED * u_time;
//Add a perpendicular sine wave offset
pos += WAVE_AMP * rot[0] * sin(phase) / freq;
所有都融合在一起,便有了 turbulence function
//Number of turbulence waves
#define TURB_NUM 10.0
//Turbulence wave amplitude
#define TURB_AMP 0.7
//Turbulence wave speed
#define TURB_SPEED 0.3
//Turbulence frequency
#define TURB_FREQ 2.0
//Turbulence frequency multiplier
#define TURB_EXP 1.4
//Turbulence starting scale
float freq = TURB_FREQ;
//Turbulence rotation matrix
mat2 rot = mat2(0.6, -0.8, 0.8, 0.6);
//Loop through turbulence octaves
for(float i=0.0; i<TURB_NUM; i++)
{
//Scroll along the rotated y coordinate
float phase = freq * (pos * rot).y + TURB_SPEED*iTime + i;
//Add a perpendicular sine wave offset
pos += TURB_AMP * rot[0] * sin(phase) / freq;
//Rotate for the next octave
rot *= mat2(0.6, -0.8, 0.8, 0.6);
//Scale down for the next octave
freq *= TURB_EXP;
}
直接看代码难以已连接,为原始 uv配制了一个 grid。 通过观察 grid的扭曲来感知图像的扭曲
| 改变迭代次数TURB_NUM | 改变振幅TURB_AMP |