Эксперименты с физикой. Часть 1.
Давно смотрел на различные физические симуляции и молча завидовал людям, которые умеют делать веревки, ткань, определять коллизии... И вот, прочитав несколько книг, я увидел что не так уж это и сложно. Я попытаюсь создать простенький двухмерный физический движок и по ходу буду описывать свои действия. Для понимания материала, я бы посоветовал вспомнить школьную геометрию и векторную математику. Хотя я постараюсь описать некоторые моменты. Также хочу заметить, что код буду писать без глубокой оптимизации и с оглядкой на ООП (хотя это отрицательно скажется на производительности).
В первой серии туториалов мы создадим так называемый soft body физический движок. А именно, я покажу как смоделировать пружину, ткань, эластичную веревку, цепь.
Let's Get Started...
В первой части мы создадим простую пружину, которая послужит нам в дальнейшем для веревки и ткани. Я выбрал следующую реализацию:
- я буду создавать frame based симуляцию, т.е. я не буду учитывать точное время между кадрами, а буду принимать это время равным 1.
- для каждой силы (а это - гравитация, сила воздушного сопротивления и др.), я создам свой генератор силы, который будет принимать в качестве параметра частицу и добавлять соответствующую силу ко всем силам, действующим на данную частицу.
- для расчета положения частицы я буду использовать отдельный класс - интегратор, который будет принимать в качестве параметра частицу.
Последовательность действий такая - в начале каждого кадра я рассчитываю все силы, действующие на частицу, и добавляю их в один общий аккумулятор сил частицы. Так удобнее, ведь результирующая сила одна - и равна сумме всех сил. Затем интегратор рассчитает положение и скорость частицы в зависимости от ускорения, которое зависит от той самой результирующей силы.
Итак, начнем со строительства фундамента - создадим класс VVector2D (т.к. в сети можно найти уйму реализаций вектора, во избежание конфликта имен я добавил букву V перед именем класса. Далее, ко всем классам буду добавлять эту букву - заодно прославлю свой ник). Каждый метод описывать не буду - остановлюсь, как я считаю, чуть ли не самом важном методе в построении физических симуляций, на методе dotProduct() - скалярном произведении векторов.
Метод принимает экземпляр вектора и возвращает скалярное произведение двух векторов. Зная величину этого скалярного произведения, мы можем рассчитать угол между векторами таким образом:
dotProduct = |a|*|b| * cosA, где |a| и |b| - длины векторов.
Также мы легко можем узнать направление векторов относительно друг друга - если скалярное произведение больше 0, то вектора направлены в одну сторону, если меньше 0, то в противоположные, если равно 0, то перпендикулярны.
Еще одной не менее важной особенность скалярного произведения векторов является его геометрическое представление - оно показывает проекцию одного вектора на другой. Если один из векторов нормализован (т.е. его длина равна 1), то dotProduct даст нам точную величину проекции.
На картинке мы видим, как пунктирная линия показывает величину проекции вектора a на единичный вектор n. Мы скоро увидим применение этой особенности.
Далее создадим класс частицы Particle. Это то, на чем мы будем проводить наш физический эксперимент. Здесь ничего особенного - частица будет хранить позицию, массу (а также инверсную массу, т.е. отношение 1 к массе - чтобы избавиться от деления), скорость. Ускорение и аккумулятор будут рассчитываться каждый фрейм. Радиус и цвет нужны для отображения на экране - в расчетах они не участвуют.
Дальше идут силы.
Gravity - сила гравитации. Тут все просто - равна произведению ускорения свободного падения на массу частицы. Ускорения я выбрал равным 1 и направленным вниз, т.е. это вектор VVector2D(0.0, 1.0). Эту силу передаем в аккумулятор сил частицы.
Drag - сила воздушного трения. Равна произведению скорости частицы на коэффициент сопротивления и направлена в противоположную скорости сторону. Коэффициент я выбрал равным 0.1. Эту силу передаем в аккумулятор сил частицы.
AnchoredSpring - сила пружины. Здесь остановимся подробнее. В данном примере я сделаю пружину, один конец которой жестко зафиксирован и смещаться не будет. К другому концу будет подвешена частица. Сила рассчитывается следующим образом:
F = k * x,
где k - коэффициент жесткости пружины или stiffness.
x - расстояние, на которое мы сместили пружину. Т.е. представьте - в спокойном состоянии у пружины есть некая длина - так называемая rest length. Мы немного растянули пружину и ее длина увеличилась по сравнению с длиной покоя. Это и есть искомое x.
Помимо этих величин также имеется и коэффициент затухания пружины damping.
Немного векторной математики - и мы получаем силу и передаем ее в аккумулятор сил частицы.
К этому моменту мы имеем одну результирующую силу и сможем найти ускорение частицы. Как это делается: мы создадим интегратор EulerIntegrator - или простой интегратор Эйлера. Тут все очень просто - зная скорость, мы прибавляем ее к позиции и получаем новую позицию частицы. Зная ускорение, мы прибавляем его к скорости и получаем новую скорость частицы.
Собрав все это вместе и запустив мы видим, что частица реалистично прыгает на пружине. Все вроде бы хорошо, но есть одно НО - тот проект, что я приложил настроен так, что все работает стабильно. Но если поменять жесткость пружины или массу частицы, мы можем увидеть, как частица начинает метаться из стороны в торону и затем улетает в бесконечность. Это происходит из-за того, что действующая сила пружины действует так, что выталкивает нашу частицу достаточно далеко и теперь, новая сила будет действовать сильнее предыдущей и т.д.
Чтобы этого не было можно поступить так:
- жестко задать параметры и пресекать лишнее неосторожное движение.
- использовать другой интегратор - например интегратор Verlet.
В следующей части я покажу второй вариант - мы напишем новый интегратор Верле. Будет круто, оставайтесь на связи!
tutorial 1.zip
Всего комментариев 16
Комментарии
|
|
|
вот это уже здорово, движок изнутри. ждем-с продолжения.
|
|
|
|
Цитата:
ко всем классам буду добавлять эту букву - заодно прославлю свой ник
А понял.. Вы - подающий надежды гений)))) |
|
|
|
))))
а статья хорошая ![]() |
|
|
|
Котяра, офигеть! Убил. Т.е. я уже на второй ступени в пути к мастерству?
|
|
|
|
Я могу точно сказать, что я на третьем пункте застрял :-)
|
|
|
|
Ай молодца +1 (я тоже всегда завидовал людям, которые могут вить веревки)
|
|
|
|
Цитата:
И вот, прочитав несколько книг, я увидел что не так уж это и сложно.
|
|
|
|
Т.е. все не русскоязычное?
|
|
|
|
Так точно. Из русскоязычных только gamedev.ru и тамошние спецы.
|
|
|
|
А почему не русские или переведенные на русский?
Есть же. Вот, например: Физика для разработчиков компьютерных игр Автор: Конгер Д. |
Последние записи от Волгоградец
- Изометрическая сортировка. Новый подход. (25.01.2013)
- Stage3D заметки (06.04.2012)
- Embed клипа с одним кадром. (16.01.2012)
- Производительность операций с floating point number (18.03.2011)
- FTE based text controls (10.01.2011)














