Archived

This topic is now archived and is closed to further replies.

Don't understand why inverse is used

This topic is 5045 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

This is some code from rsn.gamedev.net. The code initializes the joints of the milkshape3d model. However, I do not understand why the verts must be inverserotated/translated.
void Model::setupJoints()
{
	int i;
	for ( i = 0; i < m_numJoints; i++ )
	{
		Joint& joint = m_pJoints[i];
		joint.m_relative.setRotationRadians( joint.m_localRotation );
		joint.m_relative.setTranslation( joint.m_localTranslation );
		if ( joint.m_parent != -1 )
		{
			joint.m_absolute.set( m_pJoints[joint.m_parent].m_absolute.getMatrix());
			joint.m_absolute.postMultiply( joint.m_relative );
		}
		else
			joint.m_absolute.set( joint.m_relative.getMatrix());
	}

	for ( i = 0; i < m_numVertices; i++ )
	{
		
		Vertex& vertex = m_pVertices[i];
		
		if ( vertex.m_boneID != -1 )
		{
			const Matrix& matrix = m_pJoints[vertex.m_boneID].m_absolute;

			matrix.inverseTranslateVect( vertex.m_location );
			matrix.inverseRotateVect( vertex.m_location );
		}
	}

	for ( i = 0; i < m_numTriangles; i++ ) 
	{
		Triangle& triangle = m_pTriangles[i];
		for ( int j = 0; j < 3; j++ ) {
			const Vertex& vertex = m_pVertices[triangle.m_vertexIndices[j]];
			if ( vertex.m_boneID != -1 ) {
				const Matrix& matrix = m_pJoints[vertex.m_boneID].m_absolute;
				matrix.inverseRotateVect( triangle.m_vertexNormals[j] );
			}
		}
	}
}

Share this post


Link to post
Share on other sites
It''s important to understand that a model, in its "binding position" (usually with the arms straight out and the legs straight and slightly apart), the model still has a position. The joints have a certain translation and rotation relative to each other. If an additional pose were to be applied on top of that, the guy''s limbs would fly everywhere. So what you do is first you "undo" the binding pose and then put on the target pose. If you wanted, you could then put him into a new target pose by applying the inverse of the first target pose and then applying the second target pose; but this would never actually be done.


"Sneftel is correct, if rather vulgar." --Flarelocke

Share this post


Link to post
Share on other sites
I discuss this same issue in a thread at http://gamedev.net/community/forums/topic.asp?topic_id=205357

The issue is that your verts are originally in model space in base pose. You need to put them into animated model space. So you need to transform a vertex from base-pose to bone space, then apply the animation (which is a bone-space to model-space transform). The problem with the method you''re presenting (where verts are immediately transformed into bone-space) is that only one bone can affect a vertex.

Much better is to store the inverse transform of the base pose bone, and concatenate that to the animated bone transform every frame and use the result as the bone matrix. The effect is that you can do vertex-weighting on multiple bones at the expense of a matrix-vector multiply per weight per vertex (which can be done in a shader).

Share this post


Link to post
Share on other sites
When you 'inverserotate' a point based on angles, is it true you can either
A) multiply by the transpose of the matrix (assuming the matrix is just a pure rotation matrix and it is orthogonal, so it becomes the same as its inverse)

or

B) just negate the angles, rebuild the rotation matrix, and then transform the vertex normally.

I cannot seem to get B working. I'm new to skeletal animation and I need to understand every aspect of how the matrix mathematics works. Thanks.

EDIT: I'm still just having an incredibly difficult time understanding exactly what the code does, in the sense that I understand exactly what you guys said, but it doesn't seem represented in the code and the results of the program. For instance, if I do not even call the function above which supposedly initializes the vertes into animation model space, it looks identical to when I did call the function. Either the base pose looks identical to the start frame, or there is something I am missing. My understanding of the above code is this:

Go through each joint. If it has a parent, concatenate the parent's absolute matrix with the local transform of the joint.

Second loop, if it has a parent, inverse transform each of the verts to get the 'animation model space'

The problem is none of this seems very intuitive to me. The way the code is laid out, it seems that the transform to get from the base pose to the start frame is equivalent to the start frame of the object. However, when I don't inverse rotate the verts and then advance the animation, it screws up.

[edited by - Shadow12345 on February 20, 2004 1:43:30 PM]

[edited by - Shadow12345 on February 20, 2004 1:45:40 PM]

Share this post


Link to post
Share on other sites
I don''t like bumping, but this has been a particularly troublesome problem, so I guess I need to refine my questions. Does anybody know exactly what this code does, other than the fact that it initializes the rotation part of the matrix? This is from the now dead rsn.gamedev.net website. The reason I am asking what this does is I''ve commented out my own matrix mathematics stuff that I tried, and does not work with his tutorial code. However, all of my matrix stuff works perfectly for my own programs (I''ve used them very extensively). My matrix stuff is for the right handed OpenGL coordinate system (y is up, negative z axis goes into the screen, positive x axis goes off to the right). Is it possible that this code initializes rotations for a different coordinate system?


void Matrix::setRotationRadians( const float *angles )
{
// Matrix a,b,c;

// a.InitFromXRadians(angles[0]);

// b.InitFromYRadians(angles[1]);

// c.InitFromZRadians(angles[2]);

// Matrix final;

// final = Multiply(&Multiply(&b,&a),&c);

// set(final.getMatrix());

float cx = cosf( angles[0] ); //r

float sx = sinf( angles[0] );

float cy = cosf( angles[1] ); //p

float sy = sinf( angles[1] );

float cz = cosf( angles[2] ); //y

float sz = sinf( angles[2] );

m_matrix[0] = ( cy*cz );
m_matrix[1] = ( cy*sz );
m_matrix[2] = ( -sy );

float sxsy = sx*sy;
float cxsy = cx*sy;

m_matrix[4] = ( sxsy*cz-cx*sz );
m_matrix[5] = ( sxsy*sz+cx*cz );
m_matrix[6] = ( sx*cy );

m_matrix[8] = ( cxsy*cz+sx*sz );
m_matrix[9] = ( cxsy*sz-sx*cz );
m_matrix[10] =( cx*cy );
}



One last thing. When they concatenate matrices to get the base pose, I wrote the matrices to a file. Subsequently, the matrix in my own program, and the one in the tutorial are very very close, but not exactly the same. They differ by small decimals, or by sign (one is positive but the other will be negative). For example, here is one such matrix demonstrating this problem:

My matrix:
quote:

0.0260348
-0.99943
-0.0214713
0
0.00261508
-0.0214104
0.999767
0
-0.999658
-0.0260849
0.00205617
0
3.9471
39.5261
-0.368168
1



The tutorial''s matrix:

quote:

-0.026085
-0.999429
0.0214634
0
-0.00205041
0.0215242
0.999766
0
-0.999658
0.0260349
-0.0026107
0
3.9471
39.5261
-0.368168
1



As I said, if the entries are different, then they differ by a small decimal, or their sign. I am perplexed, and if I don''t figure out what is going on I''m just going to drop this because I don''t want to just directly cut and paste the tutorial''s code
.

Share this post


Link to post
Share on other sites
I would very much suspect that if you switch around the order of multiplies when you compose your "final" matrix, you will get the same result as in the tutorial.

So, try
final = Multiply(&Multiply(&a,&b),&c);

or
final = Multiply(&Multiply(&a,&c),&b);
...
some permutation should get you both in tune. Order of multiplies is important, and there''s no real standard for which one is correct.

Share this post


Link to post
Share on other sites