kd-tree строительство очень медленное

Я пытаюсь реализовать kd-tree для своего проекта 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-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));
}

Как вы можете видеть, я больше не копирую векторы, и я также передаю левый и правый дочерние элементы в качестве ссылки, чтобы они не копировались.


person puelo    schedule 08.12.2013    source источник
comment
Вы можете попробовать std :: nth_element вместо сортировки. Две половинки не будут отсортированы идеально, но вам это не нужно для вашего kd-дерева. Один элемент, который вас интересует, находится в правильном месте, а все, что ниже, будет в нижней половине. Это действительно все, что вас волнует.   -  person Damon    schedule 09.12.2013
comment
К сожалению, это не решает мою проблему. Моя частота кадров стала немного лучше, но я все еще не могу двигать камеру и т. Д. (1,24 кадра в секунду). Думаю, моя основная проблема в том, что мне нужно сравнивать объекты или, может быть, XMVectorGetX и т. Д. Не совсем уверен. Возможно, я мог бы сохранить только позиции в векторе и сравнить их.   -  person puelo    schedule 09.12.2013
comment
Я глупый. Это не из тех, кто его замедляет. Это должно быть что-то другое. Я просто закомментировал это, и он все еще был очень медленным (только на 1 кадр в секунду лучше).   -  person puelo    schedule 09.12.2013
comment
дерево kd CGAL   -  person gongzhitaao    schedule 09.12.2013
comment
Как выглядит ваш узел? Вы действительно копируете в него все данные вместо использования указателей?   -  person Jaa-c    schedule 09.12.2013
comment
Вы создаете копии данных на каждой итерации (leftSide и rightSide). Вместо этого используйте итераторы. Это (в сочетании с nth_element) значительно ускорит его.   -  person gvd    schedule 09.12.2013
comment
@ Jaa-c, если я использую ссылку в классе Node для левого и правого дочерних элементов, они не выйдут за пределы области видимости, как только я закончу построение дерева? Смотрите мою правку.   -  person puelo    schedule 09.12.2013
comment
После использования nth_element и исключения всех этих копий следующая очевидная оптимизация будет заключаться не в том, чтобы запускать построение дерева и моделирование с обнаружением столкновений каждый кадр, а в том, чтобы поместить его в другой поток, который запускает моделирование асинхронно с интервалом примерно в 10 кадров. Интерполируйте между двумя смоделированными состояниями для анимации в потоке рендеринга. Таким образом вы предотвратите остановку рендеринга этими вычислениями. То, что отображается на экране, будет правильным только на 99%, но вы не заметите разницы.   -  person Damon    schedule 09.12.2013
comment
Спасибо за эту информацию @Damon. Я учту это!   -  person puelo    schedule 09.12.2013


Ответы (1)


Я вижу две возможные проблемы:

  1. Передача вектора функции в качестве значения (это эффективно копирует весь вектор)
  2. Создание новых векторов для более мелких и крупных элементов вместо некоторой обработки на месте

По сути, функция дважды копирует все шары в исходном векторе для каждого уровня вашего kd-дерева. Это должно вызвать серьезное замедление, поэтому постарайтесь не запрашивать такой объем памяти.

Один из способов решить эту проблему - получить прямой доступ к данным вектора, использовать nth_element и т. Д. И передать рекурсивному вызову только индексы подвекторов.

person Sigroad    schedule 09.12.2013
comment
Большое спасибо. Сейчас все идет гладко. Можете ли вы проверить правильность моей реализации? Я не совсем уверен, могу ли я передать эти объекты Node и Leaf в качестве ссылки. Они выйдут за рамки? - person puelo; 09.12.2013
comment
@puelo Да, вы правы, они выйдут за рамки. Трудно что-либо сказать, не видя класса KDTreeNode, но стандартным решением было бы создать их в куче с помощью new и использовать указатели позже. - person Sigroad; 09.12.2013