Физика в Urho3D

Материал из Энциклопедия о программировании
Перейти к: навигация, поиск

Urho3D реализует моделирование физики твердых тел с помощью физической библиотеки Bullet.

Начало работы

Для использования сначала необходимо создать компонент PhysicsWorld для узла Scene.

Частота обновления физики

Симуляция физики имеет собственную фиксированную частоту обновления, которая по-умолчанию составляет 60 Гц. Когда частота кадров рендеринга выше, чем частота обновления физики, движение физики интерполируется так, что она всегда выглядит плавной. Частоту обновления можно изменить с помощью функции SetFps. Частота обновления физики также определяет частоту обновлений логики сцены с фиксированным временным шагом. Жесткий предел для физических шагов на кадр или адаптивный временной шаг можно настроить с помощью функции SetMaxSubSteps. Это может помочь предотвратить «спираль смерти» из-за того, что CPU не может справиться с физической нагрузкой. Однако обратите внимание, что использование либо может привести к замедлению времени (когда шаги ограничены), либо к непоследовательному физическому поведению (при использовании адаптивного шага).

Компоненты физики

Помимо PhysicsWorld имеются след. компоненты физики:

  • RigidBody – экземпляр физического объекта. Его параметры включают массу, линейные/угловые скорости, трение и восстановление.
  • CollisionShape – определяет физическую геометрию столкновения. Поддерживаемые формы: box, sphere, cylinder, capsule, cone, triangle mesh, convex hull и heightfield terrain (требуется компонент Terrain в том же узле).
  • Constraint – соединяет два RigidBody вместе или одно RigidBody со статической точкой в ​​мире. Поддерживаются точечные, шарнирные, ползунковые и конусные ограничения скручивания.

Движение и столкновение

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

CollisionShape предоставляет два API для определения геометрии столкновения. Либо установка отдельных свойств, таких как тип или размер фигуры, либо одновременное указание типа фигуры и всех её свойств: см. напр., SetBox, SetCapsule или SetTriangleMesh.

Жесткие тела могут быть статичными или движущимися. Тело статично, если его масса равна 0, и движется, если масса больше 0.

Внимание: Форма столкновения (CollisionShape) типа треугольной сетки (triangle mesh) не поддерживается для движущихся/динамических объектов; она не будет правильно сталкиваться из-за ограничений библиотеки Bullet. В этом случае можно использовать лишь выпуклую форму корпуса (convex hull).

Поведение твердого тела при столкновении контролируется несколькими переменными. Во-первых, слой и маска столкновения определяют, с какими другими объектами следует столкнуться: см. SetCollisionLayer и SetCollisionMask. По-умолчанию твёрдое тело находится на слое 1; слой будет соединен операцией AND с маской столкновения другого тела, чтобы увидеть, следует ли сообщать о столкновении. Для твердого тела также можно настроить trigger mode, чтобы сообщать только о столкновениях без фактического применения сил столкновения. Это можно использовать для реализации триггерных областей. Наконец, friction, rolling friction и restitution коэффициенты (от 0 до 1) контролируют передачу кинетической энергии при столкновениях. Обратите внимание, что rolling friction по-умолчанию равно нулю, и если вы хотите, напр., чтобы сфера, катящаяся по полу, в конечном итоге остановилась, вам необходимо установить ненулевое rolling friction как для сферы, так и для твердого тела пола.

По-умолчанию твердые тела могут перемещаться и вращаться вокруг всех трех координатных осей при приложении сил. Чтобы ограничить движение, используйте SetLinearFactor и SetAngularFactor и установите оси, которые вы хотите использовать, на 1, а те, которые вы не хотите использовать, на 0. Напр., движущиеся гуманоидные персонажи часто представлены формой капсулы: чтобы убедиться, что они остаются в вертикальном положении и вращаться только тогда, когда вы явно задаете поворот в коде, установите угловой коэффициент на 0, 0, 0.

Чтобы предотвратить прохождение быстро движущегося твердого тела через препятствия, можно использовать непрерывное обнаружение столкновений. Он аппроксимирует объект как развернутую сферу, но имеет большие запросы производительности, поэтому его следует использовать только при необходимости. Для включения вызовите SetCcdRadius и SetCcdMotionThreshold с ненулевыми значениями. Чтобы предотвратить ложные столкновения, фактическая форма столкновения тела должна полностью содержать радиус. Порог движения (motion threshold) - необходимое движение для каждого шага симуляции, чтобы CCD сработала: напр., box с размером 1 также должен иметь motion threshold 1.

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

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

Параметры ограничений

Положение ограничения/constraint (и поворот, если необходимо) необходимо определить по отношению к обоим соединенным телам, см. SetPosition и SetOtherPosition. Если ограничение связывает тело со статическим миром, то «положение другого тела» и «вращение другого тела» означают преобразование статического конца в мировом пространстве. Существует также вспомогательная функция SetWorldPosition для назначения ограничения позиции в мировом пространстве; это устанавливает оба относительных положения.

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

Ограничения поворота шарнира/петли, слайдера и конуса поддерживают определение пределов движения. Чтобы быть общим, они кодируются несколько неинтуитивно в Vector2. Для шарнирного ограничения координаты X нижнего и верхнего пределов определяют минимальный и максимальный угол в градусах. Напр., от -45 до 45. Для ограничения ползунка координаты X определяют максимальное линейное движение в единицах мирового пространства, а координаты Y определяют максимальное угловое движение в градусах. Ограничение скручивания конуса использует только верхний предел для определения максимальных углов (минимальный угол всегда -maximum) следующим образом: координата X - предел поворотной (главной) оси, а Y - предел раскачивающего движения относительно др. осей.

Физические события

На этапе обновления физический мир отправляет 8 типов событий:

  • E_PHYSICSPRESTEP перед пошаговым моделированием.
  • E_PHYSICSCOLLISIONSTART для каждого нового столкновения на этапе моделирования. Участвующие узлы сцены также будут отправлять события E_NODECOLLISIONSTART.
  • E_PHYSICSCOLLISION для каждого продолжающегося столкновения на этапе моделирования. Участвующие узлы сцены также будут отправлять события E_NODECOLLISION.
  • E_PHYSICSCOLLISIONEND для каждого прекращенного столкновения. Участвующие узлы сцены также будут отправлять события E_NODECOLLISIONEND.
  • E_PHYSICSPOSTSTEP после пошагового моделирования.

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

Чтение событий столкновения

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

Контактные точки кодируются в байтовом буфере, который можно прочитать с помощью вспомогательного класса VectorBuffer или MemoryBuffer. Следующая структура повторяется для каждого контакта:

  • Положение в мировом пространстве (Vector3)
  • Вектор нормали (Vector3)
  • Расстояние, отрицательное при взаимном проникновении (float)
  • Импульс, приложенный при столкновении (float)

Пример чтения данных события столкновения и точки контакта в скрипте из кода обработки столкновения игрового объекта в образцовой игре NinjaSnowWar:

void HandleNodeCollision(StringHash eventType, VariantMap& eventData) {
	Node@ otherNode = eventData["OtherNode"].GetPtr();
	RigidBody@ otherBody = eventData["OtherBody"].GetPtr();
	VectorBuffer contacts = eventData["Contacts"].GetBuffer();
	while (!contacts.eof) {
		Vector3 contactPosition = contacts.ReadVector3();
		Vector3 contactNormal = contacts.ReadVector3();
		float contactDistance = contacts.ReadFloat();
		float contactImpulse = contacts.ReadFloat();
		// Что-то делаем с контактными данными…
	}
}

Физические запросы

В физический мир предоставляются следующие запросы:

  • Raycast, см. Raycast и RaycastSingle.
  • Sphere cast (raycast с толщиной), см. SphereCast.
  • Тесты перекрытия сфер и боксов, см. GetRigidBodies.
  • Какие другие твердые тела сталкиваются с телом, см. GetCollidingBodies. В скрипте это отображается в свойство collidingBodies.