Я пытаюсь реализовать kd-дерево для моего C ++ (DirectX) проекта, чтобы ускорить обнаружение столкновений.
Моя реализация — действительно примитивная рекурсивная функция. Элемент 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));
}
Я переписал оператор bool в классе Ball:
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));
}
Как вы видите, я больше не копирую векторы, а также передаю левый и правый дочерние элементы в качестве ссылки, чтобы они не копировались.
Я вижу две возможные проблемы:
По сути, функция дважды копирует все шары в исходном векторе для каждого уровня вашего kd-дерева. Это должно вызвать серьезное замедление, поэтому старайтесь не запрашивать слишком много памяти.
Одним из способов решения этой проблемы является прямой доступ к данным вектора, использование nth_element
и т. д. и передают только индексы субвекторов в рекурсивный вызов.
Других решений пока нет …