Определение столкновения с полигональной моделью.
Автор: IvanVR1
==
==
В любой математической модели, определяющей движение игрового объекта, вряд ли удастся избежать проверки столкновения с окружающим миром через методы, работающие с полигональной моделью (ПМ). Конечно, мир можно представить геометрическими примитивами (сферами, "боксами" и т.д.), что эффективно по скорости вычислений и объему расходуемой памяти, но не всегда дает достаточную точность. Да и автоматизировать процесс подбора геометрических примитивов для аппроксимации ПМ сложно. Возникнет необходимость ручной работы, которая будет возложена на художников, и, скорее всего, вы услышите от них много неприятных слов, а может даже какие-нибудь новые выражения. Существует много вариантов решения задачи проверки пересечения с ПМ. Наиболее популярные и эффективные используют пространственные деревья (spatial trees), представляющие собой иерархии окружающих объемов или разделенное пространство.
Математические модели движения объектов чаще всего используют следующие базовые функции:
- проверка пересечения геометрических примитивов с ПМ
- проверка пересечения двух ПМ
- определение столкновения выпуклых объектов, двигающихся с постоянными скоростями, с ПМ
- определение столкновения двух ПМ, двигающихся с постоянными скоростями.
Описываемый здесь метод, использует разновидность пространственного дерева для представления ПМ, а именно axis-aligned bounding boxes tree (AABBs tree). Этот метод хорошо подходит для реализации изложенных выше функций.
Критериями выбора метода являются: скорость работы, точность, расход памяти, сложность реализации и трудоемкость подготовки данных. Для решения задач, возникающих при разработке игр, AABBs деревья подходят очень хорошо: они универсальны (с их помощью можно реализовать все функции необходимые для определения столкновений), эффективны по скорости и расходу памяти. А также имеют дополнительные плюсы: точность результата легко регулируема, реализация проста, а подготовка данных (построение дерева) полностью автоматизирована.
AABBs tree - бинарное дерево, образованное иерархией описывающих "боксов", лежащих вдоль осей координат. Каждый AABB охватывает всех своих детей. Т.е. каждый узел дерева представляет собой AABB и две ссылки на детей: "позитивного" и "негативного". Здесь термины "позитивный" и "негативный" не означают, что один лучше другого, просто так сложилось в результате следования правилам построения дерева. По каждой координате, "ребенок" имеет меньший или равный своему родителю размер и может пересекаться со своим " братом". Листьями дерева являются треугольники.
AABBs дерево строится из ПМ, представленной не пустым списком треугольников, следующим образом:
1) Если множество треугольников T состоит только из одного треугольника, переходим к пункту 7
2) Создаем новый узел U
3) Для множества треугольников T вычисляем AABB, который запоминаем в узле U дерева
4) Выбираем границу деления - плоскость, проходящую через середину наибольшей стороны AABB параллельно двум наименьшим граням
5) Множество T разбиваем на два непустых подмножества Tpositive и Tnegative по положению центров проекций треугольников на нормаль делящей плоскости.
6) Рекурсивно повторяем последовательность действий для подмножеств Tpositive и Tnegative, начиная с пункта 1
7) Треугольник назначаем листом дерева, прекращаем рекурсию
Параллельность AABB осям координат является как основным преимуществом этого метода, так и его основным недостатком. Можно очень хорошо сэкономить на расходе памяти, упростить и ускорить методы проверки пересечения узла дерева с некоторыми геометрическими примитивами. С другой стороны AABBs tree проигрывает Oriented bounding boxes (OBBs) tree по точности охвата набора треугольников. Как следствие, возрастает количество итераций необходимых для проверки пересечения с деревом. AABBs tree занимает мало памяти за счет того, что не надо хранить ориентацию "бокса". Более того, нормировав все величины по размеру корневого "бокса", можно перейти от переменных с плавающей точкой к переменным с фиксированной точкой. В коммерческой реализации, я использую переменные с фиксированной точкой, и каждый 3D вектор занимает всего 48 бит. Это дает неплохую точность и выигрыш по памяти в два раза по сравнению с использованием типа float. Скорость работы повышается за счет того, что методы проверки пересечения геометрических примитивов с AABB проще методов для OBB. Также деревья можно "слегка подрезать", прекращая рекурсию построения дерева при достижении определенного (достаточно малого) размера AABB. Для повышения скорости можно также кэшировать узлы, с которыми в прошлый раз произошло пересечение, что позволяет в некоторых ситуациях получить заметный выигрыш.
Еще одним неоспоримым плюсом AABBs дерева является возможность его применения для деформируемых объектов. Я не буду приводить здесь алгоритм перестроения дерева после деформации: в моей практике необходимость решать такую задачу ни разу не встречалась, а о вкусе устриц рассуждать не хочется... Поэтому тех, кто хочет ознакомиться с применением AABBs дерева для деформируемых объектов, отсылаю к списку литературы.
Ниже приведены алгоритмы проверки пересечения с AABBs деревом и несколько сокращенный (для экономии места) текст программы, реализующей описанные в данной статье алгоритмы и структуры данных.
Алгоритм проверки пересечения AABBs дерева с геометрическим примитивом. Для проверки пересечения AABBs дерева с выпуклым объектом, двигающимся с постоянной скоростью, последовательность действий аналогична.
1) Если находимся в листе, проверяем пересечение геометрического примитива с треугольником-листом и с результатом проверки переходим на пункт 4.
2) Проверяем пересечение геометрического примитива с AABB. Если пересечения нет, переходим с отрицательным результатом на пункт 4.
3) Рекурсивно повторяем последовательность с пункта 1 для "позитивного" и "негативного" ребенка
4) Прекращение рекурсии и возвращение результата
Алгоритм проверки пересечения двух AABBs деревьев. Если деревья двигаются с постоянной скоростью, алгоритм остается неизменным, меняются только функции проверки пересечения примитивов.
1) Если мы находимся в узлах обоих деревьев, проверяем пересечение двух OBB (т.к. деревья обычно имеют различные системы координат). Если "боксы" пересекаются, продолжаем рекурсию спуском по дереву, имеющему больший размер AABB - повторяем с пункта 1. Если нет, возвращаем отрицательный результат проверки.
2) Если мы находимся в листе одного из деревьев и узле другого, проверяем пересечение треугольника с OBB. В случае пересечения, продолжаем спуск по дереву, в узле которого находимся - повторяем с пункта 2. Если нет, возвращаем отрицательный результат проверки.
3) Если мы находимся в листьях обоих деревьев, проверяем пересечение двух треугольников с учетом координатных систем, возвращаем результат проверки.