Компаунды, или дешёвые невыпуклые тела с коллизией.
В предыдущих постах я рассказывал о Хуллах и Тримешах. Теперь настала очередь компаундов.
Итак, напомню что такое компаунды: это группа выпуклых физических тел, крепко соединённых вместе. То есть, например, если нам надо сделать стул, чтобы какой-нибудь шарик мог прокатиться у него между ножек (невыпуклая геометрия) мы можем сделать для него тримеш (тормознуто, отсутствие коллизии с другими тримешами), а можем описать его как группу из нескольких прямоугольных параллелепипедов ("боксов", "кубиков") и это будет обрабатываться
значительно быстрее тримеша:
Теория закончилась, переходим к практике. Возьмём за основу пример 2. Там можно было по нажатию на пробел создавать кубики. Попробуем соорудить вместо них что-то типа столов. Для начала нам потребуется моделька стола. Её можно было бы создать в максе, но, я думаю, связь между компаундом и моделью будет яснее, если мы соберём эту подельку прямо в блитзе, из кубиков:
Global TableMesh = CreateCube()
ScaleMesh TableMesh,3,0.3,1.5
PositionMesh TableMesh,0,3.3,0
leg = CreateCube()
ScaleMesh leg,0.3,1.5,0.3
PositionMesh leg,2.7,1.5,-1.2
AddMesh leg, TableMesh
PositionMesh leg,0,0,2.4
AddMesh leg, TableMesh
PositionMesh leg,-5.4,0,0
AddMesh leg, TableMesh
PositionMesh leg,0,0,-2.4
AddMesh leg, TableMesh
FreeEntity leg
HideEntity TableMesh
Собственно, в глобальную переменную создаётся модель стола и скрывается. Можете временно убрать HideEntity и убедиться, всё ли в порядке.
Теперь надо создать для этой модели физическое тело - компаунд. Так как мы собирали модельку из кубиков, то и компаунд собирать будем из таких же кубиков.
Опять немного теории.
Создать Compound несколько сложнее, чем простое тело. Сначала создаётся КомпаундДескриптор. Это своего рода контейнер информации о геометрии будущего компаунда. В него заносятся выпуклые физические тела, затем поворачиваются и располагаются как надо в соответствии с тем, что мы хотим получить. Затем из Дескриптора создаётся непосредственно Компаунд, к которому можно прикладывать силу, указывать координаты и т.п., т.е. всё, что можно творить с обычным физическим телом.
Итак,
Функция создаёт дескриптор и возвращает его хендл. Параметров нет.
Создадим дескрипторв нашей проге:
Desc = pxCreateCompoundDesc()
Теперь в него нужно добавлять физические тела (кстати, они в данном случае называются Shape'ы), т.к. сам он "пустой".
Чтобы добавить в него кубик, нужна команда:
pxCompoundAddCubeShape(Desc%, dx#, dy#, dz#)
|
Добавляет кубик к дескриптору. Возвращает хендл созданного Shape'а. Параметры:
Desc - дескриптор, куда добавлять кубик.
dx, dy, dz - масштаб по осям для кубика (аналогично pxBodyCreateCube, смотрите выше подробное описание если что-то упустили)
Обратите внимание: массу указывать не надо. Как бы это не физическое тело, а фигура, не имеющая массы (возможно, потому она и называется Shape а не Body). Она будет общая для всего компаунда и указывается при его (компаунда, не дескриптора) создании. Центр массы будет рассчитан там же.
Итак, добавим по очереди кубики в наш дескриптор, чтобы они соответствовали модели стола. Так как мы модель стола собирался из кубиков, то все параметры для позиционирования и для масштабирования у нас есть, осталось только использовать их. Создадим столешницу, напомню, что при создании модели код выглядел так:
Global TableMesh = CreateCube()
ScaleMesh TableMesh,3,0.3,1.5
PositionMesh TableMesh,0,3.3,0
Теперь такой же кубик делаем и для дескриптора:
Sh = pxCompoundAddCubeShape(Desc,3,0.3,1.5)
Это я создал куб в дескрипторе, отмасштабировал его, и хендл созданного шейпа у меня теперь лежит в переменной Sh. А как же его переместить? Для этого пригодится команда:
pxCompoundSetShapePos(shape%, x#, y#, z#)
|
Устанавливает позицию для шейпа. Аргументы: shape - хендл шейпа, x#, y#, z# - координаты куда надо устанавливать шейп.
Собственно, аналог PositionEntity, только для Shape'ов дескриптора. Ничего сложного тут нет.
Теперь переместим и наш шейп туда, где он должен стоять (а стоять он должен там же, где и столешница-меш, то есть в 0,3.3,0) :
pxCompoundSetShapePos(Sh,0,3.3,0)
По аналогии создаём и располагаем кубики и для ножек стола:
Sh = pxCompoundAddCubeShape(Desc,0.3,1.5,0.3)
pxCompoundSetShapePos(Sh,2.7,1.5,-1.2)
Sh = pxCompoundAddCubeShape(Desc,0.3,1.5,0.3)
pxCompoundSetShapePos(Sh,2.7,1.5,1.2)
Sh = pxCompoundAddCubeShape(Desc,0.3,1.5,0.3)
pxCompoundSetShapePos(Sh,-2.7,1.5,-1.2)
Sh = pxCompoundAddCubeShape(Desc,0.3,1.5,0.3)
pxCompoundSetShapePos(Sh,-2.7,1.5,1.2)
Так, дескриптор создан и все шейпы в ём - тоже. Теперь настало время создавать непосредственно физическое тело. Это делается командой:
pxCreateCompound (Desc, mass#)
|
Создаёт физическое тело из дескриптора. Возвращает хендл этого самого тела. Аргументы: Desc - дескриптор (естественно со всеми уже заранее созданными в нём шейпами) , mass - масса создаваемого тела.
Вот теперь давайте создадим физическое тело нашего стола:
Global TableBody = pxCreateCompound(Desc,1)
Из ранее созданного дескриптора создалось тело с массой 1.
Так как это обыкновенное тело, с ним можно вытворять всё то же что и с любым другим телом. Давайте отключим ему коллизию (как в более ранних примерах мы это делали чтобы тело-эталон не мешалось):
pxBodySetFlagCollision TableBody,0
Готово. Теперь изменим пару строчек в функции CreatepxCube чтобы вместо кубиков создавались столы:
pxC\mesh = CreateCube()
pxC\body = pxBodyCreateCube(1,1,1,1)
меняем на:
pxC\mesh = CopyEntity(TableMesh)
pxC\body = pxCopyBody(TableBody)
В персой строке вместо модели куба копируется меш стола, а во второй - вместо создания физического куба копируется тело - компаунд стола. Всё. Можно запускать и нажимать на пробле. Только вот они создются все в одной точке и потому падают ровной стопкой. Добавим некоторый элемент рандомности при создании:
pxBodySetPosition pxC\body,x+Rnd(-10,10),y,z+Rnd(-2,2)
Вот, теперь вся невыпуклость компаундов налицо. Ножки столов засовываются между ножек других столов и т.д. (прямо-таки камасутра для мебели
)
Однако обратите внимание на такую вещь (вы, наверное, уже заметили): если два компаунда создать "друг в друге" (если слишком часто нажимать на пробел), то
сложные компоунды иногда не смогут "выскочить" друг из друга, как это ранее легко делали хуллы и так и останутся слипшимися. Это не есть гуд, но что поделать. Так что следите за тем, где вы создаёте компаунды.
Полный код примера вы найдёте в аттаче "PhysXExample8.zip"
(там я переименовал типы и функции из Cube в Table чтобы они соответствовали своему названию
)
Тема компаундов достаточно обширна. Здесь я изложил только основы. В следующий раз я продолжу рассказывать о компаундах, в частности мы рассмотрим добавление в него других примитивов и хуллов.
Следующий пост ждите примерно через неделю