首页 > 解决方案 > 计算着色器中与体素世界的粒子碰撞

问题描述

我在我正在开发的体素游戏中添加了一个粒子系统。目前,所有物理都在 CPU 上完成,而且速度非常慢(我的 CPU 与 2000 个粒子作斗争)。

对于每个粒子,我确定它理论上可以碰撞的体素范围(基于粒子的位置和速度以及经过的时间),然后检查与该范围内的所有体素的碰撞并使用最近的碰撞。

为了提高性能,我正在探索是否可以使用计算着色器来执行物理。

如果我将我的体素世界转换为位数组并将其放入 SSBO 中,那么计算着色器将拥有执行碰撞检测所需的所有几何信息。然而...

我为 CPU 编写的碰撞检测代码在 GPU 上根本不会高效;有很多分支/循环。有没有一种有效的方法让粒子在计算着色器上与体素网格碰撞?

标签: openglopengl-4compute-shader

解决方案


为简化起见,将您的粒子视为仅具有位置 P 和速度 V 单位/tick 的点状对象。不是精确计算您的粒子将接触哪些体素,粒子运动的第一个近似值可能只是检查 P + V 是否被固体体素占据(使用 3D 采样器),并将 V 设置为零(或设置为本身)如果是这种情况,否则将 P 增加 V。这些条件运算可以通过整数算术有效地完成,不需要分支。

如果这个近似值太粗略,因为 V 通常是多个体素单位长,并且因为您的体素几何结构足够精细,这可能会导致粒子穿过实心墙,您可以简单地在着色器中重复上述操作 N 次,使用 V /N 而不是 V,其中 N 应该是使剪辑在大多数情况下停止的最小常量整数。恒定长度的 for 循环将由着色器编译器展开,因此您仍然不需要真正的分支。

现在使用此算法,您的粒子的行为将是一旦它们到达障碍物就会停止所有(或大部分)运动。如果它们受到重力的影响(最好也在着色器内部完成),它们将直接向下坠落,但只有在失去垂直速度之后。如果他们到达一个楼层,他们将留在原地。

如果你想让你的粒子滑过水平表面而不是停在它们着陆的地方,并在撞击墙壁时保持它们的垂直动量,你可以将 V 分成水平和垂直分量,并对这两个分量分别执行上述步骤。

您还可以选择分离 V 的所有三个坐标,因此以对角线水平运动撞击墙壁的粒子将跟随墙壁而不是直接下降,但与两个组件相比,性能损失可能超过好处。


推荐阅读