forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   Полезные функции (http://forum.boolean.name/forumdisplay.php?f=17)
-   -   синхронизация физики и анимации (newton) (http://forum.boolean.name/showthread.php?t=8293)

drwoland 15.05.2009 11:46

синхронизация физики и анимации (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 пишу недавно, поэтому не ругайте, если в коде что то коряво.

H@NON 21.01.2010 00:08

Ответ: синхронизация физики и анимации (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)


Часовой пояс GMT +4, время: 16:42.

vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot