微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何并行化基于位置的动力学中的碰撞约束

如何解决如何并行化基于位置的动力学中的碰撞约束

我正在尝试在 OpenCL 中实现 PBD 算法。在 original paper 中,算法被表述为

(1) forall vertices i
(2)     initialize x[i]=x0[i],v[i]=v0[i],w[i]=1/m[i]
(3)endfor
(4)loop
(5)    forall vertices i do v[i]←v[i]+∆t*w*i*f_ext(x[i])
(6)    dampVeLocities(v1,...,vN)
(7)    forall vertices i do p[i]←x[i]+∆t*v[i]
(8)    forall vertices i do generateCollisionConstraints(xi→pi)
(9)    loop solverIterations times
(10)        projectConstraints(C1,CM+Mcoll,p1,pN)
(11)   endloop
(12)   forall vertices i
(13)       v[i]←(p[i]−x[i])/∆t(14)x[i]←p[i]
(15)   endfor
(16)   veLocityUpdate(v1,vN)
(17)endloop

第 8 步是最难高效并行化的。我目前正在做的是使用常规 3D 网格(表示为单个缓冲区),我首先在其中插入所有粒子。接下来我迭代相邻的单元格并检查碰撞。但是当实际检测到碰撞时我该怎么办?我不能保存可变大小的向量,也不能将约束“附加”到缓冲区,因为这需要原子操作,而这些操作不是并行的。在 GPU 上实现 PBD 的一些有效方法是什么?

解决方法

到目前为止我发现这可能是实现这一点的最佳方法 要么

  • 使用 atomicAdd 模拟堆栈,类似于在面部剔除中完成的方式https://vkguide.dev/docs/gpudriven/compute_culling/
  • 为每个线程预分配一个小堆栈,并让每个线程将约束附加到该私有堆栈。然后,您可以在对数时间内有效地将所有这些堆栈连接到一个大型数组中。为了更直观地展示它,请考虑 3 个堆栈,每个堆栈的最大长度为 2
Stack 1: |_|_|  (empty stack)
Stack 2: |A|_|  (stack with one element)
Stack 3: |B|C|  (stack fully filled up to its maximum length)

然后像这样连接这些堆栈

|A|_|_|_|B|C|

现在迭代计算每个元素应该移动多少,这等于它左边(包括)的空元素数。创建第二个缓冲区来保存这些空元素的数量。这个缓冲区的初始状态是

|0|1|1|1|0|0|  (each cell is 0 if it is empty or 1 otherwise)

在第二次迭代中,您对位置 ii+1 处的单元格的值求和,并将结果存储在 i+1 中。

|0|1|2|2|1|0|  (each cell holds number of filled cells up to 2 places to the left,including itself)

在第三次迭代中,您将单元格 ii+2 的值相加

|0|1|2|3|3|2|  (each cell holds number of filled cells up to 4 places to the left,including itself)

在第四次迭代中,您将单元格 ii+4 的值相加

|0|1|2|3|3|3|  (each cell holds number of filled cells up to 8 places to the left,including itself)

现在您知道 A 应该向左移动 0B 向左移动 3C 向左移动 3,到达最终结果

|A|B|C|_|_|_|

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。