我在这里有这个SphereInFrustrum函数:
0.49% int FrustumG::sphereInFrustum(Vec3 &p, float radius) {
int result = INSIDE;
float distance;
2.40% for(int i=0; i < 6; i++) {
7.94% distance = pl[i].distance(p);
12.21% if (distance < -radius)
0.67% return OUTSIDE;
3.67% else if (distance < radius)
result = INTERSECT;
}
return(result);
}
这些数字来自我的代码分析器。问题在于,此检查比实际渲染花费的时间更长。实现几何剔除的全部意义在于我可以拥有非常大的水平。我真的只需要一种非常快速和肮脏的方式来查看AABB是否进出。现在我提供了立方体和中心的半径。鉴于我的盒子是AABB,有没有更快的方法呢?我赞成速度超过准确性。
由于
如果我提供了立方体的最小值和最大值会使它更快?我确信必须有一种方法可以在没有距离公式的情况下使用费用平方根;
float Plane::distance(Vec3 &p) {
return (d + normal.innerProduct(p));
}
float Vec3::innerProduct(Vec3 &v) {
return (x * v.x + y * v.y + z * v.z);
}
答案 0 :(得分:1)
我想留下评论来提问,但我似乎只能留下答案,这只是一个观察:
这段代码真的能做你想做的吗?
int result = INSIDE;
float distance;
2.40% for(int i=0; i < 6; i++) {
7.94% distance = pl[i].distance(p);
12.21% if (distance < -radius)
0.67% return OUTSIDE;
3.67% else if (distance < radius)
result = INTERSECT;
这个函数如何读取给我的是,假设球体在里面,对于你的截头上的每一个点i,取i和球体p的中心之间的距离,如果这个距离小于负半径...这里我的范例被破坏了。
如果您的负距离小于负半径,那么这会提早返回?那真的是你想要的吗?
答案 1 :(得分:1)
您是否真的为每个球体执行此代码?如果你这样做,难怪它的速度会慢一些。
您应该使用分层方法,它可以在一次调用中剔除整个场景部分。例如,您可以使用四维球体。
答案 2 :(得分:0)
一些想法(按复杂程度增加的顺序)
Elimintate branches - 计算所有6个距离并根据它们的最小值返回可能更快(取决于平台和编译器)。例如。在PowerPC上,可以使用minDist = (d < minDist) ? d : minDist
指令计算fsel
并避免分支。
展开(第一部分) - 展开所有六个平面的循环可能会让编译器更好地优化代码(通过隐藏指令延迟)。
展开(第二部分) - 您可以同时处理多个球体吗?同样,您可能能够隐藏一些延迟。
SIMD - 如果你不介意用SIMD弄脏手,你可以将3个飞机的“转置”存储在4个四边形中。这使您可以更轻松地计算点积,而无需执行“水平”SIMD操作。象征性地,这看起来像
vec4 sphereX = sphere.splat(0);
vec4 sphereY = sphere.splat(1);
vec4 sphereZ = sphere.splat(2);
vec4 dot = sphereX * planesX; // planesX is the x components of 3 planes
dot += sphereY * planesY;
dot += sphereZ * planesZ;
dot += planesDistance;
// dot now contains the results of 3 distances
// now do the same for the other 3 planes
实际的SIMD代码取决于平台和编译器。
还有一些方法可以对kd-tree进行截锥体查询(即MLRTA) - 我从来没有尝试过它们,但它应该大大减少你需要查询的球体数量。
希望有所帮助,如果有什么不清楚,请告诉我。