查看原文
其他

高中生也能整出高性能并行的流体仿真程序?ZENO:我想给你“整”个世界

张心欣 CG世界 2022-05-24

点击上方蓝字CG世界关注我们

“ 感知技术 · 感触CG · 感受艺术 · 感悟心灵 ”
中国很有影响力影视特效CG动画领域自媒体


作者:张心欣

本文经作者授权发布


今天为大家带来的是一个用节点系统拖拽出来的流体仿真算法(局部)。


泽森自研的可视化编程框架已经到了一个比较完善的版本, 我们可以开始用这个代码框架将我们所有的基础解算算法重新实现为可以被可视化运用的“节点”, 并成功的用这些“节点”实现了一个复杂的流体仿真算法, 所以终于有时间来与大家分享一下我们对可视化编程的理解以及这样的可视化编程系统, 到底有多大的威力。


首先我们先来看一看传统的软件界面:



注:此处没有踩的意思, 只是想表达一下这是一个大家传统观念中的“软件”, 打开有一个界面, 上面有一些目录和按钮, 每个按钮对应着一种功能, 而一个软件就是这样这些功能的“集合”了。能干什么, 不能干什么, 一眼望到了边。新的功能也只能等待软件大版本的更新。


然而这个世界上, 有一些更先进的软件系统, 比如Houdini, UE(虚幻引擎), 他们依靠自己强大的“节点”和“蓝图”系统。


Houdini的节点系统


UE的蓝图系统


让用户在作为软件使用者的同时, 也成为了软件的“创造者”, 这样的软件系统, 借助“节点”来封装“积木”,并允许用户使用连线和拼接的方式来组合这些“积木”,从而让这些软件能够做到“开发者都没有想到”的任务及功能。


这样的画图方式, 实际上就是一种“编程”。而这样的编程, 有一种更加应该被人熟知的名字:“可视化编程”。所得到的图形,实际上就是“程序”。而软件需要能够在运行时理解并执行用户所“编写”的程序, 就需要实现一套自己的“解释器”。


泽森科工在进行高性能物理解算分析系统研发的过程中, 遇到了大量制约生产力的问题:比如随着软件功能的增长, 特别是功能与功能之间的交互与耦合程度的增加, 一个交互式软件出现bug和crash的机会也变得越来越大, 随着功能的更新迭代, 一个“固定功能”的软件需要被重新编译, 重新加载的次数也越来越多。更加的,在面对具体问题中无穷无尽的变化和算法更新的情况下, 一个固定功能的系统,将越来越难满足用户与日俱增的变化的需求。越来越难满足用户不同的, 各种各样的问题。


于是, 我们打算自己打造一个可视化编程的底子。我们要让一个软件在被运行后才编程出自己要干什么。有这个想法, 是今年的开年。


一个可视化编程系统谈何容易。但是他意味着我们将可以扔掉无数个按钮, 意味着我们可以更轻装上阵, 意味着整个软件在被开发完后将可以千变万化。意味着无数的可能。但也意味着我们需要搞出自己的脚本语言系统以及解释器, 意味着我们需要设法把对于节点运算算法的编程和最后的UI交互解耦开来, 意味着我们需要做很多我们曾经不关注的事。


然而现在我们发现: 真香。



现在, 打开这个节点系统, 他长这样:什么?怎么什么也没有?


莫急, 道家所谓:无为而治。


佛家所谓,诸相皆空。


没有,才是所有。


记得我曾说过, 我要这个软件的功能和执行的任务, 是在它打开了以后才被编程实现的。


那么假设我想读取一个文件, 我该怎么办呢?


只需要创建一个读取文件节点,并填入文件地址即可,然后, 我们可以对该三维数据文件进行一个可视化, 为此, 我们只需要将其挂载到一个可视化节点:



然后选中该可视化节点并点击“执行该计算图”, 可视化窗口就会按照用户定义的这个操作来执行运算, 实际上的自动化导出脚本为:



随后, 软件的主循环逻辑就会解释并执行这一段“用户定义的”脚本,并按照该脚本定义的内容来执行程序。


值得指出的是, ZENO是一套为了偏微分方程求解而设计的框架, 所以它是以 subTimeStep为单位的, 脚本图里的每一个指令都默认地会在每个substep进行运算。也就是说当前可视化的每一帧, 都会先做一下文件的读取, 再做一下文件的可视化。


为此, 我们特别定义了RunOnce节点来进行效率优化:


通过RunOnce的定义, 用户将可以让相关节点只在计算图开始执行时执行一次。从而节省每个frame的计算资源(在一个文件有几个G时就体现出来了 :) 


当然, 一个强大的节点系统, 可以做的当然不止如此。


事实上, 通过这样的节点系统, 通过“托拉拽”的方式, 就实现“任何”的算法。


比如上图中, 我们通过读取几何文件->将几何文件转换为SDF(符号距离场)->以这个符号距离场为依据生成采样粒子->对粒子进行可视化


编辑这样一个流程将原来的三维文件转化为一堆包含于其内的粒子(想输出成文件怎么办? 再挂载一个文件写出节点)


值得注意的是, 目前的软件, 它是优美且简约的, 是没有任何多余的按钮或对话框供用户点击的(也没有任何多余的按钮需要用户点击), 你要做什么, 由你自己定义, 只需要连线堆图即可. 某种意义上讲, 这个软件所执行的程序是直到用户点击了"执行该计算流程图"时, 才被编程完毕的。


同样的, 方才的执行图由计算机自动导出的脚本代码为:


该脚本也会被软件的内在循环逻辑用zengine自动解析执行, 从而执行用户所定义的任务。


这样的功能, 还只不过是节点系统的冰山一角。使用这个节点框架, 我们将自己的高性能物理解算器的逐个部件实现成了节点, 并最终在这个“画图系统”中, 用连线画图的方式连出了一个“世界上最高性能的流体仿真解算器”。(在运行同样的场景的设置下我们比Houdini最新的解算器的计算效率要快4倍)



它不但是高性能的(由于我们的后端实现),而且是高度自由化, 高度定制化的, 用户可以选择性的使用以及省略具体的步骤, 甚至对一个frame的substep的自适应的dt来进行编程。


在这个案例中, 我们使用一个猪头作为emitter,并使用紫金钵盂作为它的边界,来demo这个用节点拉出来的解算器,相关设置emitter和边界固体的“代码”如下,一路文章读下来,大家应该能明白这几个高亮节点的含义。



值得指出的是, 在整个流体解算器的“编程”过程中, 可视化编程系统本身也起到了巨大的作用, 比如我们可以很容易地对任意一个计算步骤的结果进行可视化或者导出,从而帮助我们理解我们的代码那里出错了,大大节约了效率。它不仅仅是一个解放生产力工具, 更是一个发展生产力的工具。


第一次运行这个解算器时, 我们得到了一个错误的结果:



我们注意到这个碗漏水了。


随后, 我们通过自适应时间步长调整了积分的方案, 这样的调整, 只需要连几条线就能完成:


我们把一个CFL节点挂载到积分时间步之前


由于我们采用的都是无条件稳定的数值格式, CFL其实不影响数值稳定性, 不过它在一定程度上影响到碰撞、穿透等现象的发生。所以我们用了2*CFL来作为自适应的积分步长。



这一次, 我们得到了正确的结果。


会看实拍的过程录像, 我们也会发现使用了CFL条件的仿真, 在水流速度过快的时候会自动运行很多子步骤来解算一个frame, 而不使用CFL的仿真不使用子步骤, 虽然计算很快, 却发生了穿透。


使用CFL的Simulation


不使用子步的运行


至此为止, 我仅仅是展示了我们自研的这套可视化编程系统的操作与使用展示。


那么, 我们之所以称之为一个“可视化编程系统”的框架, 它, 框在哪呢?实际上, 在include了我们的头文件后, 要实现一个节点扩展所需要的“除了算法代码”外的代码量是“少得可怜”的。比如:



只需要写这么一段代码, 然后编译, 这个“节点”就能在编辑器里看到啦!所有的有关节点的类型注册, 描述生成, 绘制, 参数匹配检测,节点系统产生的参数的内存管理。。。等等等, 都是“自动化的”(也是这个framework大量工作所在。。。。)


美好的时光总是短暂的, 又到时间讲拜拜。


我们的发展壮大, 需要更多志同道合的兄弟加入我们,凡是在 物理解算算法, 高性能GPU运算, 分子动力学, C++和编辑器开发,实时图形可视化, UI开发等方面有卓越能力的你还请不吝戳我私信(以及 zhanshinshin@gmail.com, 我们需要在这些方面的卓越人才的加入。


最后, 我要提一下我们ZENO系统的名字的由来。



乐高, 可以得到各种各样的高楼大厦和机器人。


但实际上乐高是这样的:



这些被称为Building Block的东西, 才是乐高的价值, 才是“创造世界”和一个属于“创造者的世界”的价值。


ZENO


LEGO


we don't build solutions, we build building blocks so people can build solutions to anything.


本文首发于知乎专栏GraphiCon图形控,作者张心欣,查看原文请点击“阅读原文”。


—全文完—

A站系统不允许大作低调!刷新N遍都是大图的CG小姐姐!


《指环王》重映了!这些概念图你看过么?


为啥皮克斯的电影剧本总在大气层?


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存