Вы можете получать ложные срабатывания. Столкновения обнаружены, но столкновения не имеют.
№ 15 происходит от
- 3 оси от объекта А (нормали лица)
- 3 оси от объекта B (нормали лица)
- 9 осей от всех пар ребер A и ребер B (3x3)
- = 15 всего
9 осей составлены из перекрестных произведений ребер A и ребер B
- Ae1 x Be1 (Край 1 А, Крест 1, Б)
- Ae1 x Be2
- Ae1 x Be3
- Ae2 x Be1
- ... и так далее
Первые 6 осей (из нормали грани) используются для проверки, пересекает ли угол одного объекта грань другого объекта. (или правильнее устранить подобные столкновения)
Набор из 9 осей, образованных перекрестными произведениями ребер, используется для определения столкновения ребер на ребре, где нет вершины, проникающей в другой объект. Как «почти» столкновение на фото ниже. Предположим для остальной части этого ответа, что два поля на рисунке на самом деле не сталкиваются, а находятся на небольшом расстоянии.
Давайте посмотрим, что произойдет, если мы просто используем 6 нормалей лица для SAT. Первое изображение ниже показывает одну ось от синей рамки и 2 оси от желтой рамки. Если мы спроецируем оба объекта на эти оси, мы получим перекрытие для всех трех. Второе изображение ниже показывает две оставшиеся оси синего прямоугольника и оставшуюся ось желтого прямоугольника. Снова проецирование по этим осям покажет перекрытия на всех 3.
Так что только проверка 6 нормалей лица покажет перекрытия по всем 6 осям, что, согласно SAT, означает, что объекты сталкиваются, потому что мы не смогли найти разделение. Но, конечно, эти объекты не сталкиваются. Причина, по которой мы не нашли разделения, заключается в том, что мы не выглядели достаточно усердно!
Так как же нам найти этот пробел? На изображении ниже показана ось, на которой проекция обоих объектов обнаружит разделение.
Откуда мы берем эту ось?
Если вы представите, что вставили кусок жесткой карты в щель, эта карта будет частью разделяющей плоскости. Если мы проецируем на нормаль этой плоскости (черная стрелка на рисунке выше), мы увидим разделение. Мы знаем, что это за плоскость, потому что у нас есть два вектора, которые лежат на этой плоскости) Один вектор выровнен с краем синего цвета, а другой вектор выровнен с краем желтого цвета, и, как мы все знаем, нормаль к плоскости - это просто перекрестное произведение двух векторов, лежащих на плоскости.
Поэтому для OOBB нам нужно проверить каждую комбинацию (9 из них) перекрестных произведений краев двух объектов, чтобы убедиться, что мы не пропустили никакого разделения ребро-ребро.
Ответ Кена отмечает:
Несколько странно ссылаться на ребра, так как имеется 12 ребер по сравнению с 6 нормалями, когда вы можете также использовать три основных нормали для одного и того же вывода - ребра все выровнены с нормалями, поэтому я рекомендую использовать их вместо !
Также обратите внимание, что нормали, направленные вдоль одной и той же оси, но в другом направлении, игнорируются, и поэтому у нас остаются три уникальные оси.
Еще одна вещь, которую я хотел бы добавить, это то, что вы можете оптимизировать этот расчет, выйдя пораньше, если вы найдете разделяющую ось, прежде чем вычислять все оси, которые вы хотите проверить. Так что нет, вам не нужно проверять все оси в каждом случае, но вы должны быть готовы проверить их все :)
Вот полный список осей для тестирования, учитывая два OBB, A и B, где x, y и z относятся к базисным векторам / трем уникальным нормалям. 0 = ось x, 1 = ось y, 2 = ось z
Есть также небольшое предостережение, о котором вы должны знать.
Перекрестное произведение даст вам нулевой вектор {0,0,0}, когда любые две оси между объектами будут указывать в одном направлении.
Кроме того, так как эта часть была пропущена, вот моя реализация, чтобы проверить, перекрывается ли проекция или нет. Возможно, есть лучший способ, но это сработало для меня! (Используя Unity и его C # API)
источник
пример работы c #, основанный на ответе Acegikmo (используя некоторые API Unity):
источник