Archived

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

nyStagmus

Problem with ms3d skeletal animation and D3D8

Recommended Posts

nyStagmus    122
I have been trying to make an implementation of Brett Porters skeletal animation in Direct3D. The problem is that somehow I get the wrong transformation matrices from the keyframes. Here is some code to demonstrate how I have done:
      

// First I create all the relative and absolute matrices of the joints/bones just like Brett do

// Please note that the rotations are in the same order as Brett''s

for (i = 0; i < jointCount; i++)
{
	D3DXMATRIX temp;
	D3DXMatrixRotationZ(&joints[i].relative, joints[i].rotation[2]);
	D3DXMatrixRotationY(&temp, joints[i].rotation[1]);
	D3DXMatrixMultiply(&joints[i].relative, &joints[i].relative, &temp);
	D3DXMatrixRotationX(&temp, joints[i].rotation[0]);
	D3DXMatrixMultiply(&joints[i].relative, &joints[i].relative, &temp);

	D3DXMatrixTranslation(&temp, joints[i].position[0], joints[i].position[1], joints[i].position[2]);
	D3DXMatrixMultiply(&joints[i].relative, &joints[i].relative, &temp);

	D3DXMatrixInverse(&joints[i].relative, Null, &joints[i].relative);

	if (joints[i].parentJoint != (Word)-1)
	{
		D3DXMatrixMultiply(&joints[i].absolute, &joints[joints[i].parentJoint].absolute, &joints[i].relative);
	}
	else
		joints[i].absolute = joints[i].relative;

	joints[i].final = joints[i].absolute;
}

// Then I transform all the vertices with the inverse of the absolute matrix

// The normals of the vertices are also transformed and normalized

for (i = 0; i < vertexCount; i++)
{
	if (vertices[i].boneIndex != (Word)-1)
	{
		D3DXMatrixInverse(&invTrans, Null, &joints[vertices[i].boneIndex].absolute);
		D3DXVec3Transform(&trans, &vertices[i].position, &invTrans);			
		vertices[i].position.x = trans.x;
		vertices[i].position.y = trans.y;
		vertices[i].position.z = trans.z;

		D3DXVec3Transform(&trans, &vertices[i].normal, &invTrans);
		vertices[i].normal.x = trans.x;
		vertices[i].normal.y = trans.y;
		vertices[i].normal.z = trans.z;
		D3DXVec3Normalize(&vertices[i].normal, &vertices[i].normal);
	}
}


for (i = 0; i < jointCount; i++)
{
        // I have left out some code here that fills rotVec and transVec (of the type D3DXVECTOR3).

//I am pretty confident that the fault lies somewhere else as it is 

//pretty straight-forward


	D3DXMatrixRotationZ(&transform, rotVec.z);
	D3DXMatrixRotationY(&temp, rotVec.y);
	D3DXMatrixMultiply(&transform, &transform, &temp);
	D3DXMatrixRotationX(&temp, rotVec.x);
	D3DXMatrixMultiply(&transform, &transform, &temp);

	D3DXMatrixTranslation(&temp, transVec.x, transVec.y, transVec.z);
	D3DXMatrixMultiply(&transform, &transform, &temp);

	D3DXMatrixMultiply(&final, &joint.relative, &transform);

	if (joint.parentJoint == (Word) -1)
	{
		joint.final = final;
	}
	else
	{
		D3DXMatrixMultiply(&joint.final, &joints[ joint.parentJoint ].final, &final);
	}	
}


// Lastly I have a vertexbuffer that I fill with the retransformed vertices

// Note that DRUVertexD3D is just a custom FVF-vertex

for (j = 0; j < groups[i].vertexCount; j++)
{
	const Dword & idx = groups[i].indexBuffer[j];
			
	if (vertices[ idx ].boneIndex != (Word) -1)
	{
		const D3DXMATRIX & mat = joints[ vertices[idx].boneIndex ].final;

		DRUVertexD3D & vert = vertex[j];
					
		D3DXVec3Transform(&vec, &vertices[ idx ].position, &mat);
		vert.x = vec.x;
		vert.y = vec.y;
		vert.z = vec.z;

		D3DXVec3Transform(&vec, &vertices[idx].normal, &mat);
					
		vert.nX = vec.x;
		vert.nY = vec.y;
		vert.nZ = vec.z;
				
	}
}
    
These are snippets from the code that perform the various tasks. I am not that good at matrix math, so I think that the problem probably lies in that area... I would be immensely grateful for help as I''ve been tearing my hair for about a week now. And I''m running out.... :-)

Share this post


Link to post
Share on other sites
nyStagmus    122
Yes, sorry. I should have been more specific. What happens is that the model I am using, incidentally the same as in your tutorial , gets "weird". I.e. it is sort of morphing into strange shapes. The first frame I show, one in which I don''t use the keyframes, only the absolute matrices I calculated, displays fine. The trouble is when I calculate a final matrix for each joint from the keyframes. Then the model just seems to take on all kinds of strange shapes. However, the strange shapes do actually move pretty smooth, so it doesn''t seem like it is random movement...
I hope this clarifies my problem a little more.

Share this post


Link to post
Share on other sites
brettporter    122
Right. That being the case, I think you will be best suited to just carefully going over the functions in each different one and checking the difference. It may even be in the Milkshape loading if you have modified/rewritten that.

Then rendering part of the tutorial is quite small, and the math is abstracted, so I shouldn''t think it''d be too much in the conversion to D3D that is a problem.

But I''ve never* worked with D3D before.

(* I wrote a D3D8 implementation of PortaLib 3D some time back, before it got a lot of its features. There were a couple of bugs and I didn''t fancy maintaining it in parallel or abstracting the library at all, so I went GL only. I''m happy with that

~~~
Cheers!
Brett Porter
PortaLib3D : A portable 3D game/demo libary for OpenGL
Community Service Announcement: Read How to ask questions the smart way before posting!

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Just thought of something while at work..

In your code you have

a_matrix.set(some_matrix.get());
a_matrix.posMultiply(som_other_matrix);

Is that

(1) a_matrix = some_matrix * some_other_matrix;
or
(2) a_matrix = some_other_matrix * some_matrix;

What I was thinking was really that to get the order of multiplications right for the bones it should be opt 2. That way it would first rotate in its local space and then rotate with its parent. All in each frame. I am here referring to the final matrices in the UpdateAnimation function.

I am sorry if this is a bit incoherent but I just thought this up, although I think that I have tried turning all the multiplications around without it working.

Oh I wish that I had all my code here with me so I could try it. Thankfully I am going home soon...

/nystagmus

Yet another mumbo-jumbo-garbled production

Share this post


Link to post
Share on other sites
nyStagmus    122
Just thought of something while at work..

In your code you have

a_matrix.set(some_matrix.get());
a_matrix.posMultiply(som_other_matrix);

Is that

(1) a_matrix = some_matrix * some_other_matrix;
or
(2) a_matrix = some_other_matrix * some_matrix;

What I was thinking was really that to get the order of multiplications right for the bones it should be opt 2. That way it would first rotate in its local space and then rotate with its parent. All in each frame. I am here referring to the final matrices in the UpdateAnimation function.

I am sorry if this is a bit incoherent but I just thought this up, although I think that I have tried turning all the multiplications around without it working.

Oh I wish that I had all my code here with me so I could try it. Thankfully I am going home soon...

/nystagmus

Yet another mumbo-jumbo-garbled production

Share this post


Link to post
Share on other sites
nyStagmus    122
Hah!

I solved it now. I just changed the order of multiplication in Setup bones (absolute = relative * parent.absolute) and in AdvanceAnimation (final = relativeFinal * parent.final).

Thank you for all your help. It really is a great tutorial!

nystagmus

Share this post


Link to post
Share on other sites
nyStagmus    122
Oh, yeah. One note about the advanceanimation function. I believe that in your tutorial source you commented out the quaternion code and used the normal interpolation instead. I believe that you have to make sure that the interpolation value must be positive. Or am I mistaken. I kept getting weird rotation artifacts until I changed to quaternions.

Share this post


Link to post
Share on other sites