|
Полезные функции Выкладываем полезные функции, чтоб не изобретать велосипед заново... |
15.05.2009, 11:46
|
#1
|
AnyKey`щик
Регистрация: 15.05.2009
Сообщений: 3
Написано 0 полезных сообщений (для 0 пользователей)
|
синхронизация физики и анимации (newton)
Пользую newton для создания создания прототипа игрушки.
В процессе столкнулся с необходимостью подогнать физику под анимацию модели. Т.е. придать физическому телу (phBody) такие линейную и угловую скорость, что бы при следующем проходе phWorldStep() оно заняло то же положение, что и Entity, которому оно соответствует. В Ньютоне я подходящих инструментов не нашел. Пришлось писать самому. Все значения подгонял ручками на глазок, поэтому не везде работает гладко. Но если использовать предложенные значения, то результат получается достаточно точный. (у меня разница между координатами Entity и phBody при каждом проходе в среднем составляла 0,02 единицы)
Скажу большое спасибо тому, кто сумеет повысить точность и позволит использовать промежуточные значения шага phWorldStep, кроме указанных.
Function SyncBodyWithEntity(Body%,Entity%,phTiming#)
;Перемещает Физ.Тело в положение, которое занимает Entity
;Криво работает со значениями шага phWorldStep(phTiming#) меньше 0.1
;Точнее всего работает со значениями 0.01, 0.05, 0.1 и выше.
;При значении Меньше чем 0.01 - безбожно глючит
a#=1/phTiming ;обратная величина от шага phWorldStep()
;рассчитываем угловую скорость Entity исходя из разницы углов тела и Entity
Local deltaAngX=EntityPitch(Entity,1)- phBodyGetPitch(Body)
Local deltaAngY=EntityYaw(Entity,1)- phBodyGetYaw(Body)
Local deltaAngZ=EntityRoll(Entity,1)- phBodyGetRoll(Body)
;обрезаем полученный угол до диапазона от -180 до +180
If Abs(deltaAngX)> 180 Then deltaAngX = deltaAngX -360 * deltaAngX/Abs(deltaAngX)
If Abs(deltaAngY)> 180 Then deltaAngY = deltaAngY -360 * deltaAngY/Abs(deltaAngY)
If Abs(deltaAngZ)> 180 Then deltaAngZ = deltaAngZ -360 * deltaAngZ/Abs(deltaAngZ)
Local OmegaX#=(deltaAngZ)Mod 360
Local OmegaY#=(deltaAngZ)Mod 360
Local OmegaZ#=(deltaAngZ)Mod 360
;разворачиваем вектор скорости в обратную сторону
OmegaX=OmegaX*-1
OmegaY=OmegaY*-1
OmegaZ=OmegaZ*-1
;Вычисляем линейную скорость Entity исходя из разницы координат тела и Entity
Local fdeltax#=EntityX(Entity,1)-phBodyGetX(Body)
Local fdeltay#=EntityY(Entity,1)-phBodyGetY(Body)
Local fdeltaz#=EntityZ(Entity,1)-phBodyGetZ(Body)
Local k = phTiming*60 ;Коэффициент скорости. Пришлось оставить Int. Иначе падает точность :(
Local VelX# = fdeltax*a*k
Local VelY# = fdeltay*a*k
Local VelZ# = fdeltaz*a*k
;придаем телу угловую и линейную скорость
phBodySetVel(Body,VelX,VelY,VelZ)
phBodySetOmega(Body,OmegaX,OmegaY,OmegaZ)
End Function
P.s. На blitz'e пишу недавно, поэтому не ругайте, если в коде что то коряво.
|
(Offline)
|
|
21.01.2010, 00:08
|
#2
|
Дэвелопер
Регистрация: 17.01.2007
Сообщений: 1,552
Написано 351 полезных сообщений (для 774 пользователей)
|
Ответ: синхронизация физики и анимации (newton)
Решил вот дополнить для интересующихся синхронизацию физики с анимацией на Physics'е, да и работает стабильнее.
Global tempPiv = CreatePivot()
;--- Параметры : тело, ентити, масса тела, коэффициент упругости
Function pxSyncBodyWithEntity(body, ent, mass#, k#=1)
Local x#, y#, z#
Local pit#, yaw#, roll#
Local dx#, dy#, dz#
Local dPit#, dYaw#, dRoll#
x = pxBodyGetPositionX(body)
y = pxBodyGetPositionY(body)
z = pxBodyGetPositionZ(body)
pit = pxBodyGetRotationPitch(body)
yaw = pxBodyGetRotationYaw(body)
roll = pxBodyGetRotationRoll(body)
RotateEntity tempPiv, pit, yaw, roll, 1
dx = EntityX(ent,1) - x
dy = EntityY(ent,1) - y
dz = EntityZ(ent,1) - z
TFormVector 0, 0, 1, ent, tempPiv
x = TFormedX() : y = TFormedY() : z = TFormedZ()
dPit = VectorAngle#(0,0,1, 0,y,z)
dYaw = VectorAngle#(0,0,1, x,0,z)
TFormVector 1, 0, 0, ent, tempPiv
x = TFormedX() : y = TFormedY() : z = TFormedZ()
dRoll = VectorAngle#(1,0,0, x,y,0)
EntityParent ent, tempPiv
dPit = dPit * Sgn(EntityPitch(ent,0))
dYaw = dYaw * - Sgn(EntityYaw(ent,0))
dRoll = dRoll * Sgn(EntityRoll(ent,0))
EntityParent ent, 0
;---- ВАРИАНТ 1. действует трение
x = pxBodyGetLinearSpeedX(body)
y = pxBodyGetLinearSpeedY(body)
z = pxBodyGetLinearSpeedZ(body)
pxBodyAddForce(body, (dx*mass-x)*k, (dy*mass-y)*k, (dz*mass-z)*k, 2)
x = pxBodyGetLocalAngularSpeedX(body)
y = pxBodyGetLocalAngularSpeedY(body)
z = pxBodyGetLocalAngularSpeedZ(body)
pxBodyAddLocalTorque(body, (dPit-x)*k, (dYaw-y)*k, (dRoll-z)*k, 2)
;---- ВАРИАНТ 2. без воздействия трения
;pxBodySetLinearSpeed(body, dx*mass*k, dy*mass*k, dz*mass*k)
;pxBodySetLocalAngularSpeed(body, dPit*k, dYaw*k, dRoll*k)
End Function
Function VectorAngle#(Ax#,Ay#,Az#, Bx#,By#,Bz#)
Local d# = VectorDot(Ax#,Ay#,Az#, Bx#,By#,Bz#)
Local m# = VectorMagnitude(Ax#,Ay#,Az#)*VectorMagnitude(Bx#,By#,Bz#)
Return ACos(d#/m#)
End Function
Function VectorDot#(Ax#,Ay#,Az#, Bx#,By#,Bz#)
Return (Ax*Bx) + (Ay*By) + (Az*Bz)
End Function
Function VectorMagnitude#(Ax#,Ay#,Az#)
Return Sqr(Ax*Ax + Ay*Ay + Az*Az)
End Function
PS
Обратная величина будет так :
a# = phTiming ^(-1)
|
(Offline)
|
|
Эти 4 пользователя(ей) сказали Спасибо H@NON за это полезное сообщение:
|
|
Ваши права в разделе
|
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 16:26.
|