kd树的构建非常缓慢

kd-tree construction very slow

本文关键字:非常 缓慢 构建 kd      更新时间:2023-10-16

我正试图为我的C++(DirectX)项目实现一个kd树,以加快冲突检测速度。我的实现是一个非常原始的递归函数。nth_element似乎工作正常(如果我把它注释掉,只差1帧/秒)。我不太确定罪魁祸首是从哪里来的。

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树。我如何确定它们属于哪片叶子?因为在施工时,我只使用中心位置,而不是它们的实际直径?那我该怎么办?感谢

编辑:我已经实现了所有建议的更改,现在运行得很好。谢谢以下是我所做的:

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));
}

正如你所看到的,我不再复制向量,我也传递左和右子作为参考,这样它们就不会被复制。

我看到两个可能的问题:

  1. 将向量作为值传递给函数(这有效地复制了整个向量)
  2. 为更小和更大的元素创建新的矢量,而不是一些就地处理

基本上,该函数为kd树的每个级别复制初始向量中的所有球两次。这应该会导致一些严重的速度减慢,所以尽量避免请求太多内存。

解决它的一种方法是直接访问向量的数据,使用nth_element等,并且只将子向量的索引传递给递归调用。