Показать сообщение отдельно
Старый 10.02.2009, 17:43   #11
viper86
Нуждающийся
 
Аватар для viper86
 
Регистрация: 19.11.2008
Адрес: Украина, Луганск
Сообщений: 72
Написано 34 полезных сообщений
(для 123 пользователей)
Материалы

Материалы в PhysX

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

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

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

pxMaterialSetDyFriction(mat%, fric#) 	

fric=[0,inf]
для динамических тел

pxMaterialSetStFriction(mat%, fric#) 	

fric=[0,inf]
для статических тел

pxMaterialSetRestitution(mat%,rest#)	

rest=[0,1]
для любых тел

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

Давайте попробуем создать свой материал. Создание окна, камеры, света, физического мира (и т.п.) подробно описывать, я думаю, нет смысла, тут и так всё понятно:

Graphics3D 800,600,32,2
SetBuffer BackBuffer()

pxCreateWorld(1,"")
pxSetGravity(0,-10,0)

cam=CreateCamera()
PositionEntity cam,15,7,-15
RotateEntity cam,20,35,0

light=CreateLight()
PositionEntity light,10,10,-10

While Not KeyDown(1)

pxRenderPhysic(60,0)
RenderWorld
Flip
Wend
End
Создадим статический куб (с массой = 0), растянем его и повернём, чтобы получился склон (образно назовём её горка):

gorka_body=pxBodyCreateCube(10,0.2,10,0)
pxBodySetRotation gorka_body,0,0,-25
pxBodySetPosition gorka_body,0,5,0
gorka=CreateCube()
ScaleEntity gorka,10,0.2,10
pxBodySetEntity gorka,gorka_body
Так как тело статическое, то в цикле не нужно обновлять позицию меша gorka (pxBodySetEntity gorka,gorka_body), достаточно раз написать при создании. Конечно, можно вместо этого использовать PositionEntity и RotateEntity такие же, как и gorka_body, но это дольше и больше кода.

Должно получится приблизительно так:



Для большей наглядности создадим зеркальный пол:

plane=CreatePlane()
EntityAlpha plane,0.5
CreateMirror()
Теперь приступим непосредственно к созданию материала. Напишем следующее (сразу после создания физического мира и гравитации):

mat_stat1=pxCreateMaterial()
pxMaterialSetStFriction(mat_stat1,0.1)
pxMaterialSetRestitution(mat_stat1,0.5)
Применим наш материал к горке:

pxMaterialSetToBody(gorka_body,mat_stat1)
Вуаля! ))) Теперь наша горка имеет заданный нами материал. Но этого не заметно без взаимодействия с другими обьектами. Сделаем так: напишем функцию для создания кубиков и будем бросать 3 кубика с разными материалами на нашу горку, чтоб нам нагляднее была видна разница. Создаём тип кубиков и пишем функции создания и обновления:

Type pxCube
	Field mesh
	Field body
	Field material
End Type

Function CreatepxCube(x#,y#,z#,mat%=0)
	pxC.pxCube = New pxCube
	pxC\mesh = CreateCube()
	pxC\body = pxBodyCreateCube(1,1,1,1)
	pxC\material = mat
	If mat<>0 Then pxMaterialSetToBody(pxC\body,pxC\material)	
	pxBodySetPosition pxC\body,x,y,z	
End Function

Function UpdatepxCubes()
	For pxC.pxCube = Each pxCube
		pxBodySetEntity pxC\mesh, pxC\body
	Next
End Function
Здесь всё должно быть понятно, так как функции взяты с прошлых примеров. Только мы добавили поле material и применение материала к телу с помощью pxMaterialSetToBody(). Теперь у нас функция CreatepxCube() передаёт 4 параметра:позицию по x,y,z и необязательный материал (если = 0 то не применять никакой материал). Теперь создаём 3 новых материала в том же месте, где и первый (статический):

mat_dyn1=pxCreateMaterial()
pxMaterialSetDyFriction(mat_dyn1,0.1)
pxMaterialSetRestitution(mat_dyn1,0.1)

mat_dyn2=pxCreateMaterial()
pxMaterialSetDyFriction(mat_dyn2,50)
pxMaterialSetRestitution(mat_dyn2,0.2)

mat_dyn3=pxCreateMaterial()
pxMaterialSetDyFriction(mat_dyn3,0.1)
pxMaterialSetRestitution(mat_dyn3,0.9)
А в главном цикле пропишем создания 3х кубиков при нажатии на enter:

While Not KeyDown(1)

if keyhit(28) Then
	CreatepxCube(-3,10,-3,mat_dyn1)
	CreatepxCube(-3,10,0,mat_dyn2)
	CreatepxCube(-3,10,3,mat_dyn3)
End If

pxRenderPhysic(60,0)
UpdatepxCubes()
RenderWorld
Flip
Wend
End
Жмём F5, а затем enter и смотри, как ведут себя кубики. Если вы задавали те же коэффициенты, что я и давал, то у вас должна получиться такая картина:



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

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

pxMaterialSetFrictionCombineMode(mat%, mode%)

pxMaterialSetRestitutionCombineMode(mat%, mode%)

где mode:

0 - среднее значение: (a+b)/2
1 - минимум: min(a,b)
2 - умножение: a*b
3 - максимум: max(a,b)
4 - какой-то непонятный режим, скорее всего тестовый и нигде не используемый
Попробуем добавить ещё 3 материала, только теперь используя комбинированный режим. Что бы лучше увидеть разницу, коэффициенты оставим те же:

mat_dyn4=pxCreateMaterial()
pxMaterialSetDyFriction(mat_dyn4,0.1) 
pxMaterialSetRestitution(mat_dyn4,0.1)
pxMaterialSetFrictionCombineMode(mat_dyn4,1)
pxMaterialSetRestitutionCombineMode(mat_dyn4,1)

mat_dyn5=pxCreateMaterial()
pxMaterialSetDyFriction(mat_dyn5,50)		 
pxMaterialSetRestitution(mat_dyn5,0.2)		
pxMaterialSetFrictionCombineMode(mat_dyn5,2)		
pxMaterialSetRestitutionCombineMode(mat_dyn5,2)		

mat_dyn6=pxCreateMaterial()
pxMaterialSetDyFriction(mat_dyn6,0.1)		 
pxMaterialSetRestitution(mat_dyn6,0.9)		
pxMaterialSetFrictionCombineMode(mat_dyn6,3)		
pxMaterialSetRestitutionCombineMode(mat_dyn6,3)
Сделаем, что бы по нажатию кнопки пробел менялся режим: обычный или комбинированный. И добавим функцию удаления кубиков, чтоб когда появлялись новые, старые им не мешали:

While Not KeyDown(1)
	
	If KeyHit(57) Then state=1-state
		
	If KeyHit(28) Then	
		DeletepxCubes()	
		Select state
			Case 0 
			CreatepxCube(-3,10,-3,mat_dyn1)
			CreatepxCube(-3,10,0,mat_dyn2)
			CreatepxCube(-3,10,3,mat_dyn3)			
			
			Case 1
			CreatepxCube(-3,10,-3,mat_dyn4)
			CreatepxCube(-3,10,0,mat_dyn5)
			CreatepxCube(-3,10,3,mat_dyn6)
		End Select         	
	End If
	
	pxRenderPhysic(60,0)
	UpdatepxCubes()
	RenderWorld
	
	If state=0 Then
		Text 10,10,"Normal mode"
		Else
		Text 10,10,"Combine mode"
	EndIf
	
	Flip
Wend

Function DeletepxCubes()
	For pxC.pxCube = Each pxCube
	FreeEntity pxC\mesh 
	pxDeleteBody pxC\body 
	Delete pxC		
	Next
End Function
Вот теперь очень хорошо чувствуется разница. Первый куб взял минимальные значения от горки (потому скользик как санки по снегу), второй наоборот еле едит (перемножились коэффициенты), ну а третий как заводной скачет(максимальные значения):



Полный код приведёт в прикреплённом файле.

Также ещё существуют так называемые анизотропные материалы:

pxCreateAnisotripicMaterial(body%, nx#, ny#, nz#)

где nx#, ny#, nz# - направление вектора анизотропии
Такой тип материала изменяет значения в зависимости от направления движения. Например при движении вперёд значения больше, чем при вдижении вбок. Используется для создания лыж, санок и подобных.

Для анизотропного материала можно применять особый тип трения:

pxMaterialSetFrictionV(mat%, sfric#, dfric#)

где:
sfric - статический коэффициент трения [0,inf]
dfric - динамический коэффициент трения [0,inf]
sfric означает насколько тяжело сдвинуть тело с места, а dfric - насколько тяжело в движении.


Надеюсь я смог доходчиво обьяснить изложенный материал и если меня не закидают помидорами и АВТОМАТ не будет против, то я буду продолжать помогать ему писать учебник. Впереди ещё много интересного (магниты, ткани, мягкие тела и тд)
Вложения
Тип файла: zip materials.zip (1.2 Кб, 1667 просмотров)
__________________
Лечим заражение... одна пуля - один больной.

Последний раз редактировалось viper86, 10.02.2009 в 19:49.
(Offline)
 
Ответить с цитированием
Эти 26 пользователя(ей) сказали Спасибо viper86 за это полезное сообщение:
3dr1aN (12.02.2009), ABTOMAT (10.02.2009), baton4ik (02.02.2010), Brain (15.01.2010), den (27.07.2010), Diablomania (14.08.2009), Dream (13.02.2009), Ичигорь (01.03.2009), FireOwl (10.10.2009), h1dd3n (13.02.2009), Harter (08.10.2009), HolyDel (18.02.2009), Hurrit (16.05.2010), Isono (11.02.2009), Main Cry (23.04.2009), m_512 (13.02.2009), Nex (23.06.2009), Randomize (13.02.2009), Slavik (24.06.2009), strayhnd (30.06.2010), Tadeus (18.02.2009), tirarex (01.03.2012), tormoz (10.02.2009), TxN (15.08.2009), WhiteBlack (27.07.2010), ІГРОГРАЙКО (02.07.2009)