o2 dev
108 subscribers
49 photos
4 videos
25 files
54 links
About o2 engine development
加入频道
И это чистая правда. Здесь начинается настоящая векторная математика, оптимизации и куча интересностей. Нам надо получить примерно такую картину:
Зайдем с самого очевидного и самого сложного кейса - геометрия описывается мешем, то есть набором треугольников. С одной стороны тут все просто - проверить все пары треугольников на пересечения 2х треугольников. Но тут же всплывают нюансы: треугольников много (та же проблема с количеством пар проверки), у треугольников есть общие ребра и часть точек нужно мержить. А еще не всегда понятно в какую сторону делать нормаль, проверки треугольников запросто могут противоречить друг другу, от этого зависит в какую сторону выталкивать тела. В конечном итоге проверка мешей - это самый сложный и тяжелый вариант для обсчета физики. К тому же наименее стабильный

Гораздо проще происходит дело с простыми телами, а именно выпуклыми. Это может быть любая форма с любым количеством вершин, но ни одна часть не может быть впуклой. В чем преимущество? Мы явно можем определить ось, разделяющие тела. Нормаль коллизии всегда будет направлена вдоль этой оси, что дает стабильность. Более подробно об этом методе - separating axis theorem

Более правильным и производительным для построения геометрии является способ комбинирования нескольких выпуклых геометрий, что позволяет описать любую, в том числе полигональную форму. Есть даже специальные тулзы и алгоритмы, которые принимают на вход сложны меш, а на выходе разбитый на выпуклые части набор примитивов
Важная штука в проверке столкновений - можно сильно упрощать геометрию. Никто особо не заметит что физическая модель на так точно соответствует отображаемой модели. В большинстве случаев это даже играет на руку, тк менее детальная физичная модель лучше себя ведет в дискретном мире - не цепляется, не застревает и не требует большого количества вычислений
Теперь нужно зарешать все эти контакты. Нет, не по-пацански, а по-ботански. Вот, кстати, тоже отличная статья от того же автора на gamedev.ru, где все разжевано по формулам. Здесь я пройдусь по верхам и просто расскажу принципы

Решением контактов занимается солвер (solver), дословно решатель. Его задача разрешить все ограничения взаимодействия тел и джонтов. Это является одной из стадий работы физического движка:
- интеграция тел (их движение в течение 1/60 секунды)
- поиск столкновений: широкая фаза и узкая
- решение ограничений (контактов и соединений)
- применение других сил (гравитация, игровые механики)
- повторяем
Для каждого контакта мы должны посчитать суммарный импульс двух тел и применить его обратно к телам. Все просто. Вроде бы
Контакт может быть только между парой тел. У тел, валяющихся в куче, куча контактов с соседними телами. Они обмениваются импульсами, и в итоге эта куча как-то себя ведет - лежит, разваливается и тп. В общем тела взаимодествуют сугубо в парах
Для каждой контактирующей пары мы уже вычислили точки соприкосновения, нормаль и глубину. Суммарный импульс складывается из массы тел и их скоростей. Импульс считается относительно точки контакта, учитывается угловое вращение. Представьте себе палку, которая быстро крутится в воздухе и удаляется концом обо что-то. Импульст такого удара явно зависит от скорости вращения, ведь центр может быть недвижим. Формул не будет, это скучно, и они есть в статьях выше. А здесь у нас легкое чтиво

Попробуем применить эти импульсы к каждой паре тел. В общем, если это сделать так, то в какой-то степени это даже будет работать. Тела будут отлетать друг от друга и весте себя правдоподобно... без гравитации и длительных взаимодействий друг с другом. Такая физика подойдет может быть для простого бильярда
Большие проблемы начинаются при длительном воздействии. Самый простой пример, и самый распространенный, как назло - это лежащее на полу твердое тело. Если тупо применять импульс, то оно в лучше случае остановится и немного залезет в пол. Но если сверху на него надавит другое тело, или даже стопка тел - они начнуть разъезжаться, проникать друг в друга и все разлетится к чертям

Тут две проблемы: точность рассчета импульсов в сложных противоречащих системах и проблема проникновения при интегрировании
И тут выплывает факт, что 1/60 секунды - это довольно много в мире физики. Импульс может оказаться очень большой. А в сложных системах где на одно тело действуют противоположные импульсы, итоговый импульс может оказаться далек от реальности. Представьте ту самую кучу твердых тел, там ведь полны бардак в импульсах, они действуют в разные стороны

Плюс начинает проявляться эффект дрожания (jittering) - тела начинают дрожать, тк за 1/60 успевают перелететь нужно положение, из-за чего считается слишком большой импульс, что приводит снова к перелету в другую сторону, в итоге система не стабильна и вот так вот дрожит. Или вовсе взрывается, когда за 2-3 кадра импульсы нарастают в геометрической прогрессии и тела улетают в nan

Если вы вспомните старые игры, до массового распространения движков типа havok, physX, то вы вспомните все эти эффекты - физика в играх была либо любо глючная, либо никакая. Все из-за вот этой проблемы дискретности и применения импульсов. Это было еще где-то в начале 2000х годов. Но потом пришел Эрин Катто
это чувак, который написал Box2D. Забавно, ведь это изначально была просто демка на GDC (Game Dev Conference), где она показывал свой подход к решению проблемы. Кстати вот его канал на ютубе.

Что же такого он привнес? Численные методы в решение проблемы сложных систем контактов в физических движках. По сути, коллизии в физдвижке - это система условий. Ее можно решить классически, загнав в огромные матрицы и посчитать. Но это весьма дорого в плане ресурсов - матрицы огромные и очень разреженные, в итоге умножаешь нули на нули.

Эрин Катто придумал применил простой способ - считать все контакты в несколько итераций. То есть не один раз, а раз так 6-8 за кадр. При этом тела все еще не движутся, просто на каждой итерации импульсы в контактах уточняются и приближаются к более правильному решению системы. Собственно, так и работают разные численные методы - вместо решения системы уравнений аналитически, мы решаем их итерационно, приближая ответ к верному все ближе и ближе.

На 6-8 итерации работы алгоритма точность схождения уже достаточная чтобы корректно симулировать физику. Пропадает эффект дрожания, стопка тел становится стабильной, куча не разъезжается. Остается еще одна проблема - тела проникают друг в друга
Это можно решить наивно - придать телам чуть больший импульс, чтобы они как бы вылетели друг из друга. Ну, это работает окей в части случаев, когда глубина проникновения не большая. Ну а если большая, то импульс прикладывается неадекватно большой, и тело не вылазит, а вылетает с лютой скоростью в противоположном направлении. Думаю такой эффект вы тоже видели в некоторых играх

Эрин подошел к проблеме по-другому. Окей, нам нужно как-то вытащить тела друг из друга. При этом не разогнав их до скорости света. Окей, давайте сделаем отдельные импульсы, направленные чисто на расталкивание объектов, скорости которых будем обнуять каждый кадр. Ииии... это работает. Мы точно так же считаем дополнительный импульс, направленный на расталкивание тел, но он как бы действует только один кадр. Тела расталкиваются, но при этом не уетают - профит

Здесь стоит вспомнить про идентификацию точек контакта. Они должны быть одни и те же между разными кадрами симуляции. Это нужно для поддержания работы численного метода рассчета импульса. Начинать уточнения гораздо эффективнее не с нуля, а он предыдущего рассчитанного импульса, ведь он, вероятно будет такой же. Например, в стопке тел, которые стоят и не двигаются, импульсы между ними будут интуитивно одинаковые от кадра к кадру. Поэтому мы идентифицируем точки контакта от кадра к кадру
Теперь вкратце о трении. В целом, это те же импульсы, направленные перпендикулярно нормали контакта. А дальше все просто - коэф. трения, скольжения итп
итак, соберем все в кучу. У нас есть тела, они занимают какое-то положение в мире. У них есть параметры - масса, инерция и тп. У тел есть оболочка, или коллайдеры, с помощью которых мы понимаем как они сталкиваются.

Всю эту систему мы обновляем раз в какой-то промежуток времени, обычно это 1/60 секунды. Сначала двигаем тела в соответствии с их скоростями. Затем смотрим кто с кем столкнулся - отсеиваем очевидные НЕ пересечения в широкой фазе и уточняем точки контакта в узкой фазе. После этого в несколько итераций считаем импульсы между парами тел. Повторяем на следующем кадре
движимые тела и недвижимые. Есть ящик, который ведет себя динамически, а есть земля, которая статична. Ее подвинуть нельзя. По сути это просто типы твердых тел, что отражается в рассчете импульсов. К статическим телам не применяется импульс, весь импульс уходит в динамическое тело
ограничения или джоинты. Применяется в физике авто для подвески, например. Или для ragdoll (трупаки), для симуляции суставов тела. Задают какие-то органичения для двух тел, как они могут двигаться друг относительно друг друга. По сути, история точно такая же что и в контактах, но немного по-другому. Решается теми же численными методами внутри солвера
Собственно, все это было придумано в начале 2000х, и по сути нифига не поменялось. Физдвижки уже пршли стадию борьбы и устаканились. Все юзают PhysX для трехмерной физики, и Box2D для 2D. Мир физики затух и не развивается, что меня печалит. Потому что я правда считаю что эта зона может дать сильный толчок в развитии картинки в игре, как бы странно это ни звучало
иии здесь на сцену выходят снова численные метолы (полезная штука, да?). В это раз мой герой это Томас Якобсен, работавший над физикой первого Hitman. О дааа, бородатые года, а можно было таскать гибкие трупаки по локации, растения огибали персонажа, шторы вели себя физично, и галстук (карл!) физично болтался на груди 47го. Такого и нынче то не часто встретишь

Вот его оригинальная статья про физику в хитмане