Angles and Matrices and Whatnot
So I am trying to make a cylinder leg connect from one point to another in 3D. In my function the leg just sticks out at some obscure angle from the knee. Right now I have this (which does not work):
Where joints[0] is the right foot and joints[1] is the right knee, DATATYPE is just a macro for a double, also all the rotation functions on limbs[0] are in matrices. Any help would be greatly appreciated.
Code:
Vector delta = joints[1].posjoints[0].pos;
DATATYPE rot = atan2(delta.y, delta.x);
DATATYPE rot2 = atan2(delta.y, delta.z);
limbs[0].identity();
limbs[0].setPos(joints[1].pos);
limbs[0].rotateZ(rot);
limbs[0].rotateX(rot2);
limbs[0].renderSolid();
I adapted the code below from the ODE convenience function dRFromZAxis, so if you already use ODE you can just call that method.
Otherwise, here's my adaptation from the ODE method:
Hmm.. I see that I'm transposing at the end when I could just be setting columns not rows right above. That's likely a holdover from the ODE code.
Otherwise, here's my adaptation from the ODE method:
Code:
template < class T >
void __PlaneSpace(const vec3_<T> &n, vec3_<T> &p, vec3_<T> &q)
{
if ( std::abs(n.z) > SQRT1_2 )
{
// choose p in yz plane
float a = n.y*n.y + n.z*n.z;
float k = 1.0f / sqrt(a);
p.x = 0.0f;
p.y = n.z*k;
p.z = n.y*k;
// set q = n x p
q.x = a*k;
q.y = n.x*p.z;
q.z = n.x*p.y;
}
else
{
// choose p in xy plane
float a = n.x*n.x + n.y*n.y;
float k = 1.0f / sqrt(a);
p.x = n.y*k;
p.y = n.x*k;
p.z = 0.0f;
// set q = n x p
q.x = n.z*p.y;
q.y = n.z*p.x;
q.z = a*k;
}
}
template < class T >
mat4_<T> mat4_<T>::withZAxis( vec3_<T> n )
{
n.normalize();
vec3_<T> p,q;
__PlaneSpace( n, p, q );
mat4_<T> R;
R.setRow( 0, p );
R.setRow( 1, q );
R.setRow( 2, n );
return R.transpose();
}
Hmm.. I see that I'm transposing at the end when I could just be setting columns not rows right above. That's likely a holdover from the ODE code.
You don't need to get angles involved, If you have a vector you want the cylinder in, you could call that the y axis, pick a random perpendicular axis and call it x, now you can cross product x and y to get z. So you have a proper coordinate system now. To turn this into a transformation matrix (for example from the identity to this system) you make new matrix which has its cells made out of the dot products of the starting and finish.
Sir, e^iÏ€ + 1 = 0, hence God exists; reply!
This is exactly what I was looking for because I was worrying about using inverse trigonometry functions constantly for every single limb of every single person in my game. But I do not know exactly what you mean by making the matrix out of the cells of the dot products, could you explain that more clearly. Thanks!
What Unknown is saying  and what I was thinking when I was walking the dogs this morning  is pretty simple. I'll pseudocode it for you.
( untested )
Then, assuming your cylinder origin is it's center, you'll position the cylinder at the point between startPoint and endPoint and then set the rotation to the rotation matrix.
( untested )
Code:
vec3 direction = normalize( startPoint  endPoint );
// direction is your y axis
vec3 xAxis, yAxis = direction, zAxis;
if ( yAxis != vec3( 0,1,0 ))
{
// random xAxis which ISN'T yAxis
xAxis = vec3( 0,1,0 );
}
else
{
xAxis = vec3( 1,0,0 );
}
// compute a zAxis perpendicular to yAxis
zAxis = cross( xAxis, yAxis );
// compute xAxis perpendicular to y/z plane
xAxis = cross( zAxis, yAxis );
mat4 rotation;
rotation.setCol( 0, xAxis );
rotation.setCol( 1, yAxis );
rotation.setCol( 2, zAxis );
Then, assuming your cylinder origin is it's center, you'll position the cylinder at the point between startPoint and endPoint and then set the rotation to the rotation matrix.
How do you transform vectors in one coordinate system into another
So we start with two coordinate systems A and B which both have X, Y and Z axis.
Now we can take any vector u and express it in terms of these coordinate systems.
What we would like to do is find a matrix M such that M u_a = u_b.
We observe that u_b.x = <u,X_B> ; u_b.y = <u,Y_B> ; u_b.z = <u,Z_B>. Now we can expand u into its component form expressed in terms of A, <u,X_B> = <u_a.x X_A + u_a.y Y_A + u_a.z Z_A , X_B > and use the distributivity of inner product, u_b.x = u_a.x <X_A,X_B> + u_a.y <Y_A,X_B> + u_a.z <Z_A,X_B>. The same process works for u_b.y and .z, these 3 equations look just like the result of a matrix multiplication!
This allows us to conclude,
How does this apply to our situation with the cylinders?
Suppose coordinate system A is just {(1 0 0),(0 1 0),(0 0 1)}, you can already draw cylinder that points straight up in there.
Now coordinate system B would be have its yaxis as your 'delta' vector. Now it's just left to find an x and z axis. You can do this by picking a random axis that isn't y, taking its cross product with y and this gives you a new axis x, do it again to get z. (It doesn't have to be a 'random' but anything which isn't very close to y will do fine)
So that lets you calculate M, and if you plug that into opengl (remember opengl transposes matrices compared to the normal way we write them, and there's some extra elements to fill in with 0's and 1's) glMultMatrix before drawing the cylinder in system A that should result in having drawn it in system B.
So we start with two coordinate systems A and B which both have X, Y and Z axis.
Code:
/ X_A.x X_A.y X_A.z \
A = ( Y_A.x Y_A.y Y_A.z )
\ Z_A.x Z_A.y Z_A.z /
/ X_B.x X_B.y X_B.z \
B = ( Y_B.x Y_B.y Y_B.z )
\ Z_B.x Z_B.y Z_B.z /
Now we can take any vector u and express it in terms of these coordinate systems.
Code:
u = A u_A = B u_B
What we would like to do is find a matrix M such that M u_a = u_b.
We observe that u_b.x = <u,X_B> ; u_b.y = <u,Y_B> ; u_b.z = <u,Z_B>. Now we can expand u into its component form expressed in terms of A, <u,X_B> = <u_a.x X_A + u_a.y Y_A + u_a.z Z_A , X_B > and use the distributivity of inner product, u_b.x = u_a.x <X_A,X_B> + u_a.y <Y_A,X_B> + u_a.z <Z_A,X_B>. The same process works for u_b.y and .z, these 3 equations look just like the result of a matrix multiplication!
This allows us to conclude,
Code:
/ <X_A,X_B> <Y_A,X_B> <Z_A,X_B> \
M = ( <X_A,Y_B> <Y_A,Y_B> <Z_A,Y_B> )
\ <X_A,Z_B> <Y_A,Z_B> <Z_A,Z_B> /
How does this apply to our situation with the cylinders?
Suppose coordinate system A is just {(1 0 0),(0 1 0),(0 0 1)}, you can already draw cylinder that points straight up in there.
Now coordinate system B would be have its yaxis as your 'delta' vector. Now it's just left to find an x and z axis. You can do this by picking a random axis that isn't y, taking its cross product with y and this gives you a new axis x, do it again to get z. (It doesn't have to be a 'random' but anything which isn't very close to y will do fine)
So that lets you calculate M, and if you plug that into opengl (remember opengl transposes matrices compared to the normal way we write them, and there's some extra elements to fill in with 0's and 1's) glMultMatrix before drawing the cylinder in system A that should result in having drawn it in system B.
Sir, e^iÏ€ + 1 = 0, hence God exists; reply!
Possibly Related Threads...
Thread:  Author  Replies:  Views:  Last Post  
Skewed Vertices with Quaternions, Matrices, and Good Ol' Trig  Oddity007  4  5,481 
May 12, 2009 03:13 PM Last Post: Oddity007 

Is it possible to lerp between to matrices?  TomorrowPlusX  11  10,916 
Nov 25, 2005 01:19 PM Last Post: NicholasFrancis 

Finding Rotational Vectors and Angles  Nick  9  6,773 
Mar 25, 2005 12:14 AM Last Post: tigakub 

Question about angles  stevejohnson  8  6,470 
Apr 3, 2003 05:25 PM Last Post: Dr. Light 