原标题:[蛮牛译馆]使用Box2D进行流体渲染
这是一篇关于我如何在我的游戏“入侵液体狙击手”中实施流体渲染的技术文章,这是我在GameDev.net上参加第五届年度“令人敬畏的周之星”游戏开发大赛。
我收到的关于游戏的最大的赞美之一是人们认为流体模拟是某种软体物理或真正的流体模拟。 但是不是!
使用Box2D通过使用许多小(非旋转)圆形体进行常规的硬体碰撞来实现模拟。 在渲染中实现了软体颗粒的幻觉。
渲染过程
每个粒子使用中心不透明的白色圆圈纹理绘制,但在圆周处渐渐变得完全透明:
这些被绘制到RGBA8888离屏纹理(使用OpenGL语法中的“framebuffer”),并且我将色彩映射到粒子的预期颜色(着色是LibGDX可以使用其默认的功能着色器)。
绘制每个球比在Box2D中表示的球大得多是至关重要的。 从物理上说,这些球不会重叠(因为它毕竟是一个硬体模拟!),但在渲染中,我们确实需要这些球重叠并融合在一起。
混合是不重要的,因为我们必须考虑到一些要求:
当不同颜色的颗粒重叠时,RGB颜色通道应该混合在一起。
但我们不希望颜色饱和白色。
当我们与最初的黑色背景颜色混合时,我们不希望它们变暗。
α通道应积累,以表示每个像素处液体的“强度”。
所有这些都可以在GLES2.0中使用这种混合技术实现:
把所有的一切混合使我们有一个模糊的彩色球的纹理:
接下来,是使用自定义着色器将这个作为全屏四面体作为主后挡板。
着色器将纹理的alpha通道视为“潜在字段”,值越高,该字段在该片段越强。
着色器将字段的强度与阈值进行比较:
在这个场强足够强的情况下,我们将把这个阿拉伯数字化到1.0来表现出一些液体。
在场强太弱的地方,我们会将阿拉伯数字的值扣除为0.0(或者我们可以丢弃该片段),以避免绘制任何东西。
在最后的游戏中,我进一步深入,还包括一个围绕该阈值的小窗口,以在alpha通道中平滑地混合0和1之间,这软化并有效地消除了流体边界的别名。
这是着色器:
这给我们一个坚实的边缘边界,其中像素是流体或不被液体点燃。
这是我们应用着色器后的结果:
现在看起来更像液体一样!
这种工作方式是当粒子彼此靠近时,它们的潜在领域开始相加; 一旦场强足够高,着色器将开始点亮两颗粒子之间的像素。 这给了我们“凝聚在一起”的效果,这真的使它看起来像一个流体。
由于流体由成千上万的圆形构成,所以倾向于将间隙留在直边瓦片上。 因此,全屏四分之一实际上是放大到比屏幕稍大一些,并且在主要场景元素之后。 这有助于确保液体真正填满任何角落和缝隙。
这是我们最后的结果:
所有背后的技术都是最基础的知识
额外的要点
我做了一些其他微妙的技巧,有助于使液体更可信...
每个粒子具有年龄和当前速度。我将这些一起加在一起,用于减轻颗粒颜色的0和1之间的“泡沫因子”值。这意味着更年轻或更快速移动的颗粒比流体的较旧或固定部分更白。这个想法是让我们能够将颗粒混合成更大体积的液体。
与流体颗粒相比,流体收集的固定“井”总是稍微较暗。这保证了当它们落入井中时,我们可以看到颗粒的混合。
岩浆颗粒都是在产卵时随机选择的不同深红色。这开始是一个错误,其中岩浆和油颗粒被意外混合在一起,但它看起来很酷,我决定让它发生故意!
当我从模拟中删除一个粒子时,它不会弹出存在,而是将其淡出。这被“潜在的领域”着色器进一步伪装,使其看起来像流体排水管或更自然地收缩。所以,整体而言,褪色是不可直接观察到的。
性能优化
正如我在游戏中所提到的那样,我不得不花费一些时间来使CPU和内存模拟器成为模拟器:
接收流体的“井”真的只是“填满”的彩色矩形。他们没有模拟。这意味着我们可以从模拟中清除颗粒,一旦它们被井捕获,并且只需要增加井的填充水平。
如果颗粒减慢到低于阈值,那么它们变成非移动的静态体。静态不完全是流畅的,但是Box2D比数千动态体在表现上要好很多,因为它们对力不响应。我也在这个时候触发他们的衰落,所以他们不会在这个状态下长时间呆在玩家注意的地方。
所有颗粒将最终腐烂。我设置了20秒的最大寿命。这也是为了防止玩家欺骗关卡,欺骗自己的游戏方式。返回搜狐,查看更多
责任编辑: