毕业即失业,想学习点知识,看到了皮露露可不可的视频和Unity | 流体模拟 - Navier Stokes - 为什么不开大的文章 - 知乎
看到大佬们做的效果见猎心喜,故而开始学习,在此记录一下权做学习笔记。
(资料图)
由于流体模拟方程对我来说研究之后除了增加了一点点数学常识并没能对这个工程的理解有所帮助,所以这里大概是这怕文章中唯一一次提到这个公式了。
案例中流体的模拟是基于速度场的将整个图片划分网格通过速度场来对图片的像素进行采样,在Unity中创建一张2D贴图,每一个像素都是一个关于颜色的四维向量,我们采取颜色向量的前两个值作为速度向量来对每个像素的速度进行描述。这样就可以通过片元着色器对速度场的变化进行模拟了。
按照常规思维在模拟的时候应该将当前像素的速度和时间相乘计算新的坐标并将当前点的速度写入新坐标中,由于使用Unity的片元着色器对速度场进行模拟,片元着色器只能写入当前像素的值,所以采用另一种方法同样算出移动距离后从反方向的地方获取像素的速度并将其写入当前像素。
但是这样做的话模拟精度似乎会有很严重的损失。在实验中若不对速度场进行插值处理,速度场在边界处似乎无法流动。
在C#脚本中声明了两组RenderTexture,并在start中进行初始化,贴图vel用于储存速度场,col则是对图像进行流动模拟所用。div则储存散度场。
由于模拟是基于GPU的体现在Unity则是使用片元着色器(像素着色器)。所以需要通过shader进行实现shader是在材质上进行工作所以需要为其创建“simMat”模拟材质来进行模拟。C#脚本若无特殊说明将运行在updata中,代码将会每帧执行一次。
由于在Unity的学习中通常使用UPR管线所以在学习时也尝试在UPR的工程中进行还原,个人代码将会以注释的形式进行标注
在C#脚本中将用于储存速度场的贴图vel0和平流速度系数传入shader中进行计算则会运行shader中的相关pass并将运算结果存如vel1中,在最后交换vel1和vel0这样在下一帧时将基于上一帧的结果进行运算
在shader中顶点着色器将uv为当前像素LRTB分别为上下左右相邻的像素
dt是unity_的宏定义,tex2d()用于对贴图进行采样,通过对当前uv进行采样获得速度并将其乘以时间获得距离,再通过距离即可找到应移动到此点的速度值。将其写入当前像素
通过使用pass1进行速度扩散处理
此处为粘性扩散,意为将速度扩散至周围的像素,因为前文提到的缺陷无此方法则速度场无法流动,此处采用了插值法对自己和周围的像素采样后取平均值,但是我未能理解为何为当前像素赋予与帧时间相关的权重,以至于在处理中当前像素将会是一个很小的权重(似乎与内能损耗相关?)
完成这部分速度场就可以进行流动,以下为我复刻的代码。
标签: