Трехмерное обнаружение столкновений: выпуклый корпус против выпуклого корпуса, требуется положение и нормальное положение - PullRequest
12 голосов
/ 06 июля 2019

Я хочу знать приблизительное трехмерное положение и 3D нормаль места столкновения между двумя выпуклыми 3D корпусами (A против B).

CPU в скобках показывает относительное время CPU, необходимое для моей готовой программы.

Часть 1 : Ранний выход (ЦП 1%)

На первом шаге я использую очень дешевый алгоритм - Теорема об отделении .
Например, я использую 15 ось для 2 кубов. (В реальных случаях формы являются более сложными.)
Если существует хотя бы одна ось, которая может разделяться, return "no-collide".
В противном случае сделайте следующую часть.

Часть 2 : вершина против объема (процессор 10%)

  • Проверьте все вершины A - находится ли он внутри B.
  • Проверьте все вершины B - находится ли он внутри A.

enter image description here

Часть 3 : Край против Края (ЦП> 20%)

Есть странный случай, например https://gamedev.stackexchange.com/questions/75437/collision-detection-3d-rectangles-using-sat. Я украл изображение оттуда: -

enter image description here

Таким образом, мне также нужно ребро против ребро .

  • Для каждой пары ребер A & B (12 * 12 = 144 пар) найдите ближайшую точку на ребре A напротив ребра B. Проверьте, находится ли вершина внутри B.
  • (наоборот) Для каждой пары ребер B & A проверьте, находится ли такая вершина внутри A.

Вау, это много вычислений.
Однако это еще не конец.

Проблема

  1. Указанная позиция столкновения не такая точная (слева: текущая, справа: желаемая): -

    enter image description here

    Чтобы решить эту проблему, я подумал о создании новой выпуклой формы = A intersect B.
    Существуют некоторые бесплатные библиотеки C ++ (например, OpenMesh ), но я думаю, что это слишком дорого для процессора.
    Обратите внимание, что мне не нужно, чтобы это было точно правильно.

  2. Он также иногда сообщает о неправильном нормальном (слева: ток, справа: желание): -

    enter image description here

    ^ Эту проблему можно решить, добавив проверку edge (из A) против face (из B), но это сделало бы обнаружение всех столкновений еще более дорогим.

Вопрос

Похоже, что распространенные алгоритмы в Интернете (из которых я копирую) распознают только микрофункцию.
ИМХО, алгоритм вершинный объем / ребро-кромка фокусируется на топологии, а не на том факте, что обе фигуры имеют объем solid .

Какой алгоритм является более точным (1-й приоритет) и, возможно, дешевле?
Мой подход может быть неправильным на уровне фундамента.

Чтобы ускорить процесс, я уже немного обрезал, например. выберите только ту пару ребер A и B, которые расположены близко друг к другу.

Рекомендации: -

Редактировать (10 дней спустя)

Теперь я могу найти все пересекающиеся выпуклые точки (выпуклые обозначены розовым треугольником / прямоугольником): - enter image description here

Вот как я нахожу нормальное.

Для каждой разделяющей оси (все = 15 осей), я проект розовый выпуклый на оси.
Ось, которая дает самое короткое расстояние проекция (розовая стрелка), должна быть направлением нормали.

Мое вышеупомянутое предположение часто верно (например, слева), но иногда неправильно (например, справа).
Как улучшить это CPU-дешево?

1 Ответ

1 голос
/ 11 июля 2019

Игровые движки обычно моделируют время серией дискретных шагов.Как следствие, система столкновений может попасть в сложные (дорогостоящие в вычислительном отношении) случаи из-за взаимопроникновения (ваш случай) или из-за того, что все движется быстро - туннелирование, где A находится на одной стороне B на этапе N и полностью на другой стороне Bна этапе N + 1.Еще сложнее, если вам нужно иметь дело с многотельным или непрерывным контактом или с невыпуклым, сочлененным или мягким объектом.Хлоп!мы моделируем весь мир.

Вы хотите заниматься "игровой физикой" и использовать приближения, чтобы выкупить частоту кадров ... В конце концов, вы можете скрыть много ошибок кучей дыма или легких вспышек.:-)

Существует класс алгоритмов, которые явно учитывают моделируемое время, чтобы помочь системе столкновений.Существует много способов реализовать систему «непрерывного обнаружения столкновений».Вы можете начать здесь, но прежде чем приступить к написанию кода, вам следует прочитать широко.К счастью, есть много литературы о столкновениях.вот хорошее место для начала https://docs.unity3d.com/Manual/ContinuousCollisionDetection.html https://pybullet.org/Bullet/phpBB3/viewtopic.php?t=20

Вот один из предложенных эвристических методов, которые могут работать в вашей существующей системе .... Этот эвристический метод может работать в такой игре, как астроиды 3d, гдеобъекты свободно перемещаются в пространстве.Это может быть достаточно для того, что вам нужно.

Изображение каждый объект хранит свой текущий вектор состояния (положение, ориентация, скорость, ускорение, вращение ...) и свой предыдущий вектор состояния с предыдущего временного шага.

Предположим, вы обнаружили потенциалстолкновение между объектами A и B в момент времени = текущий.

Для времени = предыдущего предположим, что A и B не соприкасаются.

Вычислите ближайшие точки на поверхностях A и B соответственнов момент времени = prev с использованием предыдущих векторов состояний A и B. (closestA, closestB).

Сегмент линии (closestA, closestB) будет иметь ненулевую длину в момент времени = предыдущий.Вы можете просто использовать closestB для вашей позиции и нормального значения, но при этом будет иметь место некоторая ошибка, пропорциональная длине отрезка линии.

Так что выполняйте бинарный поиск по времени и минимизируйте ошибку, находя времякогда A сколь угодно близко к B.При каждом проходе поиска уменьшайте размер шага времени поиска пополам.0,5, 0,25, 0,125 .. до тех пор, пока длина (closestA, closestB) не станет ниже порога ошибки, или вы не сдадитесь.

Это должно дать вам приемлемое приблизительное решение для простых случаев ...

Кроме того, вы сказали, что используете теорему об отделении в качестве "первой проверки".На самом деле это звучит дорого для меня, если это действительно «первая проверка» ..

Самое быстрое вычисление - это то, что вы не делаете, поэтому быстрое столкновение означает много дешевых предварительных испытаний и обход дорогих случаев.

Вы можете рассмотреть возможность использования пространственных методов, таких как грубая пространственная сетка, и проверять только те объекты, которые, как вы уже знаете, находятся рядом друг с другом.

Кроме того, тест сфера-сфера - это очень быстрый предварительный тест, чтобы увидеть, перекрывается ли ограничивающая сфера двух выпуклых объектов.

...