我刚刚了解到编译器巧妙地将函数和变量的调用替换为它们代表的代码。考虑到这一点,第二种方法实际上会在下面更好(由于清晰度),实际上运行速度与第一种方法一样快?
//check to see if sphere intersects the box
bool BoundingBox::Intersects(BoundingSphere boundingSphere)
{
// check for intersection on each axis by seeing if the radius is large enough to reach the edge of the cube on the
// appropriate side. All must evaluate to true for there to be an intersection.
return (
((boundingSphere.Centre().x < negCorner.x && boundingSphere.Radius() > posCorner.x - boundingSphere.Centre().x) ||
(boundingSphere.Centre().x > posCorner.x && boundingSphere.Radius() > boundingSphere.Centre().x - negCorner.x))
&&
((boundingSphere.Centre().y < negCorner.y && boundingSphere.Radius() > posCorner.y - boundingSphere.Centre().y) ||
(boundingSphere.Centre().y > posCorner.y && boundingSphere.Radius() > boundingSphere.Centre().y - negCorner.y))
&&
((boundingSphere.Centre().z < negCorner.z && boundingSphere.Radius() > posCorner.z - boundingSphere.Centre().z) ||
(boundingSphere.Centre().z > posCorner.z && boundingSphere.Radius() > boundingSphere.Centre().z - negCorner.z)));
}
第二种方法:
//check to see if sphere intersects the box
bool BoundingBox::Intersects(BoundingSphere boundingSphere)
{
bool xIntersects, yIntersect, zIntersects;
xIntersects =
((boundingSphere.Centre().x < negCorner.x && boundingSphere.Radius() > posCorner.x - boundingSphere.Centre().x) ||
(boundingSphere.Centre().x > posCorner.x && boundingSphere.Radius() > boundingSphere.Centre().x - negCorner.x)));
yIntersects =
((boundingSphere.Centre().y < negCorner.y && boundingSphere.Radius() > posCorner.y - boundingSphere.Centre().y) ||
(boundingSphere.Centre().y > posCorner.y && boundingSphere.Radius() > boundingSphere.Centre().y - negCorner.y)));
zIntersects =
((boundingSphere.Centre().z < negCorner.z && boundingSphere.Radius() > posCorner.z - boundingSphere.Centre().z) ||
(boundingSphere.Centre().z > posCorner.z && boundingSphere.Radius() > boundingSphere.Centre().z - negCorner.z)));
return (xIntersects && yIntersects && zIntersects);
}
答案 0 :(得分:8)
无法保证您的预期行为 - 编译器必须非常聪明才能确定在返回结果之前不必计算所有 x / y / z的条件
在第一个版本中,您知道您将在第一次失败的测试中返回。我坚持使用它,并对代码进行评论和格式化以使其更清晰。
答案 1 :(得分:1)
首先,这不是一个准确的球体与盒子检查。它本质上是一个破碎的(当球体中心包含在盒子中时它不会报告交叉点!)盒子与盒子围绕球体测试。如果你想做正确的话,请寻找Arvo的算法。
但回到你的问题:如果存在可测量的速度差异,并且我怀疑存在,那么它肯定与内联无关,而是与两个函数的略微不同的语义有关。第一个函数通过&&
运算符对其顶层进行延迟评估。因此,如果您在第一个轴上得到负面结果,它将会突然出现而不会测试其他轴。当您在该轴或第二轴上有足够的负面结果时,这可能会让您在非常慢的计算机上获得速度优势。
第二个功能不会检查您是否在先前的轴上得到否定答案。结果,它将始终测试所有三个。现在,在一台体面的计算机上这可能会更快,因为它不必等待第一次检查的结果来确定它是否可以执行接下来的检查。因此,这通常会减少分支错误预测,这通常比仅仅执行两个分支的工作更快。
然后,优化器可能非常聪明,可以确定它可以执行&&
运算符另一侧的表达式而没有副作用。内联(显式或通过链接时代码生成)实际上在这里扮演一个小角色 - 因为优化器需要查看Centre
和Radius
函数实际执行的操作。
但唯一确定的方法是查看生成的代码并对其进行基准测试!
答案 2 :(得分:1)
我认为这两者的组合。您想要检查xIntersects && yIntersects && z Intersects
,因此请将它们各自作为自己的功能。像这样:
bool BoundingBox::Intersects(BoundingSphere boundingSphere)
{
return XIntersects(boundingSphere) && YIntersects(boundingSphere) && ZIntersects(boundingSphere);
}
bool BoundingBox::XIntersects(BoundingSphere boundingSphere)
{
return ((boundingSphere.Centre().x < negCorner.x && boundingSphere.Radius() > posCorner.x - boundingSphere.Centre().x) ||
(boundingSphere.Centre().x > posCorner.x && boundingSphere.Radius() > boundingSphere.Centre().x - negCorner.x));
}
bool BoundingBox::YIntersects(BoundingSphere boundingSphere)
{
return ((boundingSphere.Centre().y < negCorner.y && boundingSphere.Radius() > posCorner.y - boundingSphere.Centre().y) ||
(boundingSphere.Centre().y > posCorner.y && boundingSphere.Radius() > boundingSphere.Centre().y - negCorner.y));
}
bool BoundingBox::ZIntersects(BoundingSphere boundingSphere)
{
return ((boundingSphere.Centre().z < negCorner.z && boundingSphere.Radius() > posCorner.z - boundingSphere.Centre().z) ||
(boundingSphere.Centre().z > posCorner.z && boundingSphere.Radius() > boundingSphere.Centre().z - negCorner.z));
}
您可以获得第一个的速度和第二个的清晰度,优化编译器甚至可以优化函数调用。