joleanes.com
Home About Scripts Plugins Tutorials Home Gallery Links
< 1 2 >

 

LOOKAT FLIPPING ISSUE

Well, the previous method is pretty useful to twistbones, but what about nodes with lookat controllers? they also flip in those undesirable angles. One of the best way to fix that problem is writing our own lookat script controller.

The lookat constraint finds out the right lookat orientation by building up a rotation matrix with the given node and target position. But that algorithym has that flipping issue, the way that we can avoid that is not using a matrix to build up the lookat orientation, instead, we will build up a quaternion.

First, let's see why this flipping happens:

 

MATRIX THEORY

The matrices are always used to transform and store objects transformations in 3d space, a 3x4 matrix (also known as matrix3) is used in almost all 3d aplications. A matrix3 is a special matrix that is composed by four vectors or rows of three values, the first vector stores the direction and length of the x-axis of the node, the second vector stores the direction and length of the y-axis, the third vector stores the direction and length of the z-axis. This three vectors stores the rotation and scale of the node, for example, if the node is scaled 200% in the x axis the first vector lenght will be 2. The position of the node is stored in the fourth vector. If the matrix is a rotation matrix, the last vector should be [0,0,0] and the length of the first three vectors should be 1.

In order to transform an object several times, a matrix multiplication have to be used (the order of these transformation is important, as mentioned before). For example, when you link a node to another, the aplication internally is multiplying the local transform matrix of the child node with the transform matrix of the parent node to find the total transformation of the child node, just as follows:

T=L*P

where T is the total transformation of the node, L is the Local transform matrix, and P is the parent transformation.

 

The lookat constraint finds the rotation by finding the first three rows of the matrix3. Just as Follows:

row1=normalize (Target.position-Node.position)
row2=normalize (cross row1 Upvector)
row3=normalize (cross row1 row2)

In the first line a vector from the Node to the target is calculated, it defines the direction from the node to the target, this value is then normalized to make sure that the vector length is 1.
In the second line another vector is found, this vector is perpendicular to both, the first row and the Upvector (this vector is defined by the node selected as upNode), the cross product is used to find a vector perpendicular to another two vectors. Again the value is normalized.
The last vector is the vector perpendicular to the first two vectors.

The order of the rows depends on how the lookat controller was configurated.

The direction of the last axis will flip if the first axis goes from the left side to the right side of the upVector. That happens when the y-axis goes beyond 90 degrees or below -90 degrees depending on how the lookat constraint was configurated.

 

In order to fix the flipping issue we must understand how Quaternion works:

 

QUATERNION THEORY

quaternionA quaternion is another way to set the rotation of an object, but instead of having 3 values defining the amount of rotation per each axis, it has 4 values that defines the rotation in complex number system. The adventage of using quaternions is that they are faster to compute than matrices and its interpolation is smother than euler angles, because of that, quaternions are widely used to calculate rotations in all kind of 3d aplications. Animators preffer to use Euler angles though, With euler angles you can edit the interpolation curves per each axis using the tangent handles, with quats you can't, nevertheless, you can edit the quats interpolation using Tension, Continuity and Bias values (TCB).

A quaternion can be built up using a vector and a scalar value. This is the AngleAxis to Quat Conversion. And that is the way that you should built up a quaternion given any case. The Vector defines the Axis where the node will be rotated, and the scalar value defines the amount of rotation on the given axis (angle of rotation). In this animated image you can see how the AngleAxis reach some orientations (the arrow is the direction of the axis).

 

FIXING THE FLIPPING ISSUE IN LOOKAT SETUPS

Now, to get the lookat rotation without the flipping, we're going to build up the quaternion using the AngAxis to Quat conversion. If we do that we can rotate the bone from it's resting orientation to the desired lookat orientation, without getting that flip in the 90 degrees Y-axis. It will only flip in that almost unreachable orientation (the bone overlaping its parent).

To continue with the tutorial download this file: flipingles02.zip.

This file has a 3ds max 2008 scene with 3 bones, and one point helper. Those are: Spine01, Spine02, Joint and Target (the joint bone is used to keep the mesh volume). In this case we need the Spine02 to lookat the Target helper. To do so, select the object "Spine02", go to the motion panel, select the rotation track and assign it a script rotation controller . Create a variable called "Target" and assign it the Target node, then, create a variable "Parent" and assign it the Spine01 node, and finally create a variable NodePos and assign it the "Spine02" position controller (select the variable click "assign controller" find the Spine02 object, select the position track and press OK).

The code in the Expression Box will be as follows (replace the text that is already there):

theTargetVector=(Target.transform.position * Inverse Parent.transform)-NodePos.value
theAxis=Normalize (cross theTargetVector [1,0,0])
theAngle=acos (dot (Normalize theTargetVector) [1,0,0])
Quat theAngle theAxis

In the first line we're Finding the vector that goes from the spine01 position to the target position, that vector must be in respect to the spine01 parent, to get an orientation in parent space (the way that local controllers works). the NodePos.value is already in parent space because that variable is referencing the local position controller of the spine01.

In the second line we are finding the axis in which the node should rotate to aim that position, that vector is perpendicular to the TargetVector and the x-axis (1,0,0)

In the third line we're finding the amount of rotation needed to reach the desired rotation, that value is the angle between the x-axis (1,0,0) and the TargetVector.

In the Last line we build up our quaternion using the axis and the angle.

Here you can see what we have got so far, an almost flipless lookat script controller:

flippingless

 

You can download the finished version here: flippingless02_final.zip

Ok, this is it, thanks for watching this tutorial, see you the next Time!.

 

< 1 2 >

 

 

 

Copyright ©2010, Felix Joleanes.