Определение столкновений выпуклых объектов движущихся с постоянными скоростями.
Автор: IvanVR1
Впервые с необходимостью определения столкновений объектов движущихся на высоких скоростях я столкнулся во время разработки игры PulseRacer, вышедшей на Xbox. Это гоночная игрушка с машинками, размер которых не превышает полутора метров, а скорость огромна — свыше 300 км/ч.
Временной шаг dt был выбран равным 1/50 секунды, такая величина dt дает в целом достаточную точность и не требует серьезных вычислительных затрат. Не трудно подсчитать, что за шаг интегрирования машина перемещалась примерно на 2 метра. Первое решение было таким: аппроксимируем каждую машину боксом, потом делаем проверку пересечения стационарных «боксов». В случае пересечения, путем рекурсивного деления вектора перемещения на 2 получаем точку и время первого пересечения. Такой алгоритм работал некорректно, машины иногда проваливались друг в друга или неестественно отскакивали. Это происходило из-за того, что перемещение значительно превышало длину автомобиля. Во втором варианте решения действовали иначе: аппроксимировали перемещения машин за один шаг «боксами» и попарно проверяли на пересечение. Результат был также плачевен — автомобили вели себя, прямо скажу, странно. Эти методы эффективны только тогда, когда перемещение объекта за время dt меньше половины «длины объекта». И тогда последнее, что нам оставалось попробовать это проверка столкновения двух боксов движущихся с постоянными скоростями и не имеющих скорости вращения. Результат был великолепен, функция проверки коллизии работала быстро, а модуль физики четко обрабатывал столкновения. Поступательная скорость машины велика настолько, что скоростью вращения можно пренебречь.
Рассмотрим перемещение двух «боксов» DP0 и DP1 за время dt, скорости будут равны V0= DP0/dt и V1 = DP1/dt.
Надо реализовать функцию, принимающую координаты двух «боксов» и их скорости, возвращающую факт наличия пересечения и время первого касания.
bool TestIntersection(const class OBB& Box0, const class POINT3D& V0, const class OBB& Box1, const class POINT3D& V1, float& IntersectionTime ); class OBB // Oriented bounding box { public: class POINT3D Origin, // Центр Extents, // Размер Orientation[3]; // Ориентация //: };
Для реализации TestIntersection подойдет Метод разделяющих осей (The Method of Separating Axes). Этот метод применяется для проверки пересечения двух выпуклых объектов. Выбирается несколько осей, на которые проецируются фигуры, если хотя бы на одной из осей проекции не пересекаются, значит, и объекты не пересекаются.
Для выбора осей в 3D пространстве применяется следующее правило: к разделяющим осям относятся нормали граней и векторные произведения ребер фигур. Например, для пары боксов разделяющих осей образованных за счет нормалей граней будет 6, а за счет векторных произведений ребер 9. Для проверки пересечения "бокса" и треугольника надо использовать три неколлинеарных нормали граней "бокса", нормаль к треугольнику и девять векторных произведений, образованных тремя ребрами треугольника и тремя неколлинеарными ребрами "бокса".
Метод разделяющих осей можно надстроить так, чтобы использовать его и для динамических объектов, двигающихся с постоянной скоростью. При этом легко можно вычислить время первого касания объектов Tfirst, если объекты изначально пересекаются Tfirst=0. Относительная скорость V=V1-V0. Проецируем V на разделяющие оси. Если проекции фигур двигаются в противоположных направлениях, значит, столкновения не может произойти. Столкновение произойдет только в том случае, если все проекции двигаются на встречу друг другу. Фигуры пересекаются только тогда, когда пересекаются все их проекции, отсюда Tfirst = max ( TfirstI ), i=0..n-1, n-количество разделяющих осей, TFirsti - время первого касания для каждой проекции. Время разъединения фигур Tlast = min (TlastI), i=0..n-1, TlastI - время разъединения для каждой проекции. Если Tfirst<= Tlast, столкновение произойдет, и время первого касания будет равным Tfirst. Приведу реализацию обобщенного метода проверки пересечения двух выпуклых объектов, двигающихся с постоянными скоростями. Для частных случаев (проверка пересечения двух "боксов", проверка пересечения "бокса" и треугольника) функция требует оптимизации.