Angles and Matrices and Whatnot

Member
Posts: 40
Joined: 2008.10
Post: #1
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):
Code:
            Vector delta = joints[1].pos-joints[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();
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.
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #2
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:
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 y-z 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 x-y 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.
Quote this message in a reply
Sage
Posts: 1,403
Joined: 2005.07
Post: #3
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!
Quote this message in a reply
Member
Posts: 40
Joined: 2008.10
Post: #4
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!
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #5
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 )
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.
Quote this message in a reply
Sage
Posts: 1,403
Joined: 2005.07
Post: #6
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.

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 y-axis 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!
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Skewed Vertices with Quaternions, Matrices, and Good Ol' Trig Oddity007 4 3,681 May 12, 2009 03:13 PM
Last Post: Oddity007
  Is it possible to lerp between to matrices? TomorrowPlusX 11 5,827 Nov 25, 2005 01:19 PM
Last Post: NicholasFrancis
  Finding Rotational Vectors and Angles Nick 9 4,805 Mar 25, 2005 12:14 AM
Last Post: tigakub
  Question about angles stevejohnson 8 4,445 Apr 3, 2003 05:25 PM
Last Post: Dr. Light