3D and 2D track to point with proper interpolation in Python Solution

I’ve been trying to do this for quite some time now and only today I came up with a solution!
this might seem a bit redundant since blender has a Track To actuator, but with this code you don’t need a object to track, just a position in space.

this is a substitute for the alignAxisToVec and it dosn’t couse any unexpected orientation issues


def lerp(num1,num2,fac):
    #Linear interpolation from num1 to num2
    #This method guarantees num = num1 when time = 1
    return (1-fac)*num2 + fac*num1

def trackToPoint( obj, point, front="Y", up="Z", time=1/3):
    #Gets direction of point
    direction = Vector(point) - obj.position
    #Gets the target rotation matrix taking in acount the up and front axis
    rot_quat = direction.to_track_quat(front, up).to_matrix()
    #Apply the rotation
    obj.worldOrientation = lerp(rot_quat, obj.worldOrientation, time)


I made some small modifications so it can track disconsidering the height of the point:


def lerp(a,b,fac=1/3):
    return a + (b - a) * fac


def trackToPoint( obj, vecPos, front="Y", up="Z", time=1/3, two_D=False):
    vecPos = Vector(vecPos)
    if two_D == True: vecPos.z = obj.position.z
    direction = Vector(vecPos) - obj.position
    rot_quat = direction.to_track_quat(front, up).to_matrix()
    obj.worldOrientation = lerp(obj.worldOrientation, rot_quat, time)



If this helped you in any way let me know!
Thanks for the reply! :wink:

You may have noticed that I’m quite picky about code style… So I thought I’d just post a comment on the subject.
Firstly, I have spent far too much time writing cross products to have missed the fact that there is a to_track_quat method. Aw man!

I rewrote your provided methods ina more PEP8 compliant format, if you don’t mind :slight_smile:


def lerp(a, b, factor):
    """Interpolate between two values based upon an interpolation factor


    :param a: starting value
    :param b: ending value
    :param factor: interpolation factor
    :returns: interpolated value between (a and b)
    """

    return (1 - factor) * a + factor * b


def track_to_point(obj, point, front="Y", up="Z", factor=1/3):
    """Aligns an object to face a 3D point in space


    :param obj: game object to align
    :param point: point to align with
    :param front: optional alignment direction
    :param up: optional direction to cross with alignment and front vectors
    :param factor: optional interpolation factor
    """
    #Gets direction of point
    direction = Vector(point) - obj.position


    #Gets the target rotation matrix taking in acount the up and front axis
    target_orientation = direction.to_track_quat(front, up).to_matrix()
    source_orientation = obj.worldOrientation
    
    #Apply the rotation
    obj.worldOrientation = lerp(source_orientation, target_orientation, factor)

It’s interesting to see your lerp method. I’ve written my own lerp method in by network library, but I use the more compact interpolation formula


a + (b - a) * factor

which doesn’t play nicely with matrices which do not add together very nicely. (You want to multiply them, which is less fun). In other words, simplifying the expression is nicer for the mathutils types!

One or two words of caution - calling arguments num1 and num2 but using them “backwards” may be confusing :wink:

Very nice reply Anoose I really liked how you organized the code!
I’m going to add a second lerp function that uses a + (b - a)*factor it’s simpler to use with matrices! hehe

This is something I found on Wikipedia:


// Imprecise method which does not guarantee v = v1 when t = 1,
// due to floating-point arithmetic error.
float lerp(float v0, float v1, float t) {
  return v0 + t*(v1-v0);
}
 
// Precise method which guarantees v = v1 when t = 1.
float lerp(float v0, float v1, float t) {
  return (1-t)*v0 + t*v1;
}

I feel your pain bro, I also have wasted to much time using other, more archaic methods. When I found to_track_quat I was like aaawww man… I can’t belive it’s this easy!!! I need to share with the community!

how would I use a second objects +Z axis as up in a this track to?

BluePrintRandom it’s by defalt using +Z as up maybe you want to use it as front like this: trackToPoint(obj, [0,0,0], “-Z”,“Y”) This would be used for a camera, just change the third and fourth value to the corresponding axis you wish to track…
it can take “X”,"-X",“Y”,"-Y",“Z” and “-Z”

I have been using alignAxisToVect() with using a second object as a target for up, so that the whole rig can flip upside down in game, without flipping the camera, so what I mean in a target object, and a referance object,

I just thought this would get more attention, even though I found the solution, I think this is a very interesting method…
If this helped you in any way let me know!
Thanks for the reply!

Very nice. It helped me.

It makes me very happy to know that I helped you Raco, thank you very much for the feedback!

Good coding! :wink:

I made some small modifications so it can track disconsidering the height of the point, check the first post!

I came to this thread from another one talking about path following so apologies for resurrecting an old thread.

I’ve had some trouble in the past with the alignAxisToVect() method so I thought I’d check this other method out. it works well but there is some very funky behavior when turning, especially when changing direction 180 degrees. Check out the attached blend to see what I mean.

This shows most obviously when I slow it down to a time factor of 1/100 but it’s still visible at 1/3 factor as well.
I read some thing about why this happens when i was reseraching vector math a few years ago, but I couldn’t really understand it then and I still don’t. Anyone know what’s going on?

FollowPath_manual.blend (507 KB)

Generally better using Quaternion.slerp() instead of the lerp function

On the X-axis alignAxisToVect is working fine, so you’d know.

Yes, track to on the X axis does work rather well but it is very much broken on the Y axis.

I’ve put together a quick blend (not very pretty, sorry) for using quaternion slerp.
It works very well on all the axis’ I tried. If you wanted it to track in 2d space you’d just use [target.worldPosition.x,target.worldPosition.y,own.worldPosition.z] as the target for the second point.

Here’s the Blend file:
FollowPath_slerp.blend (512 KB)

Thanks for the example.

I use this in Elpis to track to points, hope it helped somehow…

Yes, I never use the built in track to actuator any more, or even the python functions built in to blender, since this gives a much better, bug free result. Thanks. :slight_smile:

Yeah, I tend to use

object.alignAxisToVect(object.getVectTo(thing)[1],0,1)
object.alignAxisToVect(object.parent.worldOrientation.col[2],2,1)

one thing that is really cool,

I use that in cconjunction with the first part…

I then localize the targets position to the “base”

then the distance off x is the turret angle for the other axis.

so you can aim a turret base at a objects xy,and the cannon can aim up and down on the z,

(I will post a little demo as I just realised how hard this is to explain)

I use it in my robot arms for wrectified, it is a bit like my own IK system.