# passing quaternions to objects over time

hi.

lookAt is a very useful function, but it is instant.

i want to make a turret slowly track and line up a target.

i have a quat function that returns the difference between this and that angle. but how do i apply this quat to the turret in a way that 1.) take time and 2.) is interuptible or updatable if the target moves in a new unexpected direction.

AFAIK panda’s lerp functions are uninterruptible.

my code snippets so far (which i have scavenged mostly from the awesome posts on this board - top bunch of people here), which work but aren’t interruptible, are:

``````def quat_by_quat(self,base,obj2):
#takes 2 objects
# gets pos and quat of obj1
# get required quat to point at obj2
#return difference
obj1 = base
quat1 = obj1.getQuat()
pos1 = obj1.getPos()
obj1Dir = quat1.getForward()
obj1Dir.normalize()
#v = obj1Dir
vec2obj2 = obj2.getPos() - pos1
vec2obj2.normalize()
angleTowards = self.pointAt(base,obj2)
#print ("quat1 and asngeltwards" , quat1, angleTowards)
angleinQuat = Quat()
angleinQuat.setHpr(Vec3(angleTowards))
#print ("angle in quat is ", angleinQuat)
#qSubq =  quat1 - angleinQuat
#print ("angle to turn is ",qSubq)
#obj1.setQuat(angleinQuat)
return angleinQuat

def pointAt(self, base,target):
self.tempNode = render.attachNewNode('tempNode')
self.tempNode.setPos(base.getPos())
self.tempNode.setHpr(base.getHpr())
self.tempNode.lookAt(target)
tempVec = self.tempNode.getHpr()
#print ("tempVec is", tempVec)
return tempVec

def turn_towards(self,base,angle,turnspeed):
myInterval1 = base.hprInterval(turnspeed, angle)
seq = Parallel(myInterval1)
seq.start()``````

and called with a function like

``````            qAngle = self.quat_by_quat(self.ship_root,self.target)
self.turn_towards(self.ship_root,qAngle,self.turn_rate)``````

it’s my lack of experience again, but i need a way to break the quat result into a per second turn rate and then apply it to an objects rotation.it must be simpler than it seems but right now my lack of knowledge is confusing me.

Does your turret have any sort of “update” task/method? If not, what I suggest is giving it one such - either a task of its own, or, if you have a global “update” task, perhaps a method to be called in said global update.

In this method, check the difference between your turret’s facing and its desired facing; if the shortest turn would be to the left, turn left by some value multiplied by the time since last update, and the opposite if the shortest turn would be to the right.

You might also want an edge-case to handle situations in which the shortest turn would be smaller than the turn produced by the method above, causing the turret to “overshoot”; in these cases, simply snap the turret’s facing to the desired facing.

Since you’re checking the desired direction on each update, the turret should keep turning in the correct direction, even if that direction changes.

That should, I think, do the job. thanks for the answer man, i learned some new things.

however, i didnt learn what i was asking for. i think my question was a little vague so let me ask the question better…

how can i manually interpolate a slerp between 2 quaternions (the existing object and a target object) in panda3d?

i cant find any function in the api documentation. but i figure if i can get this information i can then apply a rotation value to it based on turn rate.

A slerp is just a linear lerp between two quaternions (and then normalize the result).

i.e. R = Q1 + t * (Q2 - Q1)

The result of R will range from Q1 to Q2 while t ranges from 0 to 1. You can make this computation every frame yourself in a task and then apply R to whatever node you like.

Or, you can have Panda do it for you with something like a LerpQuatInterval.

David

Thanks, that’s what I needed. The built in lerp isn’t iterable but that formula looks spot on and much simpler than lots of the reference out there. edit - an error pops up.

r = p0 + t * (p1 - p0)
TypeError: unsupported operand type(s) for *: ‘float’ and ‘libpanda.LQuaternionf’

unfortuantley i do not know to solve this problem.

Try reversing the order of operations in that multiplication; it may well simply be that there’s an operator defined for Quat x Scalar but not Scalar x Quat.

In other words, try:

r = p0 + (p1 - p0) * t

that worked. thanks a lot!