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

Trimesh или физическая модель невыпуклых тел.

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

Для этого в Физиксе существуют такие понятия, как Тримеш (Trimesh) и Компаунд (Compound)

Компаунд - это как бы связка из нескольких хуллов (выпуклых тел). Например стул можно представить в качестве нескольких прямоугольных параллепипедов (в народе - "собрать из кубиков"), я тут попытался изобразить:



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

Если же это невозможно (например, если надо сделать (физически честную! естественно для небольших ведёрок в экшене лучше сделать просто хулл) модель ведра, то будет очень проблематично выстраивать "частокол" из "досочек" по периметру, да и вычислительные затраты будут большими) то можно использовать Тримеш. Тримеш - это физическая модель невыпуклого тела. То есть по-честному рассчитываются всякие спадины, дырки и прочие "впуклости". Само собой, особенно, если тело динамическое, это влечёт намного большие вычислительные затраты по сравнению с хуллами и компаундами. Так что прежде чем использовать тримеш, лучше подумать нельзя ли обойтись иными способами. Я бы рекомендовал использовать его для создания физ. модели уровня (т.к. статика жрёт меньше ресурсов), а для динамических объектов - использовать хуллы и компаунды. Существует очень важный недостаток тримешей, ограничивающий их применение. Дело в том, что в физиксе нету коллизии trimesh-to-trimesh. А это значит что два тела-тримеша будут просто проваливаться друг сквозь друга. Поэтому тримеш используем только для статики.

Итак, этот пост будет посвящён тримешу.

Сделал я в Максе такую модельку:

Эдакая совдеповкская кастрюля. Это яркий пример где целесообразно использовать тримеш. Сделаем это.

Возьмём за основу пример 6.
Переделаем функцию создания объекта таким образом:
Function CreatepxBody(x#,y#,z#, fig = 0)	
	pxB.pxBody = New pxBody
	
	If fig = 0 Then fig = Rand(1,2)
	Select fig
		Case 1 ; пресс-папье
			pxB\mesh = CopyEntity(PressPapierMesh)
			pxB\body = pxCopyBody(PressPapierHull)
		Case 2 ; кастрюля
			
	End Select
	pxBodySetPosition pxB\body,x,y,z
End Function
Надеюсь, тут понятно. Суть изменений: теперь в функцию передаётся параметр fig, который указывает, какой именно объект создавать (пресс-папье, кастрюля) если он не указан или равен 0 то тогда это выбирается рандомно.

Теперь надо разобраться с кастрюлей:

Global PotMesh = LoadMesh("Pot.b3d")
HideEntity PotMesh
Вот, я загрузил модель кастрюли и скрыл её чтоб не мешала. Думаю, из предыдущих примеров это ясно.
В функции создания объекта дописываем копирование сетки.
		Case 2 ; кастрюля
			pxB\mesh = CopyEntity(PotMesh)
А как быть с телом? Надо создать тримеш. Тут нам поможет команда:
pxCreateTriMesh%(vbank%, fbank%, MESH_NBVERTICES%, MESH_NBFACES%, mass#)
Создаёт тримеш. Параметры:

Vbank - банк вершин,
Fbank - банк треугольников,
MESH_NBVERTICES - количество вершин,
MESH_NBFACES - количество треугольников,
mass - масса.

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

Размер банка - количество треугольников * 12

n*12+0 - индекс нулевой вершины n-ного треугольника (целое число - int)
n*12+4 - индекс первой вершины n-ного треугольника (целое число - int)
n*12+8 - индекс второй вершины n-ного треугольника (целое число - int)

* Индексы вершин соответствуют тому порядку, в котором они заносились в Vbank. Если использовались стандартные блитзевские индексы вершин в меше, то проблем не будет.
Опять же, в примерах есть соответствующая функция создания Тримеша из блитзевского меша:

Function BodyCreateMesh(mesh%)
	nsurf = CountSurfaces(mesh)
	nvert = 0
	nface=0
	For ns = 1 To nsurf
		Local surf = GetSurface(mesh,ns)
		nface = nface+CountTriangles(surf)
		nvert = nvert +CountVertices(surf)
	Next

	fbank = CreateBank(nface*4*3)
	nf = 0
	vbank = CreateBank(nvert*4*3)
	nv = 0
	For ns = 1 To nsurf
		surf = GetSurface(mesh,ns)
		nfv = CountTriangles(surf)
		For nfc = 0 To nfv -1
			PokeInt fbank,nf*12+0,TriangleVertex(surf,nfc,0)
			PokeInt fbank,nf*12+4,TriangleVertex(surf,nfc,1)
			PokeInt fbank,nf*12+8,TriangleVertex(surf,nfc,2)
			nf=nf+1
		Next

		nvv = CountVertices(surf)
		For nvc = 0 To nvv - 1
			PokeFloat vbank,nv*12+0,VertexX(surf,nvc)
			PokeFloat vbank,nv*12+4,VertexY(surf,nvc)
			PokeFloat vbank,nv*12+8,VertexZ(surf,nvc)
			nv = nv+1
		Next
	Next
	bbb%=pxCreateTriMesh(vbank, fbank, nvert, nface,0)
	FreeBank vbank
	FreeBank fbank
	Return bbb%
End Function
Внимание! При экспорте из макса модели для последуюбщей генерации из неё тримеша нужно придерживаться тех же правил, что и для хулла! (ищите в посте выше)

Из ентити она создаёт Тримеш с массой 0 (т.е. статическое тело)
Но мы всё-таки попробуем создать динамический тримеш. Поэтому модифицируем функцию таким образом:
Function BodyCreateMesh(mesh%, mass#=0)
...
bbb%=pxCreateTriMesh(vbank, fbank, nvert, nface,mass)
Вот, теперь в функцию можно передать значение массы и тримеш создастся с указанной массой.

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

Global PotHull = BodyCreateMesh(PotMesh, 5)
pxBodySetFlagCollision(PotHull, 0)
Разница - в том что вместо BodyCreateHull используется BodyCreateMesh, ну и массу я поставил побольше.

При создании кастрюли просто копируем это тело:

pxB\body = pxCopyBody(PotHull)
Теперь изменим немного условие создания объекта. Пускай это будут разные клавиши:

If KeyHit(57) Then CreatepxBody(0,20,0,1)
If KeyHit(15) Then CreatepxBody(0,10,0,2)
Табуляция - кастрюля, пробел - промокашка. Тут, наверное, всё понятно.
Кстати, внимательные догадались, что теперь хуллы создаются чуть выше

На всякий случай оnодвинем камеру подальше, а то великовата вышла кастрюля

PositionEntity cam,0,50,-50
TurnEntity cam,30,0,0
Запускаем, давим сначала на табуляцию, потом на пробел:
(я ещё сделал рандомное назначение цвета для промокашек - думаю, не стоит объяснять как это делается)



Как видите, вся невыпуклость кастрюли налицо.

Однако, попробуйте нажимать TAB несколько раз. Видите, одна кастрюля проваливается в другую? Поэтому, повторюсь, тримеши надо использовать только для статических объектов.

При генерации тримеша подставим массу 0:
Global PotHull = BodyCreateMesh(PotMesh, 0)
Как видите, теперь на кастрюлю не действует гравитация и столкновения с объектами не сообщают ей никаких импульсов, т.е. она статична. Именно так и создаются физические модели для уровней (Конечно, кастрюля - не слишком удачный пример для уровня).

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



Кстати, при экспорте из Макса физической модели не обязательно хранить инфу о текстурах, нормалях и т.п. - так экономится размер файла

PotMeshPhys = LoadMesh("PotPhys.b3d")
Global PotHull = BodyCreateMesh(PotMeshPhys, 0)
pxBodySetFlagCollision(PotHull, 0)
FreeEntity PotMeshPhys
Тут всё аналогично хуллу.

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

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


Следующий пост будет посвящён компаундам.
З.Ы. К сожалению, теперь буду писать с частотой максимум раз в неделю т.к. с 11-го уже опять школа

З.З.Ы. !! Не забывайте про ResetXForm! !!

Надеюсь, этот пост оказался вам полезен.
Вложения
Тип файла: zip PhysXExample7.zip (11.8 Кб, 1968 просмотров)
__________________
Мои проекты:
Анальное Рабство
Зелёный Слоник
Дмитрий Маслов*
Различие**
Клюква**

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

(Offline)
 
Ответить с цитированием
Эти 37 пользователя(ей) сказали Спасибо ABTOMAT за это полезное сообщение:
3dr1aN (09.01.2009), ACTIVATOR (20.01.2009), Alex_Noc (09.01.2009), Arles (25.08.2009), baton4ik (01.02.2010), Blender (17.01.2010), Brain (15.01.2010), CRASHER (18.01.2009), den (27.07.2010), Diablomania (14.08.2009), Dream (09.01.2009), Eugenes (01.07.2012), h1dd3n (31.01.2009), H@NON (09.01.2009), Harter (15.10.2009), HolyDel (17.01.2009), Hurrit (16.05.2010), Максим (09.01.2009), is.SarCasm (20.02.2010), Isono (17.01.2009), laaqiq (18.01.2010), Main Cry (23.04.2009), mr.DIMAS (11.01.2009), m_512 (13.02.2009), Nex (23.06.2009), NitE (10.01.2009), PackegerX (03.02.2010), Randomize (20.01.2009), rr333 (12.02.2009), SBJoker (09.01.2009), Slavik (24.06.2009), strayhnd (30.06.2010), Tadeus (09.01.2009), tormoz (09.01.2009), viper86 (08.02.2009), WhiteBlack (27.07.2010), ІГРОГРАЙКО (02.07.2009)