Rotation from A to B

Started by
3 comments, last by Endar 17 years, 9 months ago
For my skeletal animation system, I needed to find the local transform required to draw a bone given the two points to draw it from. I wanted the bone to be more complicated than just a line, so I have a small pyramid that is drawn. It's being drawn from point A to point B where point A is the center of the base of the pyramid (square), and point B is the tip of the pyramid.

echo::util::CVector3d p1( 0.064704396f, 40.745468f, 0.0f );
echo::util::CVector3d p2( 0.064704396f, 44.231636f, 0.0f );

echo::util::CVector3d localZ( p2 - p1 );
localZ.normalize();	// the direction from the start point to end point

// assuming that the up vector for the world is (0,1,0)
echo::util::CVector3d localX;
localX = localZ.crossProduct( echo::util::CVector3d(0,1,0) );

// find the local y axis
echo::util::CVector3d localY;
localY = localX.crossProduct( localZ );

// create the matrix
// http://www.gamedev.net/community/forums/viewreply.asp?ID=2391549
echo::util::CMatrix m;

// normalize, just in case
localX.normalize();
localY.normalize();
localZ.normalize();

m(0,0) = localX.x;	m(1,0) = localY.x;	m(2,0) = localZ.x;
m(0,1) = localX.y;	m(1,1) = localY.y;	m(2,1) = localZ.y;
m(0,2) = localX.z;	m(1,2) = localY.z;	m(2,2) = localZ.z;

m.setTranslation( p1 );

I was given this code here by "someusername", and has worked for some time, but I recently noticed that with some bones (simply the distance between two joints, not an actual "bone" object) I would get some wierdness. It would draw a straight line from the start point to a point in space. It wouldn't draw the pyramid, just a straight line. No matter how I rotated the model, the line's end point would stay anchored to the same spot. I found that I was having trouble with the end matrix 'm' and some joints. More specifically when the direction vector between the two points was the same as the world's 'up' vector. This would cause me to get floating point errors, and would therefore give me an invalid matrix to transform by the world matrx to draw the bone. So, is there another way to do this? Or should I make up some sort of a special case?
[size="2"][size=2]Mort, Duke of Sto Helit: NON TIMETIS MESSOR -- Don't Fear The Reaper
Advertisement
Any 'aim-at' algorithm that uses a fixed reference vector will have the behavior you describe. I can think of a few things you might try though:

1. Use the orientation information for each bone directly, if your keyframe format provides it. This would probably be the ideal solution.

2. Otherwise, you could create an arbitrary basis by using, instead of a fixed reference, the cardinal axis least aligned with the bone direction. The problem with this though is that the orientation will 'pop' as the bone moves around, which won't look so good.

3. A perhaps better option is to handle it as a special case, as you said. Check for the case where the bone direction is close to being aligned with the reference vector, and choose a different reference vector in this case. This will probably give you a more natural change of orientation in the pyramid as the bone moves around.
Quote:Original post by jyk
3. A perhaps better option is to handle it as a special case, as you said. Check for the case where the bone direction is close to being aligned with the reference vector, and choose a different reference vector in this case. This will probably give you a more natural change of orientation in the pyramid as the bone moves around.


This sounds like the best thing to do. How would I go about it? I mean, I could use (1,0,0) as a reference vector instead of the up vector (0,1,0), but wouldn't I have to change the order of the products?
[size="2"][size=2]Mort, Duke of Sto Helit: NON TIMETIS MESSOR -- Don't Fear The Reaper
You shouldn't have to change the order of the products. Just check the absolute value of the dot product of the normalized bone direction vector and the default reference director (0,1,0), and if it's close to 1 use a different reference vector instead.
Thanks jyk, that worked perfectly.

Perhaps if you get a chance you could explain to me more why it worked with only changing the reference vector. I know that the cross product gives you a vector perpendicular to the two operated on. And from my understanding of the code we're finding the x and y axes in the direction of the rotation (which is the z axis).
[size="2"][size=2]Mort, Duke of Sto Helit: NON TIMETIS MESSOR -- Don't Fear The Reaper

This topic is closed to new replies.

Advertisement