Stam J. Real-Time Fluid Dynamics for Games[J]. Journal of Graphics Tools, 2003, 6.
感谢朱老师的指导..本文对论文的实现代码进行分析,并试图补全论文中说得不够详细的部分,侧重于对solver的分析,opengl的部分比较简单,附件为已添加注释的代码。
我使用canvas api实现了一个基于web的版本,限于浏览器性能,在帧率上不如原文。可以在此链接中浏览效果:http://pigcage.tech/MyProjects/stablefluid/
一、系统的建立
1、网格系统
这里使用的是欧氏方法,代码中创建了一个N*N的网格(其中N=64,越大的N值意味着越高的性能开销)。在网格的四周有一层边界(0与N+1),亦即实际网格的大小为size=(N+2)*(N+2)。对于网格中的每一个单元格(cell),假定N*N网格的边长为1,那么每个单元格的边长为h=1/N。
基于此网格系统,程序使用一些全局变量来储存流体的基本属性,见附件中demo.c的注释如图:
时间步长为dt,一般来说,应满足dt < h * |u|,以保证模拟的精度。
每个单元格对应有密度(density)与速度(velocity)两个属性。其中速度为矢量,此处为二维模拟,故分为u、v两个方向表示,此处u指上下方,v指左右方。对于这些属性,分别使用形如dens、dens_prev形式的两个数组, 表示网格该属性的当前状态和前一状态。使用SWAP(x0,x)来交替这两个数组以达到状态的更新,其中x0为上一状态。这些数组均为一维数组,程序中使用形如dens[IX(i , j)]的形式,表示第j行i列的单元格属性。
2、准备知识
1.为了便于求解,使用到了Splitting方法,大体来说是这样的,感觉比较显然就不具体描述了吧..
2.N-S方程
3.顺便贴一下物质导数D
二、密度步骤
由于这里是处理烟雾,密度的高低等价于烟雾的浓度。使用密度数据即可绘制对应的烟雾视图。对密度的处理分为上图几个步骤,在每一帧中,依次添加力、处理扩散和移动。
1、力和源的添加
这一步比较简单,使用add_source函数。
void add_source ( int N, float * x, float * s, float dt )
{
int i, size=(N+2)*(N+2);
for ( i=0 ; i<size ; i++ ) x[i] += dt*s[i];
}
用户输入的源(source)或力(force)被储存在 s[ ] 中,那么把这些状态直接加到新一帧的对应属性 x[ ] 即可。至于乘以dt也就是因为使用了splitting的方法,并不是冲量..下同。
2、扩散(diffusion)
上面已经处理了外部输入源的情况。对于接下来的扩散步骤(烟雾的自发扩散)。根据N-S方程,我们知道扩散项为 k · ∇^2 u