【发布时间】:2013-12-09 19:56:37
【问题描述】:
我正在尝试为我的 C++ (DirectX) 项目实现一个 kd-tree,以加快我的碰撞检测。 我的实现是一个非常原始的递归函数。 nth_element 似乎工作正常(如果我将其注释掉,则只有 1 fps 的差异)。我不太确定它的罪魁祸首来自哪里。
KDTreeNode Box::buildKDTree(std::vector<Ball> balls, int depth) {
if (balls.size() < 3) {
return KDTreeNode(balls[0].getPos(), KDTreeLeaf(), KDTreeLeaf());
}
Variables::currAxis = depth % 3;
size_t n = (balls.size() / 2);
std::nth_element(balls.begin(), balls.begin() + n, balls.end()); // SORTS FOR THE ACCORDING AXIS - SEE BALL.CPP FOR IMPLEMENTATION
std::vector<Ball> leftSide(balls.begin(), balls.begin() + n);
std::vector<Ball> rightSide(balls.begin() + n, balls.end());
return KDTreeNode(balls[n].getPos(), this->buildKDTree(leftSide, depth + 1), this->buildKDTree(rightSide, depth + 1));
}
我已经覆盖了 Ball 类中的 bool 运算符:
bool Ball::operator < (Ball& ball)
{
if (Variables::currAxis == 0) {
return (XMVectorGetX(this->getPos()) < XMVectorGetX(ball.getPos()));
} else if (Variables::currAxis == 1) {
return (XMVectorGetY(this->getPos()) < XMVectorGetY(ball.getPos()));
} else {
return (XMVectorGetZ(this->getPos()) < XMVectorGetZ(ball.getPos()));
}
}
我很确定这不是实时处理构造的最佳方式。 也许你可以帮助我走上正轨。
还有一件事我真的很想知道:假设我在场景中有很多球体并且我使用了 kd-tree。我如何确定它们属于哪个叶子?因为在施工时我只使用中心位置,而不是它们的实际直径?那我该怎么办呢? 谢谢
编辑:我已经实施了所有建议的更改,现在运行良好。谢谢! 这是我所做的:
KDTreeNode Box::buildKDTree(std::vector<Ball>::iterator start, std::vector<Ball>::iterator end, int depth) {
if ((end-start) == 1) {
return KDTreeNode(balls[0].getPos(), &KDTreeLeaf(), &KDTreeLeaf());
}
Variables::currAxis = depth % 3;
size_t n = (abs(end-start) / 2);
std::nth_element(start, start + n, end); // SORTS FOR THE ACCORDING AXIS - SEE BALL.CPP FOR IMPLEMENTATION
return KDTreeNode(balls[n].getPos(), &this->buildKDTree(start, (start+n), depth + 1), &this->buildKDTree((start+n), end, depth + 1));
}
如您所见,我不再复制向量,并且我还将左右子元素作为参考传递,因此它们不会被复制。
【问题讨论】:
-
您可以尝试std::nth_element 而不是排序。这两部分不会被完美排序,但你的 kd-tree 不需要它。您感兴趣的一个元素在正确的位置,任何较低的元素都将在下半部分。这才是你真正关心的。
-
遗憾的是这并不能解决我的问题。我的帧率稍微好一点,但我仍然无法移动相机等(1.24fps)。我想我的主要问题是我必须比较对象或者 XMVectorGetX 等。不太确定。我也许可以只将位置存储在向量中并进行比较。
-
我很愚蠢。不是那种会减慢它的速度。它必须是不同的东西。我刚刚评论了它,它仍然很慢(只有 1 fps 好)。
-
在使用
nth_element并删除所有这些副本之后,下一个明显的优化将不是在每一帧都运行带有碰撞检测的树构造和模拟,而是将它放在另一个异步运行模拟的线程中在大约 10 帧的间隔上。在渲染线程中的动画的两个模拟状态之间进行插值。这样您就可以避免这些计算停止渲染。屏幕上显示的内容只有 99% 的正确率,但您无法区分。