Показать сообщение отдельно
Старый 09.02.2009, 00:09   #10
ABTOMAT
Ференька
 
Аватар для ABTOMAT
 
Регистрация: 26.01.2007
Адрес: улица Пушкина дом Колотушкина
Сообщений: 10,741
Написано 5,461 полезных сообщений
(для 15,675 пользователей)
Сообщение Ответ: Учебник по PhysX Wrapper для Blitz3D

Сочленения

Итак, сочленения. По-буржуйски - джойнты (joints)
Сочленения - это объекты, которые могут определённым образом "сцеплять" тела. То есть например, в том же пресловутом Ragdoll'е все физ. тела для костей соединены между собой сочленениями. Если бы этого не было, что все части тела разлетелись бы кто куда и никаког орегдолла не получилось бы.
Джойнтов (во враппере, по крайней мере) существует достаточно много, рассмотреть их в одной статье не удастся, поэтому начну с самых основных.

Сферический джойнт.

Это самый распространённый вид сочленения. По сути, это шарнир, то есть имеет лимит в виде конуса. Чтобы лучше понять, как он будет работать, посмотрите на эту картинку:

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

Переходим к практике. Возьмём за основу Пример 2.
Будем создавать теперь уже не один кубик, а два вытянутых "кирпича", да ещё исоединённые между собой джойнтами.

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

Но лучше поступим по-иному. Будем создавать сначала два pxCube'а, а потом между ними - джойнт.

Итак, напишем функцию, которая создаёт два куба типа pxCube, один чуть повыше другого. Понадобится также заставить функцию CreatepxCube возвращать созданный тип, чтобы мы могли к ним потом обратиться и создавать кубы более продолговатые:

Function CreateBunch(x#,y#,z#)
	Cube1.pxCube = CreatepxCube(x#,y#+5,z#)
	Cube2.pxCube = CreatepxCube(x#,y#-5,z#)	
End Function

Function CreatepxCube.pxCube(x#,y#,z#)
	pxC.pxCube = New pxCube
	pxC\mesh = CreateCube()
	ScaleEntity pxC\mesh,1,5,1
	pxC\body = pxBodyCreateCube(1,5,1,1)
	pxBodySetPosition pxC\body,x,y,z
	Return pxC
End Function
CreateBunch создаёт 2 куба с разницей по высоте в 5. Теперь надо сцеплять их сферическим джойнтом. Делать это будем при помощи команды
pxJointCreateSpherical( body1%, body2%, x#, y#, z#, nx#, ny#, nz#)
Создаёт сферический джойнт (он же шарнир), возвращает его хендл.
Аргументы:
body1, body2 - тела, которые будем сцеплять.
x, y, z - координаты джойнта при его создании.
nx, ny, nz - нормализованный вектор направления оси джойнта. Попробую объяснить проще: помните серый конус с картинки выше? Эти параметры как раз указывают, куда будет направлен этот конус. Например, при 0,1,0 цилиндр будет направлен вверх.

Внимание! Тела body1, body2 должны быть динамическими (т.е. иметь массу <> 0). Если вы хотите привязать тело к статике, то подставьте 0 вместо статического тела.

Привяжем 2 наших кубика один к другому:

pxJointCreateSpherical Cube1\Body,Cube2\Body,x,y,z,0,1,0
Джойнт в данном случае нужно располагать посередине между двумя телами. Т.к. оба куба смещены по вертикали то соответственно и "конус" будет направлен вверх.

Теперь по пробелу уже создаём связку:

If KeyHit(57) Then CreateBunch(0,20,0)
Тыкаем на пробел, смотрим на результат.
Обратите внимание: два сцеплённых друг с другом тела не коллизятся друг с другом!
Можно включить коллизию.

pxJointSphericalSetCollision(joint%)
Команда заставляет рассчитывать коллизию между двумя телами, сцеплёнными сферическим джойнтом. (для других типов джойнтов - свои версии этой команды!) Аргументы: joint - хенджл джойнта.

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

Joint = pxJointCreateSpherical (Cube1\Body,Cube2\Body,x,y,z,0,1,0)
pxJointSphericalSetCollision(Joint)
Ага, теперь они коллизятся. Только почти не поворачиваются и это понятно: т.к. куба сцеплены вплотную друг к другу, то они мешают друг другу вертеться. В функции создания поменяем расстояние между создаваемыми кубами. Вместо 5 возьмём 6.

Cube1.pxCube = CreatepxCube(x#,y#+6,z#)
Cube2.pxCube = CreatepxCube(x#,y#-6,z#)
Теперь всё хорошо видно. И вертятся и коллизятся. Но всё-таки ограничение по коллизии - это не вариант. Зачем точно рассчитывать коллизию хуллов, когда можно поступить гораздо проще - ограничить конус вращения?

Итак, уберём включение коллизии, вернём расстояние между кубами на 5 и рассмотрим, как можно по-иному ограничить вращение.

pxJointSphericalSetLimitAngle(joint%, angle#, hardn#, restit#)
Указывает джойнту лимит угла конуса вращения. Кстати, угол может принимать занчения и больше 90°, в реальном мире технически (при классическом шарнире) это было бы невозможно (шарнир бы просто вывалился) или потребовало бы каких-то иных путей решения задачи, но так как у нас тут компьютерное моделирование физики, то мы можем сотворить всё что угодно.

Аргументы:

joint - хендл джойнта
angle - угол лимита в градусах
hardn - жёсткость лимита. Диапазон: [0;1] По умолчанию: 1.
restit - упругость лимита. Диапазон: [0;1] По умочанию: 0.

*Очень странно, но при любых значениях hardn и restit получается один и тот же эффект. При значениях за пределами указанного диапазона лимит отключается вовсе. Use it wisely.

Укажем лимит в 90°, остальные параметры оставим как по дефолту и посмотрим, что выйдет:

pxJointSphericalSetLimitAngle(Joint, 90,1, 0)
Вот, теперь тела не могут вращаться более чем на 90° от изначального положения.



*Это важно: в школьной геометрии (11-й класс) углом конуса считается угол при вершине его осевого сечения, что логически верно. Но в PhysX'е указывается только половина этого угла. Взгляните на картинку: угол, задавемый параметром angle вышеописанной функции обозначен синим:

Будьте бдительны и не ведитесь на дезинформацию минобразования РФ =-)))

Тела крутятся вокруг своей оси. А что, если это например нога человека? Ведь она же не может крутиться на 360° ? Это дело тоже можно ограничить.

pxJointSphericalSetLimitTwist(joint%,mintwist#,max twist#,spr#,damp#,targetVal#)
Ограничивает кручение вокруг оси джойнта. Аргументы:
joint - джойнт
mintwist,maxtwist - минимально и максимально возможное кручение
spr - упругость. Диапазон: [0;бесконечность), по умолчанию: 0
damp - "вязкость"
targetVal - значение, к которому будет стремиться поворот.

Создадим ограничение +- 10° с некоторой упругостью и вязкость. Целевое значение пусть будет 0
pxJointSphericalSetLimitTwist(Joint,-10,10,10,1,0)
Вот, мы ограничили вращение в разумных пределах.

Рассмотрим ещё одну команду для сферического джойнта:

pxJointSphericalSetLimitSpring(joint%, spr#, damp#, targetVal#)
Указывает растяжимость соединения. Аргументы:
joint - джойнт
spr - эластичность. По дефолту 0, может принимать значения от 0 до бесконечности.
damp - вязкость
targetVal - значение к которому стремиться. По дефолту 0.

Установим эту самую растяжимость:

pxJointSphericalSetLimitSpring(Joint, 10, 1, 0)
И последнее. Чтобы удалить джойнт используйте

pxDeleteJoint (joint)
Тупо удаляет джойнт.
Аргументы: joint - джойнт

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

Type Joint
	Field Joint
End Type

Function FreeAllJoints()
	For j.Joint = Each Joint
		pxDeleteJoint(J\Joint)
		Delete J
	Next
End Function

.......
Function CreateBunch(x#,y#,z#)
	Cube1.pxCube = CreatepxCube(x#,y#+5,z#)
	Cube2.pxCube = CreatepxCube(x#,y#-5,z#)		
	Joint = pxJointCreateSpherical (Cube1\Body,Cube2\Body,x,y,z,0,1,0)
	pxJointSphericalSetLimitAngle(Joint, 30,1, 0)
	pxJointSphericalSetLimitTwist(Joint,-10,10,10,1,0)
	pxJointSphericalSetLimitSpring(Joint, 10, 1, 0)
	J.Joint = New Joint
	J\Joint = Joint
End Function
Вызов по левому шифту:

If KeyHit(42) Then FreeAllJoints()
Теперь если нажать шифт, то все кубики разваливаются)
Кстати, обратите внимание на то, что при уничтожении джойнта коллизия между двумя телами снова включается и они "выскакивают" друг из друга. Поэтому если вы собрались в процессе игры разрушать некоторые джойнты, то коллизию всё-таки лучше включить.

Полный код примера вы найдёте в аттаче "PhysXExample13.zip"

В этот раз хотел написать ещё и про хиндж, да не успеваю в СЗИП СПБГУТД на этой неделе будет тестирование, по итогам которого соответственно повышаются шансы на поступление, так что надо готовиться. В-общем, кто учился в 11-м классе - тот поймёт. Не могу сказать точно, будет ли следующий пост через неделю. Если нет - напишу позже. На сегодня у меня всё
Вложения
Тип файла: zip PhysXExample13.zip (683 байт, 1605 просмотров)
__________________
Мои проекты:
Анальное Рабство
Зелёный Слоник
Дмитрий Маслов*
Различие**
Клюква**

* — в стадии разработки
** — в стадии проектирования
Для проектов в стадии проектирования приведены кодовые имена


Последний раз редактировалось ABTOMAT, 09.02.2009 в 19:54.
(Offline)
 
Ответить с цитированием
Эти 26 пользователя(ей) сказали Спасибо ABTOMAT за это полезное сообщение:
3dr1aN (10.02.2009), baton4ik (02.02.2010), Blender (17.01.2010), Brain (15.01.2010), CRASHER (10.02.2009), DeadElf (27.07.2010), den (27.07.2010), Diablomania (14.08.2009), h1dd3n (13.02.2009), H@NON (09.02.2009), Harter (08.10.2009), HolyDel (09.02.2009), Hurrit (16.05.2010), Main Cry (23.04.2009), m_512 (13.02.2009), Nex (23.06.2009), Randomize (10.02.2009), Render (09.02.2009), Slavik (24.06.2009), strayhnd (30.06.2010), St_AnGer (25.09.2016), tormoz (09.02.2009), TxN (15.08.2009), viper86 (10.02.2009), WhiteBlack (27.07.2010), ІГРОГРАЙКО (02.07.2009)