Свойства

Современные физические движки симулируют не все физические законы реального мира, а лишь некоторые, причём с течением времени и прогресса в области информационных технологий и вычислительной техники список «поддерживаемых» законов увеличивается. На конец 2010 года физические движки могут симулировать следующие физические явления и состояния:

  • динамика абсолютно твёрдого тела ,
  • динамика деформируемого тела ,
  • динамика жидкостей,
  • динамика газов,
  • поведение тканей,
  • поведение верёвок (тросы, канаты и т. д.).

Класификация

Все физические движки условно делятся на два типа:

  • игровые,
  • научные.

Первый тип используется в компьютерных играх как компонент игрового движка. В этом случае он должен работать в режиме реального времени, то есть воспроизводить физические процессы в игре с той же самой скоростью, в которой они проходят в реальном мире. Вместе с тем от игрового физического движка не требуется точности вычислений. Главное требование - визуальная реалистичность, - и для его достижения не обязательно проводить точную симуляцию. Поэтому в играх используются очень сильные аппроксимации, приближенные модели и другие программные «трюки».

Научные физические движки используются в научно-исследовательских расчётах и симуляциях, где крайне важна именно физическая точность вычислений. Вместе с тем скорость вычислений не играет существенной роли.

Использование

Описание

Физический движок позволяет создать некое виртуальное пространство, которое можно наполнить телами (виртуальными статическими и динамическими объектами), и указать для него некие общие законы взаимодействия тел и среды, в той или иной мере приближенные к физическим, задавая при этом характер и степень взаимодействий (импульсы, силы, и т. д). Собственно расчёт взаимодействия тел движок и берёт на себя. Когда простого набора объектов, взаимодействующих по определённым законам в виртуальном пространстве, недостаточно в силу неполного приближения физической модели к реальной, возможно добавлять (к телам) связи. Рассчитывая взаимодействие тел между собой и со средой, физический движок приближает физическую модель получаемой системы к реальной, передавая уточнённые геометрические данные средству отображения (рендереру).

Тело

Известные физические движки

Игровые проприетарные

Игровые свободные

Игровые аппаратные

  • PhysX - физический процессор ; работает по сути так же, как и графическая карта, но в пользу физики PhysX. То есть, имея такую плату и игру с PhysX, игровая физика будет значительно лучше, нежели без использования адаптера PhysX.

Сегодня мы поговорим об основных компонентах, которые составляют физический движок и о том, как сложить их вместе. Этот туториал предназначен для программистов, у которых есть базовые познания в математике и геометрии, и которые хотят окунуться в мир моделирования.

Я надеюсь, что если до этого вы могли сделать разве что физику для игры Pong 1972-го года, то после прочтения этой статьи вы легко сможете написать свои ограничения для ваших физических движков.

Вы можете написать код для этого?

Я всегда считал название серии книг «… для чайников» обнадеживающим. Ведь если даже чайник сможет это изучить, то у вас и подавно получится, верно?

… для чайников?

Отсюда и название этого туториала.

План действий

Итак, я собираюсь осветить несколько вещей о физических движках, которые вы, возможно, захотите узнать:

  • Абсолютно твёрдые тела
  • Коллизии
  • Трение покоя
  • Ограничения (Соединения)

Моделирование

Имейте в виду, что мы начнем с самых азов. Надеюсь, в дальнейшем станет ясно, почему.

Начнем с частиц, которые, предположим, имеют позицию P и скорость V . Каждый кадр мы изменяем позицию P , добавляя к ней скорость V . Этот процесс называется интегрированием .

Вы можете использовать любые единицы, подходящие вашей модели. Обычно выбор падает на ед/метр, что я в данном случае и использую. Экран имеет размер два на два метра (в нашем мире), поэтому скорость определяется в метрах в секунду. Чтобы наш пример заработал, нам нужно знать, число секунд в кадре. Теперь, для правильного движения частиц воспользуемся формулой P += V * dt , где dt — время (в секундах), прошедшее с предыдущего кадра.

Можно сымитировать движение множества частиц, сохраняя массивы их позиций и скоростей, и циклически интегрируя каждый элемент в них. Чтобы предотвратить выход частиц из области видимости, мы заставим их отталкиваться от краев экрана.

Для того, чтобы частицы отскакивали от краев мы просто должны отслеживать столкновения с краями экрана и менять их скорость, по оси столкновения, на противоположную.

For all i if (P[i].x < -1 && V[i].x < 0) { V[i].x = -V[i].x; } if (P[i].y > 1 && V[i].y > 0) { V[i].y = -V[i].y; }; if (P[i].x > 1 && V[i].x > 0) { V[i].x = -V[i].x; } if (P[i].y < -1 && V[i].y < 0) { V[i].y = -V[i].y; }

В каждом блоке первое условие определяет пересечение частицы в пространстве, а второе проверяет, направляется ли частица к краю. Второе условие очень важно, так как в противном случае столкновение будет срабатывать снова, и в следующем кадре частицы будут ошибочно двигаться со скоростью, большей чем один пиксель в кадр. Таким образом, оно выполняет имитацию твердого тела на основе импульса, и отделяет ограничения-неравенства (например, касание) и ограничения-равенства (большинство соединений).

Это пример кода, который вы, наверняка, уже давным-давно написали, только начав интересоваться физическими моделями. Я включил его в туториал, поскольку считаю, естественным переход от этого простого примера к более сложной физике.

Что происходит в данной простейшей модели?

Сами того не зная, мы присвоили нашим частицам такой тип физического материала, который включает в себя коэффициент восстановления ( /) и подчиняется закону сохранения импульса ( /). Кроме того, мы обозначили, что мир имеет бесконечную массу, таким образом он никак не реагирует при воздействии частиц на него. Отражая частицы при ударе, мы сохраняем их импульс (проигнорировав их массу в вычислениях), указывая этим, что коэффициент восстановления частицы равен единице, то есть, как у совершенно упругого супер-мяча. В добавок, для реакции на столкновение, мы предпочли модель импульса/скорости модели силы/ускорения, изменяя скорость частиц мгновенно, а не за определенный промежуток времени.

На самом деле, здесь мы имеем дело с высоко оптимизированным случаем имитации физики. «Каким образом оптимизированный?» — спросите вы. Позвольте мне объяснить:

Если бы мы решили написать вышеприведенный код «по уму», избегая грубых упрощений, нам мы бы пришлось учитывать следующее. Наша среда определена ее границами — четырьмя плоскостями выровненными по осям (фактически — это линии, так как мы находимся в двухмерном мире). Каждая из этих плоскостей имеет нормаль, указывающую внутрь, и расстояние до начала координат. Они выглядят так:

Planes = { (1, 0, 1), (0, -1, 1), (-1, 0, 1), (0, 1, 1) }

Теперь мы должны определить столкновения, как мы делали это ранее, но на этот раз мы не будем ничего упрощать. Чтобы обнаружить пересечение частиц с плоскостями, мы должны выполнить скалярное произведение ( /) и добавить расстояние до начала координат.

For all particles i { for all planes j { distance = P[i].x*Planes[j].a + P[i].y*Planes[j].b + Planes[j].c; if (distance < 0) { // collision responce } } }

Этот код определяет длину проекции ( /) вектора направленного от плоскости к частице на нормаль плоскости. А поскольку нормали наших плоскостей имеют единичную длину, это значение является расстоянием от частицы до плоскости . Очевидно, что если вычисленное расстояние оказалось меньше нуля, то наша частица проникла в плоскость и нам следует среагировать на столкновение.

Теперь, если мы внимательнее, включая коэффициенты каждой плоскости, изучим код расчета расстояния, приведенный выше:

Plane0dist = P[i].x*1 + P[i].y*0 + 1; plane1dist = P[i].x*0 + P[i].y*-1 + 1; plane2dist = P[i].x*-1 + P[i].y*0 + 1; plane3dist = P[i].x*0 + P[i].y*1 + 1;

Немного упростив,

Plane0dist = P[i].x + 1; plane1dist = -P[i].y + 1; plane2dist = -P[i].x + 1; plane3dist = P[i].y + 1;

и чуть-чуть преобразовав, мы получим условия проверки для этих плоскостей

If (P[i].x < -1) if (-P[i].y < -1) = if (P[i].y > 1) if (-P[i].x < -1) = if (P[i].x > 1) if (P[i].y < -1)

Эти условия оказались точь в точь такими же, как и в нашем первом, простом, примере. Второе условие также должно быть выполнено. С помощью него мы реагируем на столкновение только один раз, в момент столкновения. Это можно сделать выполнив скалярное умножение скорости частиц, на нормаль к каждой плоскости.

If (P[i].x < -1 && V[i] N[i] < 0)

Мы назовем это перпендикулярная скорость , поскольку это скорость частицы по направлении к нормали. Если значение этой величины оказывается меньше нуля, то это значит, что частица движется по направлению к плоскости и мы фиксируем столкновение. Как только столкновение будет обработано, перпендикулярная скорость станет больше или равна нулю, в зависимости от коэффициента восстановления. Я бы мог провести детальный анализ этого условия, как делал это выше, чтобы доказать что в конечном итоге решение будет совпадать с первой версией кода, но оставлю это в качестве упражнения для читателей.

Это свидетельствует от том, что оба наших подхода являются, фактически, одним и тем же.

Хорошо, как же в данном случае нам обрабатывать столкновение?

Нам нужно решение, которое даст тот же результат, что и исходная программа, но которое, в тоже время, будет являться полным. Мы можем сделать это с помощью вектора отражения () из закона отражения ( /). Он рассчитывается следующим образом:

R = V – 2*N*(V.N)

Где V — это вектор скорости, а N — нормаль поверхности. Мы должны упростить выражение, подобно тому, как мы делали это в коде проверке столкновения:

Plane0vel x = V.x - 2* 1*(V.x* 1 + V.y* 0) = V.x -2*V.x = -V.x plane0vel y = V.y - 2* 0*(V.x* 1 + V.y* 0) = V.y - 0 = V.y plane1vel x = V.x - 2* 0*(V.x* 0 + V.y*-1) = V.x - 0 = V.x plane1vel y = V.y - 2*-1*(V.x* 0 + V.y*-1) = V.y - 2*V.y = -V.y plane2vel x = V.x - 2*-1*(V.x*-1 + V.y* 0) = V.x - 2*V.x = -V.x plane2vel y = V.y - 2* 0*(V.x*-1 + V.y* 0) = V.y plane3vel x = V.x - 2* 0*(V.x* 0 + V.y* 1) = V.x plane3vel y = V.y - 2* 1*(V.x* 0 + V.y* 1) = V.y - 2*V.y = -V.y

Теперь вы видите, что в результате, мы получим в точности такое же выражение, как и в нашем первом, простом, примере.

Замечу, что масса была полностью проигнорирована в наших вычислениях. Она просто отбрасывается из уравнений, когда мы имеем дело со столкновением тела, с бесконечной массой (наш несложный мир).

Так, как же будет выглядеть новая версия в псевдокоде?

For all particles i { for all planes j { N = {Planes.a, Planes.b}; distance = P[i] N + Planes[j].c; if (distance < 0 && V[i] N < 0) { // collision response, reflect particle V[i] -= 2*N*N V[i]; } } }

Отлично, мы превратили простой пример в более сложный (чем следовало), но зачем?

Во-первых, чтобы продемонстрировать, что корни всех наших первичных предположений были основаны на реальных законах. Во-вторых, чтобы показать преимущества более сложной реализации. Поскольку теперь, мы можем работать с произвольными 2d-плоскостями, вместо плоскостей, выровненных по осям. Это значит, что мы можем повернуть наш мир, и наша физическая модель по прежнему будет работать корректно:

Наведите курсор на пример выше, чтобы повернуть плоскость. Обратите внимание, что для этого примера я ввел некоторые корректировки в поведение точек при вращении плоскости, чтобы убедиться, что точки по прежнему находятся внутри нее.

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

Добавить гравитацию довольно просто. Мы будем вычитать силу тяжести из скорости наших частиц до того как произойдет столкновение, учитывая тот факт, что сила тяжести является ускорением.

V[i] += G*dt

В данном случае, G — вектор {0, −9.8}, а dt — время, прошедшее с предыдущего кадра.

Также, нам хотелось бы использовать другой коэффициент восстановления, поскольку наши частицы не могут быть сделаны из супер-резины. Давайте вспомним формулу для расчета вектора отражения , которую мы использовали ранее:

R = V – 2*N*(V.N)

Мы можем без проблем переписать данное уравнение, включив туда коэффициент восстановления:

R = V – (1+e)*N*(V.N)

Где e — это коэффициент восстановления, который варьируется от нуля (абсолютно пластичный) до единицы (абсолютно упругий). Как вы можете видеть, эти два равенства эквивалентны, при e = 1 , мы получим исходное уравнение. Коэффициент восстановления частиц в примере ниже варьируется от 0 до 1.

Единственное, что мы можем сейчас сделать для большей реалистичности этой физической модели (не касаясь имитации абсолютно твердых тел и вращения), это добавить учет масс при столкновениях. Чтобы добиться этого, нам придется заменить частицы на круги, поскольку маловероятно, что две частицы когда-либо столкнуться, ведь они не имеют размера!

Рисунок 1

Как показано на Рисунке 1 , два круга A и B пересекутся, если расстояние между ними будет меньше, чем сумма их радиусов. Перпендикуляр столкновения — это предварительно нормированный вектор d между ними.

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

ratio a = M b / (M a + M b)

ratio b = M a / (M a + M b)

Два соотношения выше помогут решить нашу задачу. Например:

M a = 1.0

ratio a = 0.5 / (1.0 + 0.5) = 1/3

ratio b = 1.0 / (1.0 + 0.5) = 2/3

Как видно, ⅓ + ⅔ = 1 , что говорит о том, что импульс сохраняется корректно. А если масса тела b равна половине массы тела a , то оно должно будет получить двойную силу воздействия при столкновении.

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

V a = V a – (1+e)*N*((V b –V a) . N)*(M b / (M a +M b))

V b = V b – (1+e)*-N*((V b -V a) . –N)*(M a / (M a +M b))

С помощью этих выражений мы получим нормаль, проходящую от тела b , к телу a , после чего мы будем должны инвертировать ее, чтобы вычислить отраженную скорость. Вы, наверное, уже заметили, что выражения выше имеют много повторяющихся вычислений. Давайте попробуем их немного упростить. Для этого мы можем воспользоваться относительной скоростью двух рассматриваемых объектов:

V r = V a – V b

Теперь, когда у нас осталась всего одна скорость, выражение упростилось.

I = (1+e)*N*(V r . N)

V a = – I*(M b / (M a +M b))

V b = +I*(M a / (M a +M b))

Здесь, мы рассматриваем один объект, как неподвижный относительно другого. Но мы можем ещё больше упростить эти выражения:

I = (1+e)*N*(V r . N)*(M a *M b)/(M a +M b)

V a – = I / M a

V b + = I / M b

Объединив выражения, мы можем сократить количество вычислений, и упростить последний шаг до простого деления, хотя знание массы все еще будет необходимо для расчетов.

Вы можете увидеть, как это работает:

(M a *M b)/(M a +M b) / M a = M b /(M a +M b)

(M a *M b)/(M a +M b) / M b = M a / (M a +M b)

Наконец, мы можем вывести (из дробной части), что:

(M a +M b)/(M a *M b) = 1/M a + 1/M b

А это значит, что мы теперь можем переписать линейное уравнение импульса так:

Это удобно, поскольку мы можем сохранить значения отношений 1/M a и 1/M b в определениях наших твердотельных кругов, чтобы не пересчитывать их постоянно. Это также значит, что теперь у нас есть способ представления объектов с бесконечной массой (сохраняя инверсную массу равной нулю).

V a – = I * 1/M a

V b + = I * 1/M b

В этом примере, вы можете взаимодействовать с телом с помощью мыши.

Вы, наверное, уже заметили проблему проникновения, связанную с системой обнаружения столкновений, которая фиксирует столкновение, когда становится уже слишком поздно. Это проблема усугубиться еще сильнее, если мы добавим большее количество твердых тел, так как сейчас система ничего не предпринимает, чтобы исправить это:

Чтобы устранить данную проблему, нам необходимо определить столкновение прежде, чем оно произойдет. К счастью, я уже рассказывал про эту технику в предыдущей статье , которую я советую вам почитать.

Как только вы примените эту технику, проблема исчезнет сама собой и для этого потребуется всего-навсего несколько строчек кода. Единственное ограничение — мы должны предполагать, что коэффициент восстановления никогда не будет равняться нулю. Это не слишком серьезное ограничение с учетом того, сколько пользы это нам принесет.

Пишем код

В физических движках знание математики — это только половина дела; вторая половина — это то, как вы организуете свой движок, с точки зрения иерархии классов, и то как вы напишите их.

Я покажу вам одно из возможных решений, которое я успешно использовал в прошлом. Возможно, оно покажется вам через чур простым, но вы хотя бы получите представление об этом. Здесь я использую ActionScript, но принципы изложенные ниже применимы к любому объектно-ориентированному языку.

Public class RigidBody { protected var m_pos:Vector2; protected var m_vel:Vector2; protected var m_invMass:Number; /// /// /// public function RigidBody(pos:Vector2, vel:Vector2, invMass:Number) { m_pos=pos; m_vel=vel; m_invMass=invMass; } /// /// /// public function GenerateContact(rb:RigidBody):Contact { throw new Error("Not implemented on base class"); } /// /// /// public function Integrate(dt:Number):void { m_pos=m_pos.Add(m_vel.MulScalar(dt)); } }

Итак, я создал базовый класс RigidBody , который содержит три параметра, используемые в примерах выше. Также, в нем существует метод Integrate, который отвечает за перемещение объекта во времени и (то, что должно быть виртуальным) метод GenerateContact() , который возвращает перпендикуляр столкновения и расстояние между объектами типа RigidBody .

Public class Circle extends RigidBody { private var m_radius:Number; /// /// /// public function Circle(pos:Vector2, radius:Number, invMass:Number) { m_radius = radius; super(pos, new Vector2(), invMass); } /// /// /// public override function GenerateContact(rb:RigidBody) :Contact { if (rb is Circle) { ... } else if (rb is ...) { ... } else { throw new Error("unahandled case!"); } } }

Также, у нас есть с класс Circle , который является производным класса RigidBody и расширяет его функционал наличием радиуса (параметр m_radius ). Также, в нем присутствует реализация метода GenerateContact() , который, по мере надобности, возвращает всю необходимую информацию.

Выделяя функционал в базовый класс и конкретные реализации, мы можем оперировать разными типами твердых тел (RigidBody) в одном списке, что значительно упрощает код.

Public class Plane extends RigidBody { private var m_n:Vector2; private var m_d:Number public function Plane(n:Vector2, d:Number) { m_n=n; m_d=d; super(n.MulScalar(-d), new Vector2(), 0); } /// /// /// public override function GenerateContact(rb:RigidBody):Contact { if (rb is Particle) { ... } else if (rb is Circle) { ... } else { throw new Error("unhandled case!"); } }

Выше приведена конкретная реализация другого класса, представляющего бесконечную плоскость (края нашего экрана).

Public class Contact { public var m_normal:Vector2; public var m_dist:Number; /// /// /// public function Contact(n:Vector2, dist:Number) { m_normal = n; m_dist = dist; } }

Выше вы можете видеть определение класса Contact , который позволит передать системе всю необходимую информацию о контакте для обработки столкновения.

Private function Update(e:GameLoopEvent):void { const dt:Number = Math.min(e.m_elapsed, 1.0/15.0); // apply gravity for each (var p:RigidBody in m_rigidBodies) { if (p.m_InvMass>0) { p.m_vel=p.m_vel.Add(Constants.kGravity.MulScalar(dt)); } } // collide for (var i:int=0; i<0||rbj.m_InvMass>0) { const c:Contact=rbi.GenerateContact(rbj); ... //resolve collision } // integrate for each (p in m_rigidBodies) { p.Integrate(dt); } }

Фрагмент кода выше демонстрирует, как в данный момент выглядит тело цикла обновления. Порядок тут очень важен;

  1. Сначала внешние силы — гравитация.
  2. Затем, определение столкновений, чтобы получить информацию о контакте и обработать ее.
  3. И наконец, каждый элемент RigidBody интегрируется во времени.

Фиксирование временного шага в начале, необходимо при отладке, чтобы не получить такое его значение, которое взрывало бы все!

Ограничения

Хорошо, теперь у нас есть множество сфер, взаимодействующих между собой, и наш физический движок приобретает форму, но что насчет ограничений?

Прежде чем начать рассматривать эту тему, я думаю, что должен объяснить некоторые термины, необходимые для понимания проблемы.

Ограничение

Грубо говоря, это то, что описывает как два твердых тела должны взаимодействовать между собой. Поэтому, когда происходит столкновение, мы создаем ограничение, которое вводит в действие правило, не позволяющее твердому телу проходить сквозь объект, с которым оно столкнулось, позволяя только толкать его. Мы уже писали код для этого выше (пока без учета вращения):

I = (1+e)*N*(V r . N) / (1/M a + 1/M b)

Все ограничения, с которыми мы будем иметь здесь дело, являются импульсно-скоростными. Сила и ускорение сюда не входят.

Ограничение-неравенство

Это ограничение, которое действует только в одном направлении. Таким образом, ограничение столкновения — это ограничение-неравенство, поскольку позволяет толкать, но не позволяет тянуть. Если бы это было позволено, то твердое тело приклеилось бы к объекту, с которым оно столкнулось. Мы приводим это ограничение в действие путем проверки, о которой я писал выше:

If (V N < 0) { // handle constaint }

Игра Little Big Planet содержит множество ограничений этого типа; лебедки, поршни, веревки, вот несколько примеров — им разрешено движение только в одном направлении в пределах ограничения. Так, например, движение поршня ограничено верхними и нижними границами.

Ограничение-равенство

Этот тип ограничения позволяет в равной степени, как толкать, так и тянуть. Примером может послужить ограничение от точки до точки, когда два твердых тела соединенны в одной точке — одна точка на каждом теле зафиксирована, и остается в одной позиции. Например, в шарнирном соединении, ось шарнира ограничена положением твердых тел. Ограничением для прута является его неизменная длина.

Проектирование ограничений

Прежде чем приступить к проектированию конкретного ограничения, следует подумать о том, какое ограничивающее влияние оно окажет на два твердых тела, связанных между собой.

Например, ограничение расстояния (прут в LBP), не позволяет двум точкам приблизиться (или удалиться) больше чем на указанное расстояние. Помещение конечных точек в центр масс твердых тел (случай, который я хотел бы описать), держит два круглых тела на фиксированном расстоянии друг от друга, но при этом позволяет им продолжать перемещаться в двухмерном пространстве.

Рисунок 2

Как вы можете видеть на Рисунке 2 , тела А и B никогда не окажутся к друг другу ближе чем на расстояние d , но в тоже время они могут перемещаться, что в конечном итоге позволяет им вращаться друг относительно друга.

Уровень импульса/скорости

Как я уже говорил выше, описываемая мною модель является симулятором уровня импульса/скорости, а не силы/ускорения. Это означает, что все ограничения должны быть реализованы с использованием импульсов для изменения скорости тел.

Это значит, что при проектировании этого ограничения вы должны подумать (на бумаге, со схемами) о том, как оно ведет себя на уровне позиция/расстояние. Затем, вам следует обдумать, как это все отразиться на скорости.

Резюмируем: ограничение расстояния не дает конечным точкам приближаться или отдаляться друг от друга. Говоря на языке скоростей — это одномерное ограничение; относительная скорость тел по заданной оси равняется нулю. Эта ось определяется вектором между конечными точками.

Рисунок 3

На Рисунке 3 , тела A и B имеют начальные скорости, которые нарушают указанное нами ограничение расстояния (Рисунок 2 ). Чтобы решить данную задачу, нам, для начала, необходимо выяснить фактические скорости объектов. В данном случае, их будут представлять проекции скоростей A v и B v на ось ограничения.

Как только мы получим скорости объектов, будет разумно превратить их в одну, относительную скорость (как мы делали это раньше, с касаниями). Также, выше, мы уже вывели формулу для одномерных ограничений (из ограничения касания):

I = (1+e)*N*(V r . N) / (1/M a + 1/M b)

Давайте немного отредактируем ее, чтобы она стала более читабельной:

I = RelativeVelocityMagnitudeToRemove / (1/M a + 1/M b)

В дополнение к этому, нам нужно будет внести некоторые корректировки в расчет позиции. Поскольку, когда в системе есть более чем одно активное ограничение, одной итерации будет мало. В данном случае, мы просто добавим искусственные поправки к рассчитанной скорости: (текущая длина — желаемая длина) / временной шаг.

Выше представлен результат — вы можете манипулировать кругами при помощи мыши. Один из них зафиксирован в одной точке для демонстрации ограничения цепи.

Пишем код

Итак, давайте давайте дополним существующий код:

Public class Constraint { protected var m_bodyA:RigidBody; protected var m_bodyB:RigidBody; /// /// /// public function Constraint(bodyA:RigidBody, bodyB:RigidBody) { m_bodyA = bodyA; m_bodyB = bodyB; Assert(m_bodyA.m_InvMass>0||m_bodyB.m_InvMass>0, "Constraint between two infinite mass bodies not allowed"); } /// /// /// public function ApplyImpulse(I:Vector2):void { m_bodyA.m_vel = m_bodyA.m_vel.Add(I.MulScalar(m_bodyA.m_InvMass)); m_bodyB.m_vel = m_bodyB.m_vel.Sub(I.MulScalar(m_bodyB.m_InvMass)); } /// /// /// public function Solve(dt:Number):void { throw new Error("base class doesn"t implement!"); } }

Из фрагмента кода выше видно, что мы добавили ещё один базовый класс. Он описывает основную часть ограничения, но в тоже время не содержит никаких конкретных деталей — как и раньше, мы оставляем это для определения в производных классах. Однако, он обеспечивает нас своего рода каркасом — каждое ограничение должно содержать реализацию метода Solve() , выполняющего большую часть работы. Кроме того, класс содержит метод ApplyImpulse() , который помогает нам избежать дублирования кода.

Public class DistanceConstraint extends Constraint { private var m_distance:Number; /// /// /// public function DistanceConstraint(bodyA:RigidBody, bodyB:RigidBody, distance:Number) { super(bodyA, bodyB); m_distance = distance; } /// /// /// public override function Solve(dt:Number):void { // get some information that we need const axis:Vector2 = m_bodyB.m_Pos.Sub(m_bodyA.m_Pos); const currentDistance:Number = axis.m_Len; const unitAxis:Vector2 = axis.MulScalar(1/currentDistance); // calculate relative velocity in the axis, we want to remove this const relVel:Number = m_bodyB.m_vel.Sub(m_bodyA.m_vel).Dot(unitAxis); const relDist:Number = currentDistance-m_distance; // calculate impulse to solve const remove:Number = relVel+relDist/dt; const impulse:Number = remove / (m_bodyA.m_InvMass + m_bodyB.m_InvMass); // generate impulse vector const I:Vector2 = unitAxis.MulScalar(impulse); // apply ApplyImpulse(I); } }

Выше показана реализация ограничения расстояния, принцип работы которого был описан выше.

Private var m_joints:Vector.;

Здесь, мы инициализируем список ограничений. Они отличаются от касаний (Contact ) своим постоянством, поэтому мы можем выделить их в отдельный список.

Const dt:Number = Math.min(e.m_elapsed, 1.0/15.0); // apply gravity for each (var p:RigidBody in m_rigidBodies) { ... } // collide for (var i:int=0; i0||rbj.m_InvMass>0) { ... } } } // solve constraints for each(var jt:Constraint in m_joints) { jt.Solve(dt); } // integrate for each (p in m_rigidBodies) { p.Integrate(dt); }

Так выглядит тело цикла обновления. Теперь здесь есть цикл для обработки ограничений. Я решил поместить его ниже обработки касаний, благодаря чему сделал соединения важнее, чем касания (это поведение будет более корректным, чем если бы мы поместили цикл выше обработки касаний). Вы же можете сделать наоборот, если захотите.

Заключение

Эта статья раскрыла физику, скрытую за самой простой 2d-игрой (pong), показав, что ее принципы основаны на реальных законах. Также, в статье подробно, шаг за шагом, изложена техника, используемая в данной игре, до того момента, когда проектирование ограничения и физического движка можно было бы рассматривать как расширенный случай столкновения двух объектов

Я надеюсь, от этой статьи у вас разыгрался аппетит для дальнейшего изучения имитации физики и она получилась простой для понимания.

Исходный код

К данной статье прилагается исходный код, который вы можете .

Исходный код к данной статье содержит весь код фреймворка (включая демки), написанный на actionscript 3.0 (применим для любого объектно-ориентированного языка).

Используются не как отдельные самостоятельные программные продукты , а как составные компоненты (подпрограммы) других программ.

Все физические движки условно делятся на два типа: игровые и научные .

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

Современные физические движки симулируют не все физические законы реального мира, а лишь некоторые, причём с течением времени и прогресса в области информационных технологий и вычислительной техники список «поддерживаемых» законов увеличивается. На начало 2010 года физические движки могут симулировать следующие физические явления и состояния:

  • динамика абсолютно твёрдого тела
  • динамика деформируемого тела
  • динамика газов
  • поведение верёвок (тросы, канаты и т.д.)

В августе 2009 года англоязычный журнал Game Developer (англ. ), посвящённый разработке компьютерных игр, опубликовал статью о современных игровых движках и их использовании. Согласно данным журнала, наиболее популярным среди разработчиков является движок nVidia PhysX , который занимает 26,8% рынка. На втором месте находится Havok , который занимает 22,7% рынка. Третье место принадлежит движку Bullet Physics Library (10,3%), а четвёртое - Open Dynamics Engine (4,1%).

Использование

Описание

Физический движок позволяет создать некое виртуальное пространство, которое можно наполнить телами (виртуальными статическими и динамическими объектами), и указать для него некие общие законы взаимодействия тел и среды, в той или иной мере приближенные к физическим, задавая при этом характер и степень взаимодействий (импульсы, силы и т. д). Собственно расчёт взаимодействия тел движок и берёт на себя. Когда простого набора объектов, взаимодействующих по определённым законам в виртуальном пространстве, недостаточно в силу неполного приближения физической модели к реальной, возможно добавлять (к телам) связи. Рассчитывая взаимодействие тел между собой и со средой, физический движок приближает физическую модель получаемой системы к реальной, передавая уточнённые геометрические данные средству отображения (рендереру).

Тело

Тело (англ. body ) - объект игровой физики, который определяется:

  • его формой (есть простые формы: шар, куб, цилиндр; есть сложные формы, набор которых в разных движках может различаться);
  • неким набором параметров (масса, упругость, коэффициент трения, инертность по осям).

Связь

Связь (соединение; англ. joint ) - ограничения объектов игровой физики, каждое из которых может накладываться на одно или два тела.

Взаимодействие

Как правило, физический движок и решает проблему взаимодействия тел. Тем не менее, может появиться необходимость использования собственного алгоритма взаимодействия, и, как правило, движки предоставляют такую возможность.

Известные физические движки

Игровые проприетарные

Игровые свободные

Ныне несуществующие

  • NovodeX - физический движок, приобретённый компанией Ageia и преобразованный в PhysX.
  • Meqon - физический движок, приобретённый компанией Ageia и интегрированный в состав её движка PhysX.
  • Ipion Virtual Physics - физический движок, приобретённый компанией Havok и интегрированный в состав её движка Havok Physics;
  • Karma - коммерческий движок от ныне закрытой компании MathEngine , интегрирован в Unreal Engine 2.0/2.5 .

Другие

  • Open Physics Initiative - проект, инициированный компаниями AMD и Pixelux Entertainment по объединению Bullet Physics Library и Digital Molecular Matter , добавлении в новообразованный продукт поддержки OpenCL и DirectCompute и оптимизации результирующего движка для выполнения на графических процессорах Radeon .

См. также

Напишите отзыв о статье "Физический движок"

Примечания

Ссылки

  • - общая информация о физических движках на сайте GameDev.ru
  • - список терминов и понятий, относящихся к программированию физических движков на сайте GameDev.ru
  • Lentyay. . gamesector.org (23 октября 2006 года). Проверено 7 июля 2009. .
  • Lentyay. . gamesector.org (2 ноября 2006 года). Проверено 7 июля 2009. .
  • Lentyay. . gamesector.org (16 мая 2007 года). Проверено 7 июля 2009. .
  • Andretti. . ITC.ua (3 декабря 2007 года). - Подборка скриншотов из компьютерных игр, которая демонстрирует развитие визуализации воды. Проверено 2 августа 2009. .
  • Zogrim. (англ.) . (7 декабря 2009 года). Проверено 11 марта 2010. .
  • Наталья Зайцева. . Intel Software Network (6 октября 2009 года). Проверено 21 марта 2010. .

Отрывок, характеризующий Физический движок

– Vous ne daignez pas descende jusqu"a moi, vous… [Вы не удостаиваете снизойти до брака со мною, вы…] – заплакав, сказала Элен.
Лицо стало утешать ее; Элен же сквозь слезы говорила (как бы забывшись), что ничто не может мешать ей выйти замуж, что есть примеры (тогда еще мало было примеров, но она назвала Наполеона и других высоких особ), что она никогда не была женою своего мужа, что она была принесена в жертву.
– Но законы, религия… – уже сдаваясь, говорило лицо.
– Законы, религия… На что бы они были выдуманы, ежели бы они не могли сделать этого! – сказала Элен.
Важное лицо было удивлено тем, что такое простое рассуждение могло не приходить ему в голову, и обратилось за советом к святым братьям Общества Иисусова, с которыми оно находилось в близких отношениях.
Через несколько дней после этого, на одном из обворожительных праздников, который давала Элен на своей даче на Каменном острову, ей был представлен немолодой, с белыми как снег волосами и черными блестящими глазами, обворожительный m r de Jobert, un jesuite a robe courte, [г н Жобер, иезуит в коротком платье,] который долго в саду, при свете иллюминации и при звуках музыки, беседовал с Элен о любви к богу, к Христу, к сердцу божьей матери и об утешениях, доставляемых в этой и в будущей жизни единою истинною католическою религией. Элен была тронута, и несколько раз у нее и у m r Jobert в глазах стояли слезы и дрожал голос. Танец, на который кавалер пришел звать Элен, расстроил ее беседу с ее будущим directeur de conscience [блюстителем совести]; но на другой день m r de Jobert пришел один вечером к Элен и с того времени часто стал бывать у нее.
В один день он сводил графиню в католический храм, где она стала на колени перед алтарем, к которому она была подведена. Немолодой обворожительный француз положил ей на голову руки, и, как она сама потом рассказывала, она почувствовала что то вроде дуновения свежего ветра, которое сошло ей в душу. Ей объяснили, что это была la grace [благодать].
Потом ей привели аббата a robe longue [в длинном платье], он исповедовал ее и отпустил ей грехи ее. На другой день ей принесли ящик, в котором было причастие, и оставили ей на дому для употребления. После нескольких дней Элен, к удовольствию своему, узнала, что она теперь вступила в истинную католическую церковь и что на днях сам папа узнает о ней и пришлет ей какую то бумагу.
Все, что делалось за это время вокруг нее и с нею, все это внимание, обращенное на нее столькими умными людьми и выражающееся в таких приятных, утонченных формах, и голубиная чистота, в которой она теперь находилась (она носила все это время белые платья с белыми лентами), – все это доставляло ей удовольствие; но из за этого удовольствия она ни на минуту не упускала своей цели. И как всегда бывает, что в деле хитрости глупый человек проводит более умных, она, поняв, что цель всех этих слов и хлопот состояла преимущественно в том, чтобы, обратив ее в католичество, взять с нее денег в пользу иезуитских учреждений {о чем ей делали намеки), Элен, прежде чем давать деньги, настаивала на том, чтобы над нею произвели те различные операции, которые бы освободили ее от мужа. В ее понятиях значение всякой религии состояло только в том, чтобы при удовлетворении человеческих желаний соблюдать известные приличия. И с этою целью она в одной из своих бесед с духовником настоятельно потребовала от него ответа на вопрос о том, в какой мере ее брак связывает ее.
Они сидели в гостиной у окна. Были сумерки. Из окна пахло цветами. Элен была в белом платье, просвечивающем на плечах и груди. Аббат, хорошо откормленный, а пухлой, гладко бритой бородой, приятным крепким ртом и белыми руками, сложенными кротко на коленях, сидел близко к Элен и с тонкой улыбкой на губах, мирно – восхищенным ее красотою взглядом смотрел изредка на ее лицо и излагал свой взгляд на занимавший их вопрос. Элен беспокойно улыбалась, глядела на его вьющиеся волоса, гладко выбритые чернеющие полные щеки и всякую минуту ждала нового оборота разговора. Но аббат, хотя, очевидно, и наслаждаясь красотой и близостью своей собеседницы, был увлечен мастерством своего дела.
Ход рассуждения руководителя совести был следующий. В неведении значения того, что вы предпринимали, вы дали обет брачной верности человеку, который, с своей стороны, вступив в брак и не веря в религиозное значение брака, совершил кощунство. Брак этот не имел двоякого значения, которое должен он иметь. Но несмотря на то, обет ваш связывал вас. Вы отступили от него. Что вы совершили этим? Peche veniel или peche mortel? [Грех простительный или грех смертный?] Peche veniel, потому что вы без дурного умысла совершили поступок. Ежели вы теперь, с целью иметь детей, вступили бы в новый брак, то грех ваш мог бы быть прощен. Но вопрос опять распадается надвое: первое…
– Но я думаю, – сказала вдруг соскучившаяся Элен с своей обворожительной улыбкой, – что я, вступив в истинную религию, не могу быть связана тем, что наложила на меня ложная религия.
Directeur de conscience [Блюститель совести] был изумлен этим постановленным перед ним с такою простотою Колумбовым яйцом. Он восхищен был неожиданной быстротой успехов своей ученицы, но не мог отказаться от своего трудами умственными построенного здания аргументов.
– Entendons nous, comtesse, [Разберем дело, графиня,] – сказал он с улыбкой и стал опровергать рассуждения своей духовной дочери.

Элен понимала, что дело было очень просто и легко с духовной точки зрения, но что ее руководители делали затруднения только потому, что они опасались, каким образом светская власть посмотрит на это дело.
И вследствие этого Элен решила, что надо было в обществе подготовить это дело. Она вызвала ревность старика вельможи и сказала ему то же, что первому искателю, то есть поставила вопрос так, что единственное средство получить права на нее состояло в том, чтобы жениться на ней. Старое важное лицо первую минуту было так же поражено этим предложением выйти замуж от живого мужа, как и первое молодое лицо; но непоколебимая уверенность Элен в том, что это так же просто и естественно, как и выход девушки замуж, подействовала и на него. Ежели бы заметны были хоть малейшие признаки колебания, стыда или скрытности в самой Элен, то дело бы ее, несомненно, было проиграно; но не только не было этих признаков скрытности и стыда, но, напротив, она с простотой и добродушной наивностью рассказывала своим близким друзьям (а это был весь Петербург), что ей сделали предложение и принц и вельможа и что она любит обоих и боится огорчить того и другого.
По Петербургу мгновенно распространился слух не о том, что Элен хочет развестись с своим мужем (ежели бы распространился этот слух, очень многие восстали бы против такого незаконного намерения), но прямо распространился слух о том, что несчастная, интересная Элен находится в недоуменье о том, за кого из двух ей выйти замуж. Вопрос уже не состоял в том, в какой степени это возможно, а только в том, какая партия выгоднее и как двор посмотрит на это. Были действительно некоторые закоснелые люди, не умевшие подняться на высоту вопроса и видевшие в этом замысле поругание таинства брака; но таких было мало, и они молчали, большинство же интересовалось вопросами о счастии, которое постигло Элен, и какой выбор лучше. О том же, хорошо ли или дурно выходить от живого мужа замуж, не говорили, потому что вопрос этот, очевидно, был уже решенный для людей поумнее нас с вами (как говорили) и усомниться в правильности решения вопроса значило рисковать выказать свою глупость и неумение жить в свете.

Physics Engine — является базовым объектом для создания физического мира. Он необходим, чтобы работали физико-ориентированные объекты. Этот объект должен присутствовать в кадре, если вы используете один из физических типов движений.
Physics Engine содержит ряд настроек мира и контролирует объекты в физическом мире.

Свойства движка Physics Engine

  • Gravity (Вес)
    • Gravity strength (Сила тяжести)
      Параметр силы тяжести в физическом мире. Значение земного тяготения составляет около 10 (точно 9,81), поэтому значение по умолчанию для этого свойства установлено 10.000000. Вы можете изменить это значение в соответствующем действии.
    • Gravity angle (Направление силы тяготения)
      На Земле гравитация направлена, как бы, вниз, но вы можете установить направление притяжение в любую сторону.
      Направление силы тяжести также может быть изменено с применением действия.
  • Backdrops (Декорации / фон / элементы препятствий)
  • Projectiles (Пули / Снаряды)
    • Create projectiles in the physical world (Создавать пули в физическом мире)
      Если установлен этот параметр, то в действии Launch an object будет создаваться пуля физического мира, но при условии, что объект, из которого пуля запущена имеет один из физических движений. Если одно из этих условий ложно, то будет создана обычная (не физическая) пуля.
    • Density (Плотность)
      Плотность пуль, созданных действием Launch an object . При плотности равной 100 пуля будет тяжелее, и, следовательно, труднее перемещать при столкновении с другими объектами, но другой стороны, пуля будет сильнее толкать статические объекты. Меняя значение плотности вы меняете массу пуль. Масса объекта вычисляется в физике из значений плотности и размеров объекта.
    • Friction (Трение)
      Это свойство определяет, как пули ведут себя, когда они сталкиваться с другим объектами. Значение трения от 0 до 100 определит насколько скользящими будут пули.
    • Elasticity (Упругость)
      В значении 0 пуля остановится, как только столкнется с другим объектом. В значении 100 пули будут отскакивать, сохраняя динамику их движения. Промежуточные значения изменяют этот импульс.
    • Gravity scale (Гравитация масштаб)
      Это процентное значение, указывающее, насколько сильно сила тяжести будет действовать на пулю. Значение 100 — нормальная гравитация, в соответствии с силой притяжения установленной в движке Physic Engine. Значение 0 позволит пули лететь по прямой линии. Значение 200 увеличит в 2 раза силу притяжения действующую на пулю, и, таким образом, пуля упадет быстрее.
  • Non-physical objects (Не физические объекты)
  • Advanced (Расширенные настройки)
    • Engine ID (ID движка)
      Это свойство следует изменять только если вы решите использовать более одного объекта физического движка в кадре (например для того что бы сделать разную силу тяжести). Это свойство содержит номер (он должен быть уникальным), затем этот номер прописывается в свойствах объектов, что бы указать какому движку он подчиняется.
    • Display factor (Фактор отображения)
      Box2D работает с единицами измерения в метрах и килограммах. В Clickteam Fusion 2.5 размеры кадра и объектов исчисляются в пикселях. Это свойство содержит коэффициент умножения и координирует размеры Clickteam Fusion 2.5 при передаче их в физический мир. Значение 32 означает, что объект 32 пикселей в ширину, будет иметь ширину 1 м в физическом мире.
      Значение 32 отлично работает для большинства игр. Но если ваша игра содержит очень большие объекты, движок не может справиться с ними. Поэтому вы должны, изменить это значение в зависимости от размера ваших объектов. Более высокое значение уменьшает размер объектов в физическом мире. Меньшее значение увеличивает их.
      Также стоит отметить, что как результат расчета, объекты двигаются быстрее с более низкими значениями этого свойства.
    • Velocity iterations (Скорость итераций)
      Это свойство используется, чтобы определить точность обработки физического мира. Движок работает, оценивая столкновения различных объектов, чем больше значение этого параметра, тем точнее результат вычислений, но и медленнее движок.
      Значение по умолчанию 6 должно быть достаточным для большинства игр. Но если в вашей игре какая-то сложная реализация, которая требует большой точности, то необходимо увеличить это значение. Пожалуйста, обратите внимание, что это будет экспоненциально тормозить движок.
      Можно, например, установить это свойство в более высокое значение, что бы точно произвести вычисления в начале кадра, а затем стабилизировать, установив его в меньшее значение во время игры, с помощью действия «Set iterations «.
    • Position iterations (Итерация позиции)
      Это свойство похоже на предыдущее, и влияет на вычисление положения объектов в физическом мире. Значение по умолчанию 2 должно быть достаточно для большинства игр, но вы также можете увеличить, если для вас движок не будет достаточно точным. Чем выше значение, тем медленнее будет движок, поэтому выбор правильной величины должен быть результатом практической оценки.

Действия движка Physics Engine

  • World
    • Add object to world Добавить объект в мир.
      Позволяет вставлять не физические объекты (например, активный объект с простым движением) в физическом мире.
      Эта функция позволяет использовать простой тип движения path в физическом мире. Например, когда вы делаете движущуюся платформу или врагов-охранников, которые движутся из стороны в сторону. Просто добавьте не физический тип движения по траектории в мир.
    • Remove object from world
      Это действие удалят объект, который был добавлен в физический мир. Он не разрушает объект, объект будет оставаться на сцене, но станет не физическим.
    • Set gravity force
      Это действие изменяет текущий коэффициент силы притяжения в мире. Значение 10 (точно 9,81) совпадает с земной гравитацией. Вес 0 создаст невесомость.
    • Set gravity angle
      Это действие изменяет направления силы притяжения. Угол в градусах (от 0 до 360). Все объекты мира будут мгновенно реагировать на изменение угла притяжения.
    • Set iterations
      Изменение точности вычислений движка путем установки количества итераций, выполняемых движком. Первым параметром является скорость итераций (значение по умолчанию 6), и второй параметр — это количество итераций (значение по умолчанию равно 2). Подробнее об это свойство еще будет описано ниже.
  • Objects
    В действиях движка можно менять физические параметры (плотность, трение, гравитационной масштаб и упругость) любого физического объекта.
  • Joints
    Clickteam Fusion 2.5 позволяет создавать различные типы соединений, поддерживаемых Box2D. Вы должны ввести имя, когда вы создаете соединение, так как это имя будет использоваться для обращение к суставу. Позволяя вам делать следующее:
    • Distance joints
      Расстояние между двумя соединенными объектами. Для того, что бы применять это действие два тела уже должны быть на соединены.

      • Joint two objects at hot spots
        Создает дистанцию сустава в месте расположения горячей точки (hot spot — точка привязки координат со значком глаза) двух объектов. После создания расстояние между двумя объектами будет оставаться постоянным (если только на объект не будет оказано действительно сильное воздействие).

      • Создает дистанцию сустава в месте расположения активных точек (action point — квадратная) связаных объектов.

      • Создает дистанцию соединения в заданных координатах внутри объектов. Вам нужно будет указать значения смещения от точки реальной координаты (hot spot) объектов.
      • Set joint elasticity
        Делает пружинное соединение между двумя объектами, как будто они соединены резинкой. Это действие принимает два параметра: первый — частота колебаний пружины/резинки, в герцах (Гц). Значение 10 заставит резинку сокращаться 10 раз в секунду. Вы не должны вводить значения выше 30 (для FPS приложений — 50). Второй параметр — коэффициент затухания, значение от 0 до 100: значение 0 приведет к тому, что резинка всегда будет колебаться, 100 будет останавливаться мгновенно.
    • Revolute joints
      Когда скреплены два объекта, где будет их ось вращения? Осью вращения может являться точка координат одного из объектов или точка соединения этих объектов.


      • Создает ось вращения на месте расположения точки координат (hot spot) первого объекта. Объекты будут вращаться вокруг своей оси, и также они не отделяются друг от друга.
      • Joint two objects at action point
        Создает ось вращения на месте расположения активной точки (action point) первого объекта. Объекты будут вращаться вокруг своей оси, и также они не отделяются друг от друга.
      • Joint two objects at position
        Создает ось вращения в заданных координатах первого объекта. Значение является смещением от горячей точки (hot-spot) объекта.
      • Set joint angle limits
        Действие позволяет ограничить вращение второго объекта в конкретной области угла. Он принимает два параметра, меньший предел угла (значение в градусах от 0 до 360), и верхний предел угла (выражается в градусах от 0 до 360). Если оба значения равны 0, предел будет удален (не будет предела вращения).
      • Set joint motor
        Заставляет принудительно вращаться второй объект. Действие создает «крутящий момент». Первый параметр — по часовой или против часовой, значение от -250 (вращение против часовой стрелки) до +250 (вращение по часовой стрелке), второй параметр — скорость вращения, значение от 0 до 100.
    • Prismatic joints
      Призматическое соединение придает относительное перемещение двух объектов вдоль указанной оси. Призматическое соединение предотвращает относительное вращение вокруг оси. Таким образом, призматическое соединение имеет одну степень свободы.

      • Joint two objects at hot spot
        Создает призматические соединения в месте расположения горячей точки (hot-spot) двух объектов. После того, как соединение создано, объекты будут оставаться в той же оси.
      • Joint two objects at action point
        Создает призматический сустав в месте расположения активной точки (action point) двух объектов.
      • Joint two objects at position
        Создает призматическое соединение в заданных координатах внутри объектов. Значения добавляет смещение от горячей точки (hot-spot) объектов.
      • Set joint translation limits
        Действие позволяет ограничить движение объектов до определенной части оси. Первый параметр является нижним пределом, задается в пикселях от позиции первого объекта, а второй параметр, верхний предел, также выражается в пикселях от первого объекта.
      • Set joint motor
        Действие приводит в движение второй объект от (или к) первого объекта. Первым параметром является направление движения, значение от -250 (сближает объекты) до 250 (объекты движутся друг от друга). Вторым параметром является скорость движения, значение от 0 до 250.
    • Pulley joints
      Шкив соединяет два объекта с планкой и друг с другом. Когда один объект поднимается вверх, другой опускается вниз.
      • Joint two objects at hot spot
        Создает соединение шкив на месте расположения горячей точки двух объектов. Вы должны указать длину (в пикселях) и угол (в градусах от 0 до 360) веревки, прикрепленной к двум объектам. После того, как объекты создаются, они будут связаны друг с другом невидимой веревкой. Последний параметр является передаточным отношением, значение от 0 до 100.
      • Joint two objects at action point
        Создает соединение шкива в месте расположения активной точки двух объектов. Как и в предыдущем действии, вы должны указать длину (в пикселях) и угол (в градусах от 0 до 360) веревок, прикрепленных к двум объектам. Последний параметр представляет собой передаточное отношение, значение от 0 до 100. Например, если использовать значение 50, второй объект будет двигаться в половину скорости первого объекта.
  • Destroy joint
    Действие уничтожает сустав. После этого объекты будут свободно перемещаться.

События движка Physics Engine

Сам объект движка Physics Engine не содержит никаких событий или условий.

Значения движка Physics Engine для различных выражений

  • Gravity
    • Angle
      Возвращает текущее направление гравитации, выраженная в градусах (от 0 до 360).
    • Strength
      Возвращает текущую силу тяжести, выраженная в метрах за секунду в квадрате.
  • Iterations
    • Velocity iterations
      Возвращает текущее число итераций скорости.
    • Position iterations
      Возвращает текущее количество итераций позиции.
  • Distance joints
    • Frequency
      Возвращает коэффициент упругости в суставах, измеряется в герцах, и является значением заданном в действии «Set elasticity».
    • Damping
      Возвращает коэффициент затухания в суставах, значение от 0 до 100, и является значением заданном в действии «Set elasticity».
  • Revolute joints
    • Lower angle limit
      Возвращает нижний предел угла сустава, значение, выраженное в градусах, которое определено в действии «Set angle limit».
    • Upper angle limit
      Возвращает верхний предел угла сустава, значение, выраженное в градусах, которое определено в действии «Set angle limit».
    • Motor strength
    • Motor speed
  • Prismatic joints
    • Lower translation limit
      Возвращает нижний предел ограничивающий движение объектов по оси, значение, выраженное в пикселях, и является значением заданном в действии «Set translation limit».
    • Upper translation limit
      Возвращает верхний предел ограничивающий движение объектов по оси, значение, выраженное в пикселях, и является значением заданном в действии «Set translation limit».
    • Motor strength
      Возвращает моторную силу в суставе (вращательный момент), значение от 0 до 100, которое определено в действии «Set motor».
    • Motor speed
      Возвращает скорость вращения в суставе, значение от 0 до 100, которое определено в действии «Set motor».

Это нужно знать о Physics Engine Object

Замечания, касающиеся физических движений в Clickteam Fusion 2.5, и так их обрабатывает движок физики.

Большие и плотные объекты
Движок не может справиться с объектами, которые являются слишком тяжелыми. Тяжелыми предметами являются крупные объекты с плотностью, близкой к 100. Если свалить такие объекты в кучу, то они будут вызывать ошибки расчетов движка и объекты будут мерцать на экране.
Можно решить эту проблему путем уменьшения плотности объектов.
Вы также можете решить эту проблему путем увеличения скорости и позиции итераций в движке Physics Engine Object, либо изменив масштаб.

Груды объектов не могут стабилизироваться
Если ваш кадр содержит кучу объектов, и если эта куча не останавливается в статическом положении через некоторое время, это может быть связано с неточностью расчетов в физическом движке. Параметры движка устанавливаются, чтобы был баланс между скоростью выполнения и точностю вычислений. Вы можете увеличить эту точность в течение определенного периода времени (в начале кадра в событии start of frame), а когда все объекты найдут свое место, вернуть ее к нормальному значению.
Чтобы сделать это, вы должны использовать действие «Set engine iterations» в движке Physics Engine object. Значение по умолчанию составляет 6 и 2. Вы можете увеличить, чтобы увидеть результат.

Движущиеся объекты, кажется, сталкиваются далеко от фоновых объектов
Эта проблема может возникнуть, если ваш объект имеет вогнутую форму. Box2D не принимает вогнутые формы. Вы должны сократить свой объект в несколько, выпуклых объектов.
Более подробная информация .

Народ, черкните в комментах был ли для вас полезен перевод и нужны ли другие переводы? Спасибо.

Physics Engine - является базовым объектом для создания физического мира. Он необходим, чтобы работали физико-ориентированные объекты. Этот объект должен присутствовать в кадре, если вы используете один из физических типов движений. Physics Engine содержит ряд настроек мира и контролирует объекты в физическом мире. Свойства движка Physics Engine Gravity (Вес) Gravity strength (Сила тяжести) Параметр силы тяжести в физическом мире. Значение земного тяготения составляет около 10 (точно 9,81), поэтому значение по умолчанию для этого свойства установлено 10.000000. Вы можете изменить это значение в соответствующем действии. Gravity angle (Направление силы тяготения) На Земле гравитация направлена, как бы, вниз, но вы можете установить направление…

Физический движок Physics Engine

Физический движок Physics Engine

Источник: codingclub

ВОЗМОЖНОСТИ СУЩЕСТВУЮЩИХ ДВИЖКОВ

НЕ ИМЕЕТ СМЫСЛА МНОГО ГОВОРИТЬ О ТОМ, ЧТО В СОВРЕМЕННЫХ ИГРАХ ОЧЕНЬ ЧАСТО ИСПОЛЬЗУЮТСЯ ФИЗИЧЕСКИЕ СИМУЛЯЦИИ РАЗЛИЧНОГО РОДА. ФИЗИКА УЖЕ ДАВНО (И НАДОЛГО) ПРОТОПТАЛА ДОРОЖКУ В СИМУЛЯТОРЫ, В ОСНОВНОМ АВТОМОБИЛЬНЫЕ

Физика используется и как основной элемент геймплея (хардкорные симуляторы), и как средства к получению дополнительных эмоций у игрока (различного рода разрушения). Также есть ряд жанров, в которых массовое применение физики началось сравнительно недавно - это прежде всего шутеры и игры с видом от третьего лица. Спектр использования физических эффектов в них очень широк: от достаточно простых rag-dolls и пинания ящиков до попыток завязать часть геймплея на физику (Half-life 2, Psi-ops и т.д.). Кроме всего перечисленного, существует ряд игровых жанров, в которых физика не нужна в принципе, к примеру в пошаговых глобальных стратегиях. В целом на сегодня физика в играх является важнейшим элементом, но несмотря на это раскручена не так, как графика.

немного терминологии

физический движок (фд)

ФД - библиотека, которая рассчитывает физические взаимодействия между объектами игрового мира (симулируется физика, описываемая законами Ньютона). Физические движки, используемые при разработке игр, как правило, не симулируют физические процессы игрового мира со 100% точностью, а лишь производят достаточно точную аппроксимацию физических законов. Современные игровые физические движки состоят из двух частей: подсистемы определения столкновений и подсистемы расчета физических взаимодействий.

подсистема определения столкновений

Основные два параметра подсистемы определения столкновений: скорость работы и точность определения столкновений. Недостаточная точность приводит к появлению разных артефактов, таких как перекрытие объектов, неопределение столкновений при существенно разных размерах и скоростях объектов и т.д. Для ускорения работы подсистемы столкновений используют различного рода разбиения пространства на подпространства, такие как quadtree (рекурсивное деление пространства на четыре подпространства) или осtree (деление на восемь подпространств), для снижения количества проверок столкновений. Системы столкновений работают дискретно - столкновения рассчитываются через определенные промежутки времени. Итак, такого рода системы могут приводить к тому, что столкновения с участием быстро движущихся объектов не фиксируются - для борьбы с подобного рода артефактами некоторые системы столкновений поддерживают так называемый continuous collision detection (CCD) (системы непрерывного отслеживания столкновений). Суть метода continuous collision detection заключается в том, что проверка столкновений между двумя объектами производится не между ними самими в дискретные моменты времени, а между вытянутыми объемами, которые представляют движение объектов в течение всего временного шага.

подсистема симуляции (пс)

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

Подавляющее большинство физических движков может (с различным успехом) симулировать физику твердого тела (Rigid body simulation). Твердое тело - это тело, которое не меняет свою форму (к ним можно отнести кирпич, стол, стену и т.д.). На данный момент подавляющее большинство игр использует именно физику твердого тела, главным образом потому, что с приемлемой производительностью может обсчитываться лишь физика твердого тела. Для представления объема твердых тел, в зависимости от движка, могут использоваться как различные примитивные тела (прямоугольники, сферы, цилиндры, конусы и т.д.), так и более сложные (карты высот, выпуклые многогранники или невыпуклые многогранники). Если используются только примитивные тела, более сложные тела описываются с помощью аппроксимации примитивами. Для описания свойств твердых тел используется понятие материала, который описывается параметрами: коэффициент трения (может быть два: коэффициент трения покоя, который показывает, как тяжело сдвинуть тело, и коэффициент трения движения, который показывает, как тяжело удерживать тело в движении), упругость (сколько энергии остается после столкновения с другим телом). Помимо этих параметров, могут быть и другие. Твердое тело также имеет массу. Движение твердых тел описывается при помощи линейной, угловой скорости и ускорения. Хотя движки позволяют устанавливать эти параметры непосредственно, воздействия на тела, как правило, осуществляют при помощи приложения либо физических сил (влияют на ускорения тел), либо импульсов (влияют на скорости).

На базе физики твердого тела реализуется также физическое поведение персонажей и широко известный эффект тряпичной куклы (rag-doll), который заключается в том, что персонаж (чаще всего мертвый) падает вниз, как тряпичная кукла. Для реализации подобного рода поведения только твердых тел недостаточно. Используются так называемые сочленения (joint) или ограничения (constraint).

Джоинт - это точка, которая соединяет два твердых тела (соединение обычно задается относительно точки джоинта) и накладывает ограничения на положение тел в пространстве друг относительно друга или на скорости тел относительно друг друга. Типов джоинтов много (некоторые движки позволяют писать собственные). Для реализации рэгдолов используют ball-joint и hinge-joint. Ball-joint - это шарнирное соединение двух тел, оно ограничивает перемещение тел друг относительно друга и налагает ограничение на то, как повернуты тела относительно друг друга по трем осям (при помощи джоинтов такого типа в регдолле крепится плечо или голова к телу). Hinge-joint - это петельное соединение двух тел, которое ограничивает повороты тел относительно друг друга одной осью. В целом же спектр применения джоинтов очень широк и не ограничивается только созданием rag-dolls.

Помимо физики твердого тела, различные физические движки могут реализовывать дополнительные возможности: специальную поддержку симуляции движения автомобилей, симуляцию воды и прочих жидкостей, симуляцию тканей и одежды, симуляцию частиц, дополнительную поддержку для симуляции персонажей - высокоуровневые контроллеры персонажей, встроенную поддержку rag-dolls, поддержку анимации и т.д.

физика и разработка игры

Наличие физики в игре накладывает отпечаток на весь процесс разработки. В зависимости от того, каков объем и характер физических фич, могут быть затронуты практически все аспекты производственного процесса - от геймплея до контента.

Как делать физику - этот вопрос требует решения. На одном полюсе - решение о том, чтобы писать физику самостоятельно. На другом полюсе - покупка готового решения, которое полностью покроет спектр поставленных задач. Где-то посредине находится такой вариант: модифицировать существующий, но далеко не на 100% подходящий движок. Как и в остальных областях разработки ПО, данное решение зависит от множества факторов: наличия средств, наличия персонала, наличия подходящих решений и т.д.

В зависимости от выбора и требований к физике сложность разработки может значительно колебаться. Если же рассматривать одну и ту же игру с физикой и без нее, при прочих равных, то вариант с физикой (достаточно объемной) затронет всех участников производственного процесса. Наличие физики прежде всего влияет на архитектуру кода игры: введение такой сложной подсистемы влияет и на графику, и на искусственный интеллект, и даже на ввод пользователя.

Помимо архитектурных моментов, в команде разработчиков появляется новая роль - программист физики, который будет вынужден заниматься вопросами реализации воплощения физических фич (эта доля тяжелая и неблагодарная). Наличие физики повлияет и на геймдизайн. С одной стороны, можно будет добавлять различные физические геймлей-фичи, с другой стороны, появится дополнительная забота о том, как физика скажется на остальном геймплее. Также физика затрагивает и производство контента для игры: придется создавать физические модели объектов, настраивать материалы, rag-dolls и джоинты.

Добавление физики в игру усложняет процесс разработки продукта и требует дополнительных ресурсов.

обзор существующих решений

До недавнего времени ситуация на рынке физических движков была довольно стабильна. Существовало несколько бесплатных физических движков (разного качества), а также ряд коммерческих физических движков. Однако в ушедшем 2005 году компания AGEIA анонсировала первый в истории игровой индустрии ускоритель физики, который снимает с центрального процессора задачу расчета физики. Ускоритель пока еще не появился в продаже, но его создатели утверждают, что их продукт будет способен обсчитывать порядка 40 000 объектов (на данный момент количество физических объектов, обсчитываемых на ПК, составляет десятки).

Ниже рассмотрим основные физические движки, которые существуют на сегодня. Помимо чисто физических движков, существует масса игровых движков, которые содержат физические подсистемы, написанные поверх одной из библиотек (на www.devmaster.net/engines можно ознакомиться с игровыми движками).

PhysX (www. ageia.com, коммерческий)

Эта физическая технология предоставляется компанией AGEIA и как физический движок, и как АПИ для работы с их физическим ускорителем. На данный момент ряд игровых компаний заявили о поддержке этой технологии в своих продуктах (в том числе Unreal Engine).

Возможности PhysX:

СИМУЛЯЦИЯ ТВЕРДЫХ ТЕЛ, В КАЧЕСТВЕ ФИЗИЧЕСКОГО ПРЕДСТАВЛЕНИЯ МОГУТ ИСПОЛЬЗОВАТЬСЯ ПРИМИТИВЫ (ПЛОСКОСТИ, БОКСЫ, КАПСУЛЫ) И ВЫПУКЛЫЕ МНОГОУГОЛЬНИКИ, А ТАКЖЕ ИХ КОМБИНАЦИИ;

ПОЛНОСТЬЮ НАСТРАИВАЕМЫЕ ДЖОИНТЫ С ШЕСТЬЮ СТЕПЕНЯМИ СВОБОДЫ;

СИМУЛЯЦИЯ ЖИДКОСТЕЙ;

ФИЗИЧЕСКОЕ ВЗАИМОДЕЙСТВИЕ МЕЖДУ ЖИДКОСТЯМИ И ТВЕРДЫМИ ТЕЛАМИ;

КОНТРОЛЛЕРЫ ПЕРСОНАЖЕЙ (ПЕРСОНАЖ МОЖЕТ СОСТОЯТЬ ИЗ БОКСОВ И КАПСУЛ), ПОЗВОЛЯЮЩИЕ АВТОМАТИЧЕСКИ ПЕРЕМЕЩАТЬСЯ ПО ЛЕСТНИЦАМ;

АВТОМОБИЛИ НА ОСНОВЕ ТРЕЙСИНГА ЛУЧА;

ПОДДЕРЖКА НЕСКОЛЬКИХ СЦЕН;

СИСТЕМА СТОЛКНОВЕНИЯ ПОДДЕРЖИВАЕТ НЕПРЕРЫВНОЕ ОТСЛЕЖИВАНИЕ СТОЛКНОВЕНИЙ;

МУЛЬТИПЛАТФОРМЕННОСТЬ;

МНОГОПОТОЧНОСТЬ.

Havok (www.havok.com, коммерческий)

Один из старейших физических движков. На нем сделаны десятки игр (посмотреть их список можно по адресу www.havok.com/content/blogcategory/29/73). Недавно Havok анонсировал новую технологию расчета физики Havok FX, которая производит расчеты физики на видеокартах используя шейдеры 3.0.

Возможности Havok:

ФИЗИКА ТВЕРДОГО ТЕЛА;

ДЖОИНТЫ;

КОНТРОЛЛЕРЫ ПЕРСОНАЖЕЙ (ПОЗВОЛЯЮТ ПЕРСОНАЖАМ ПЕРЕМЕЩАТЬСЯ ПО ЛЕСТНИЦАМ);

МУЛЬТИПЛАТФОРМЕННОСТЬ;

МНОГОПОТОЧНОСТЬ.

Trueaxis (www.trueaxis.com)

Бесплатный для некоммерческого использования. Исходники закрыты.

Возможности:

ФИЗИКА ТВЕРДОГО ТЕЛА;

СИСТЕМА СТОЛКНОВЕНИЯ ПОДДЕРЖИВАЕТ НЕПРЕРЫВНОЕ ОТСЛЕЖИВАНИЕ СТОЛКНОВЕНИЙ;

В КАЧЕСТВЕ ПРЕДСТАВЛЕНИЯ МОГУТ ИСПОЛЬЗОВАТЬСЯ ВЫПУКЛЫЕ МНОГОУГОЛЬНИКИ, КАПСУЛЫ, ЦИЛИНДРЫ И СФЕРЫ;

ПОДДЕРЖКА СИМУЛЯЦИИ АВТОМОБИЛЕЙ;

ДЖОИНТЫ.

ODE (www.ode.org, BSD, исходники открыты)

Единственный в списке движок с открытыми исходниками, что позволяет ему служить в качестве базы для построения собственного физического движка (небезызвестный проект S.T.A.L.K.E.R. использует модифицированный ODE), а также просто для изучения того, как оно все внутри устроено. ODE очень часто используется различными игровыми движками в качестве физической подсистемы.

Возможности:

ФИЗИКА ТВЕРДОГО ТЕЛА;

ДЖОИНТЫ;

СИСТЕМА СТОЛКНОВЕНИЙ ОТДЕЛЕНА ОТ ФИЗИЧЕСКОЙ СИМУЛЯЦИИ, ЧТО ПОЗВОЛЯЕТ ИНТЕГРИРОВАТЬ ODE С РАЗНЫМИ СИСТЕМАМИ СТОЛКНОВЕНИЙ.

Tokamak (www.tokamakphysics.com, беcплатный, исходники закрыты)

Возможности:

ФИЗИКА ТВЕРДОГО ТЕЛА;

ДЖОИНТЫ (ВСЕГО ДВА ВИДА: BALL И HINGE - ДОСТАТОЧНО ДЛЯ ПОСТРОЕНИЯ RAG-DOLLS).

Newton (www.physicsengine.com, беcплатный, исходники закрыты)

Возможности:

СИСТЕМА СТОЛКНОВЕНИЯ ПОДДЕРЖИВАЕТ НЕПРЕРЫВНОЕ ОТСЛЕЖИВАНИЕ СТОЛКНОВЕНИЙ;

ФИЗИКА ТВЕРДОГО ТЕЛА;

ПОДДЕРЖКА СИМУЛЯЦИИ АВТОМОБИЛЕЙ.

физика на примере

Для практического примера возьмем демонстрационную программу из OPAL (open physics abstraction layer: http://ox.slug.louisville.edu/opal/wiki) - это открытый физический движок, предоставляющий единый высокоуровневый интерфейс для работы с другими физическими движками. На данный момент существует единственная реализация поверх ODE, в разработке находится оболочка над TrueAxis. Для работы необходимо скачать сам движок - ?download.

Нас интересует дема, которая находится в папке opal-0.3.1-srcsamplessimple и показывает базовые аспекты работы с физическим движком OPAL, демонстрируя работу с твердыми телами. В качестве визуализатора используется библиотека SDL (www.libsdl.org/index.php). Приложение состоит из единственного файла main.cpp и нескольких h-ков. При старте появляется статический бокс. При нажатии клавиши «пробел» на этот бокс падают твердые тела, представляемые при помощи различных примитивов. Рассмотрю файл main.cpp и прокомментирую те его части, которые относятся к физической симуляции.

набор глобальных переменных

std::vector gEntities;

opal::Simulator* gSimulator = NULL;

Переменная gSimulator типа opal::Simulator указывает на экземпляр физического движка OPAL. Тип opal::Simulator - собственно, и есть сам физический движок. Он инкапсулирует внутри систему расчета столкновений и подсистему расчета физики. Как правило, в приложении достаточно одного экземпляра физического движка. Подобного рода архитектура, при которой существует некий объект, содержащий информацию обо всех физических объектах игрового мира, и производит обсчет физики и используется практически во всех высокоуровневых физических движках.

Переменная gEntities содержит список сущностей типа opalSamples::Entity, которые имеют физическое представление. Сам класс и его наследники мало интересны, так как они в данной программе служат для отрисовки симулируемых объектов. В самом классе opalSamples::Entity интересует нас одно поле - opal::Solid* mSolid. Тип opal::Solid представляет твердое тело в физическом движке OPAL. Твердое тело обладает позицией, скоростью, ускорением и является базовой единицей симуляции - такого рода сущность есть в любом физическом движке. В данной программе для рисования сущности необходимо знать позицию твердого тела - эта информация получается путем вызова метода getTransform у mSolid.

содержимое функции main

gSimulator = opal::createSimulator();

gSimulator->setGravity(opal::Vec3r(0, (opal::real)-9.81, 0));

В первой строчке создаем экземпляр симулятора при помощи функции opal::createSimulator(). Во второй строчке устанавливаем силу гравитации для этого симулятора при помощи метода setGravity и передачи в качестве параметра вектора силы тяжести. Заметь, что можно задать гравитацию, отличную от земной, или установить ее равной нулю. С точки зрения физической симуляции, гравитация - это всего лишь одна из сил, действующих на тело, подобного рода метод применяют из соображений удобства и эффективности, так как, как правило, в симулируемом мире гравитация присутствует.

1. opal::Solid* platformSolid = gSimulator->createSolid();

2. platformSolid->setStatic(true);

3. opal::BoxShapeData boxShape;

4. boxShape.dimensions = gGroundDimensions;

5. platformSolid->addShape(boxShape);

В приведенном куске кода создаем объект в виде прямоугольной коробки, который служит в качестве земли. В первой строчке создаем твердое тело в нашем симуляторе (это твердое тело будет обрабатываться именно данным симулятором и никаким другим).

Во второй строчке делаем тело статическим, то есть таким, которое не может менять свою позицию (обладает бесконечной массой), но может взаимодействовать с другими физическими телами. Как правило, в играх такие статические тела используются для симуляции неподвижных объектов локаций, таких как земля, стены и т.д.

В третьей строчке создаем экземпляр структуры boxShape, которая описывает трехмерный прямоугольник (бокс).

В четвертой строчке устанавливаем его размеры по трем осям, а в пятой - устанавливаем этот прямоугольник в качестве объема для нашей земли, вызвав метод addShape. Заметь, что можно добавлять сколько угодно разных фигур (Shapes), описывая таким образом сложный объем. В OPAL, помимо боксов, в качестве объема можно использовать сферы, цилиндры, плоскости и многоугольники, причем и выпуклые, и невыпуклые. Все фигуры имеют, помимо специфичных для каждой фигуры параметров (как dimensions в нашем примере), ряд общих полей:

Matrix44r offset;

Material material;

Поле offset задает смещение фигуры относительно центра твердого тела, поле material задает свойства материала фигуры. В OPAL"е материал имеет следующие свойства:

hardness - от 0 до 1. Показывает, насколько допустимо перекрытие объемов тел.

friction - от 0 до 1, трение движения. Чем больше это значение, тем быстрее будет останавливаться движущееся тело.

bounciness - от 0 до 1, упругость. Чем больше значение, тем больше энергии будет поглощаться при соударении.

density - плотность материала. На основании этого параметра и объема фигуры вычисляется масса фигуры.

основной цикл программы (вернее, те его части, которые представляют интерес в контексте рассматриваемого вопроса)

opal::real dt = (opal::real)timer.getElapsedSeconds();

gQuit = processInput();

gSimulator->simulate(dt);

Нам интереснее всего вот эта строчка:

gSimulator->simulate(dt);

В метод simulate передаем единственный параметр - время, которое прошло в «физическом мире». Именно внутри этого вызова происходит расчет столкновений и расчет взаимодействия физических объектов, происходит обновление позиций, скоростей и т.д.

gSimulator->destroy();

Заключительная строчка программы вызывает метод destroy объекта-симулятора, тем самым освобождая все ресурсы, занятые им, и уничтожая все физические объекты, созданные через методы симулятора, подобные createSolid.

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