Code archives/3D Graphics - Misc/SmoothTrack V2.0 (Quats)
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
This one creates a stag type for every unique entity being track(This is done automatically behind closed doors, you never have to use the type) It uses quats to track, which =much smoother. You need Vector's Quat lib to use this, it's in the code archives, and included below. | |||||
Type stag Field id,p#,y#,r# Field c.quat,d.quat,rt.rotation,rb.quat Field tar.rotation End Type Function smoothTrack(ent1,ent2,speed#=0.2,lockYaw#=0,range#=150) For s.stag=Each stag If s\id=ent1 ap#=s\p ay#=s\y ar#=s\r found=True Exit EndIf Next If Not found ap#=EntityPitch(ent1,True) ay#=EntityYaw(ent1,True) ar#=EntityRoll(ent1,True) s.stag=New stag s\id=ent1 s\rt=rotation(ap,ay,ar) s\c=New quat s\d=New quat eulerToQuat(s\c,s\rt) s\tar=New rotation s\rb=New quat EndIf range=range/2 y2#=EntityYaw(ent2,True) ay=lockAng(ay,lockyaw,range) s\tar\pitch=EntityPitch(ent2,True) s\tar\yaw=EntityYaw(ent2,True) s\tar\roll=EntityRoll(ent2,True) eulertoquat(s\d,s\tar) quatSlerp(s\rb,s\c,s\d,0.1) quatToEuler(s\rt,s\rb) s\rt\yaw=lockAng(s\rt\yaw,lockYaw,range) RotateEntity ent1,s\rt\pitch,s\rt\yaw,s\rt\roll,True eulertoQuat(s\c,s\rt) s\p=ap s\y=ay s\r=ar End Function Function lockAng#(from#,lock#,range#) If KeyDown(57) DebugLog "In>"+from out#=from If from>lock d1#=360.-from+lock d2#=from-lock If d1>d2 If d2>range out#=lock+range EndIf Else If d1>range out#=lock-range EndIf EndIf Else d1#=360-lock+from d2#=lock-from If d1>d2 If d2>range out#=lock-range EndIf Else If d1>range out#=lock+range EndIf EndIf EndIf ; If out<0. out=360.-Abs(out) ; If out>360. out=out-360. If KeyDown(57) DebugLog "Out>"+out Return out End Function ;----- ;The quat lib below here is not by me, it's public domain code wrote by vector. (Inform me if I've remembered your name wrong ;) ) Type Rotation Field pitch#, yaw#, roll# End Type Type Quat Field w#, x#, y#, z# End Type ; Change these constants if you notice slips in accuracy Const QuatToEulerAccuracy# = 0.001 Const QuatSlerpAccuracy# = 0.0001 Function rotation.rotation(pitch#,yaw#,roll#) r.rotation=New rotation r\pitch=pitch r\yaw=yaw r\roll=roll Return r End Function Function copyQuat.quat(in.quat) out.quat=New quat out\w=in\w out\x=in\x out\y=in\y out\z=in\z Return out End Function Function quat.quat(w#,x#,y#,z#) q.quat=New quat q\w=w q\x=x q\y=y q\z=z Return q End Function Function setQuat(q.quat,w#,x#,y#,z#) q\w=w q\x=x q\y=y q\z=z End Function Function setRotation(r.rotation,pitch#,yaw#,roll#) r\pitch=pitch r\yaw=yaw r\roll=roll End Function ; convert a Rotation to a Quat Function EulerToQuat(out.Quat, src.Rotation) ; NB roll is inverted due to change in handedness of coordinate systems Local cr# = Cos(-src\roll/2) Local cp# = Cos(src\pitch/2) Local cy# = Cos(src\yaw/2) Local sr# = Sin(-src\roll/2) Local sp# = Sin(src\pitch/2) Local sy# = Sin(src\yaw/2) ; These variables are only here to cut down on the number of multiplications Local cpcy# = cp * cy Local spsy# = sp * sy Local spcy# = sp * cy Local cpsy# = cp * sy ; Generate the output quat out\w = cr * cpcy + sr * spsy out\x = sr * cpcy - cr * spsy out\y = cr * spcy + sr * cpsy out\z = cr * cpsy - sr * spcy End Function ; convert a Quat to a Rotation Function QuatToEuler(out.Rotation, src.Quat) Local sint#, cost#, sinv#, cosv#, sinf#, cosf# Local cost_temp# sint = (2 * src\w * src\y) - (2 * src\x * src\z) cost_temp = 1.0 - (sint * sint) If Abs(cost_temp) > QuatToEulerAccuracy cost = Sqr(cost_temp) Else cost = 0 EndIf If Abs(cost) > QuatToEulerAccuracy sinv = ((2. * src\y * src\z) + (2 * src\w * src\x)) / cost cosv = (1. - (2. * src\x * src\x) - (2 * src\y * src\y)) / cost sinf = ((2. * src\x * src\y) + (2 * src\w * src\z)) / cost cosf = (1. - (2. * src\y * src\y) - (2 * src\z * src\z)) / cost Else sinv = (2 * src\w * src\x) - (2 * src\y * src\z) cosv = 1 - (2 * src\x * src\x) - (2 * src\z * src\z) sinf = 0 cosf = 1 EndIf ; Generate the output rotation out\roll = -ATan2(sinv, cosv) ; inverted due to change in handedness of coordinate system out\pitch = ATan2(sint, cost) out\yaw = ATan2(sinf, cosf) End Function ; use this to interpolate between quaternions Function QuatSlerp(res.Quat, start.Quat, fin.Quat, t#) Local scaler_w#, scaler_x#, scaler_y#, scaler_z# Local omega#, cosom#, sinom#, scale0#, scale1# cosom = start\x * fin\x + start\y * fin\y + start\z * fin\z + start\w * fin\w If cosom <= 0.0 cosom = -cosom scaler_w = -fin\w scaler_x = -fin\x scaler_y = -fin\y scaler_z = -fin\z Else scaler_w = fin\w scaler_x = fin\x scaler_y = fin\y scaler_z = fin\z EndIf If (1.0 - cosom) > QuatSlerpAccuracy omega = ACos(cosom) sinom = Sin(omega) scale0 = Sin((1 - t) * omega) / sinom scale1 = Sin(t * omega) / sinom Else ; Angle too small: use linear interpolation instead scale0 = 1 - t scale1 = t EndIf res\x = scale0 * start\x + scale1 * scaler_x res\y = scale0 * start\y + scale1 * scaler_y res\z = scale0 * start\z + scale1 * scaler_z res\w = scale0 * start\w + scale1 * scaler_w End Function ; result will be the same rotation as doing q1 then q2 (order matters!) Function MultiplyQuat(q1.Quat, q2.Quat) Local a#, b#, c#, d#, e#, f#, g#, h# a = (q1\w + q1\x) * (q2\w + q2\x) b = (q1\z - q1\y) * (q2\y - q2\z) c = (q1\w - q1\x) * (q2\y + q2\z) d = (q1\y + q1\z) * (q2\w - q2\x) e = (q1\x + q1\z) * (q2\x + q2\y) f = (q1\x - q1\z) * (q2\x - q2\y) g = (q1\w + q1\y) * (q2\w - q2\z) h = (q1\w - q1\y) * (q2\w + q2\z) q1\w = b + (-e - f + g + h) / 2. q1\x = a - ( e + f + g + h) / 2. q1\y = c + ( e - f + g - h) / 2. q1\z = d + ( e - f - g + h) / 2. End Function ; convenience function to fill in a rotation structure Function FillRotation(r.Rotation, pitch#, yaw#, roll#) r\pitch = pitch r\yaw = yaw r\roll = roll End Function |
Comments
| ||
I haven't actually tested your code yet, but the description (from the first version posting) sounds just like AlignToVector. Is your function different than using that? |
| ||
Well yeah, allign to vector needs a vector, this actually mimics entity2.(I.e if entity2 was a head, and so was entity1, as head 2 moved, head1 would rotate to match it, but smoothly, and always taking the shortest route) Plus you can lockthe yaw on this to within a range. But it's not meant as a replacement for alligntovector, if that's what you mean. |
Code Archives Forum