GLSL 中数学运算的计算成本

问题描述 投票:0回答:3

我正在使用 GLSL 着色器编写 GPGPU 程序,并尝试对 N 体碰撞检测算法进行一些优化。一种是执行“快速”检查以确定两个物体是否在同一范围内。这个想法是快速取消许多可能性,这样我只需对少数物体执行更准确的碰撞测试。如果快速检查确定它们有可能发生碰撞,则会执行准确检查。

物体是圆(或球体)。我知道它们的中心位置和半径。快速检查将查看它们的正方形(或立方体)边界框是否重叠:

//make sure A is to the right of and above B
//code for that

if(A_minX > B_maxX) return false;   //they definitely don't collide
if(A_minY > B_maxY) return false;   //they definitely don't collide

if(length(A_position - B_position) <= A_radius + B_radius){
    //they definitely do collide
    return true;
}

我的问题是执行此快速检查(确保 A 和 B 的顺序正确,然后检查它们的边界框是否重叠)的开销是否会比调用

length()
并将其与它们的组合半径进行比较更快.

了解 GLSL 中各种数学运算的相对计算成本会很有用,但我不太确定如何凭经验发现它们,或者这些信息是否已经发布在某个地方。

glsl
3个回答
1
投票

您可以通过比较值的平方来避免使用平方根(

length()
函数隐式需要平方根)。

测试可能如下所示:

vec3 vDiff = A_position - B_position;
float radSum = A_radius + B_radius;
if (dot(vDiff, vDiff) < radSum * radSum) {
    return true;
}

这将其减少回单个测试,但仍然仅使用简单且高效的操作。


0
投票

虽然我们讨论的是成本主题,但这里不需要两个分支。您可以改为测试按组件测试的结果。因此,可以使用

any (greaterThan (A_min, B_max))
将其折叠为单个测试。一个好的编译器可能会解决这个问题,但如果您自己考虑数据并行性,它会有所帮助。

成本都是相对的。 15 年前,完成

length (...)
所做的事情所需的算术工作是这样的,您可以在更短的时间内完成立方体贴图纹理查找 - 在较新的硬件上,您会疯狂地这样做,因为计算比内存更快。

从长远来看,线程分歧可能比指令或内存吞吐量更成为瓶颈。也就是说,如果并行运行的两个着色器调用在着色器中采用不同的路径,则可能会带来不必要的性能损失。底层硬件架构意味着曾经是优化的安全赌注的东西可能不会在未来出现,甚至可能导致您的优化尝试损害性能。


0
投票

在 SIMD 中,“if”操作的成本很高,因为一堆 ALU 总是执行相同的命令。实际情况是,所有分支都被执行,但某些 ALU 忽略结果(其中“if”失败)。

因此,分支比算术运算的成本要高得多。 (顺便说一句,对于具有长管道的 CPU 也是如此 - 例如 Intel、AMD、ARM 等)

在您的情况下,可以通过逻辑操作替换所有分支 - 这会快得多,并且还删除一些测试。

因此很有可能

return length(A_position - B_position) <= A_radius + B_radius ;

如果没有两个额外的“if”语句,实际上会快得多。

在您的情况下,也可以保存 sqrt:

float length2(vec3 a) {
    return dot(a,a)
}

float r = A_radius + B_radius;
return length2(A_position - B_position) <= r*r ;
© www.soinside.com 2019 - 2024. All rights reserved.