Эксперименты с физикой. Часть 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
Комментарии
28.03.2010 23:50 | |
вот это уже здорово, движок изнутри. ждем-с продолжения.
|
29.03.2010 10:03 | |
Цитата:
ко всем классам буду добавлять эту букву - заодно прославлю свой ник
А понял.. Вы - подающий надежды гений)))) |
29.03.2010 11:43 | |
))))
а статья хорошая |
29.03.2010 12:39 | |
Котяра, офигеть! Убил. Т.е. я уже на второй ступени в пути к мастерству?
|
29.03.2010 19:22 | |
Я могу точно сказать, что я на третьем пункте застрял :-)
|
31.03.2010 18:32 | |
Ай молодца +1 (я тоже всегда завидовал людям, которые могут вить веревки)
|
21.04.2010 21:36 | |
Цитата:
И вот, прочитав несколько книг, я увидел что не так уж это и сложно.
|
22.04.2010 14:51 | |
Т.е. все не русскоязычное?
|
22.04.2010 15:32 | |
Так точно. Из русскоязычных только gamedev.ru и тамошние спецы.
|
22.04.2010 15:43 | |
А почему не русские или переведенные на русский?
Есть же. Вот, например: Физика для разработчиков компьютерных игр Автор: Конгер Д. |
Последние записи от Волгоградец
- Изометрическая сортировка. Новый подход. (25.01.2013)
- Stage3D заметки (06.04.2012)
- Embed клипа с одним кадром. (16.01.2012)
- Производительность операций с floating point number (18.03.2011)
- FTE based text controls (10.01.2011)