【问题标题】:kd-tree construction very slowkd-tree 构建速度很慢
【发布时间】: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% 的正确率,但您无法区分。

标签: c++ sorting kdtree


【解决方案1】:

我看到两个可能的问题:

  1. 将向量作为值传递给函数(这实际上复制了整个向量)
  2. 为越来越大的元素创建新向量,而不是一些就地处理

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

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

【讨论】:

  • 非常感谢。现在运行流畅。你能验证我的实现是正确的吗?我不太确定是否可以将这些 Node 和 Leaf 对象作为参考传递。他们会超出范围吗?
  • @puelo 是的,你是对的,它们会超出范围。如果没有看到 KDTreeNode 类,很难说什么,但标准解决方案是使用 new 在堆上创建它们,然后再使用指针。
猜你喜欢
  • 1970-01-01
  • 2021-09-01
  • 2011-07-05
  • 2013-12-29
  • 2014-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多