Skinned Animation Problems

Started by
4 comments, last by lmffs 13 years, 7 months ago
I'm currently trying to animate my mesh with skinned animation, but the results are very off. With no animation transformations preformed on the bones, the model is displayed properly, however when it is animated, the whole model becomes erratic. I think my skeleton is correct, so I think there's something wrong with the way I'm animating and transforming the bones.
I've looked through a lot of tutorials and many books but I've really been struggeling with this for a while now. I believe all the data is being loaded correctly and I'm just not using the transformations correctly, but I haven't been able to pinpoint exactly what the problem.
What happens to the model is that I can see vertices moving around and rotating, but the mesh is skewed and not translated properly.
I'm using the data provided by Assimp for the animations, so there might be something I'm not aware of. Here is some of the relevant code.

//code in animationfor(unsigned int i = 0; i < mNumChannels; ++i) //each channel affects a single bone{	chan = &mChannels;	math::Vec3<float> * posVec = &chan->mPositionKeys[0].mVec;	math::Quaternion * quat = &chan->mRotationKeys[0].mQuat;	float scale = chan->mScaleKeys[0].mVec.x; //turn into uniform scaling...	unsigned int j;	for(j = 0; j < chan->mNumPositionKeys; ++j)	{		if(chan->mPositionKeys[j].mTime >= delta){			posVec = &chan->mPositionKeys[j].mVec;			break;		}	}	for(j = 0; j < chan->mNumRotationKeys; ++j)	{		if(chan->mRotationKeys[j].mTime >= delta){			quat = &chan->mRotationKeys[j].mQuat;			break;		}	}	for(j = 0; j < chan->mNumScaleKeys; ++j)	{		if(chan->mScaleKeys[j].mTime >= delta){			scale = chan->mScaleKeys[j].mVec.x;			break;		}	}	SkeletonNode* node = mSkeleton->findNode(chan->mName);	//order of transformation is scaling, rotation, translation.	math::Matrix4x4 trans; //identity matrix	trans.mMatrix[3] = posVec->x;	trans.mMatrix[7] = posVec->y;	trans.mMatrix[11] = posVec->z;	math::Matrix4x4 matscle; //identity matrix	matscle.mMatrix[0] = scale;	matscle.mMatrix[5] = scale;	matscle.mMatrix[10] = scale;			math::Matrix4x4 orient;	quat->toMatrix4x4(orient);	math::Matrix4x4 final;	final = orient * trans; //not using scale for testing	node->updateTransform(final);}mSkeleton->updateBones()


void SkeletonNode::updateTransform(math::Matrix4x4& transform){	mLocalTransform = transform;	return;}


//update bone helper functionvoid Skeleton::updateBonesH(SkeletonNode *node, math::Matrix4x4 transform){	if(!node) return;	node->mGlobalTransform =  transform * node->mLocalTransform;	for(unsigned int i = 0; i < node->mNumChildren; ++i)	{		updateBonesH(&node->mChildren, node->mGlobalTransform);	}	if(node->mBone){		math::Matrix4x4 b = node->mBone->mOffsetMatrix; //inverse bind pos		math::Matrix4x4 c = node->mGlobalTransform; //current pose		math::Matrix4x4 f = b * c;		node->mBone->mFinalMatrix = f;	}}


And here is my vertex shader...

#version 130in vec4 position;in vec4 boneWeightValue;in vec4 boneWeightIndex;uniform mat4 boneMatrices[32];uniform mat4 perspectiveModelViewMatrix;uniform mat4 modelViewMatrix;void main(){		vec4 pos1 = boneWeightValue.x * (boneMatrices[int(boneWeightIndex.x)] * position);	vec4 pos2 = boneWeightValue.y * (boneMatrices[int(boneWeightIndex.y)] * position);	vec4 pos3 = boneWeightValue.z * (boneMatrices[int(boneWeightIndex.z)] * position);	vec4 pos4 = boneWeightValue.w * (boneMatrices[int(boneWeightIndex.w)] * position);	vec4 pos =  pos1 + pos2 + pos3 + pos4;	gl_Position = perspectiveModelViewMatrix * pos;}


The bone matrices seem to be transferred correctly to the shader, since the initial pose, without any animation, is perfectly fine.
I would really appreciate it if anyone has any experience working with Assimp animations, or can help me in understand what I'm doing wrong.

[Edited by - lmffs on August 30, 2010 3:29:15 PM]
Advertisement
Just an idea but I've had similar problems when the joint offsets where not properly aligned. Very weird animation resulted indeed. I can't read your code I'm not a good enough programmer but I would recommend just animating ONE bone and see if altering its offset matrix brings it under control. Assimp may use different axes to your API.

Are you animating in DirectX remember it uses left hand co-ords and the y axis is up - not into the screen.

I'll *try* and read your code and see if there's an issue. I've also got my own format to animate so I am not a total n00b with graphics programming but still very new ;o)

Hope that helps maybe? Out of curiousity does your skin translate in funny ways rather than just static rotation about a specific point (i.e. the joint position)?

**Edit**

I assume you know the procedure for rotation about an arbitrary axis?
Thanks for the reply. I'm using Open GL for rendering, and I'm pretty sure my transformations are using the same axis as Assimp. And yes, parts of my skin rotates and moves very strangely, like the global transformation I'm building for that bone is getting corrupted along the way.

I'll follow your advice and try playing around with the bones directly and see what I can learn.
I'm not sure how your math library works for matrices, and this could be totally incorrect, but it appears you're multiplying matrices in one order in some places and a different order in the shader.
// in your codefinal = orient * trans; //rotation followed by translation

// in your shadergl_Position = perspectiveModelViewMatrix * pos;

You might try reversing the order of matrix multiplication in one or the other of those instances.

As I remember, OpenGL functions multiply matrices in TRS order (translate, rotate, scale) and expects matrices in column-major order (rather than row-major).

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

So speaketh the master. How you read all that code and picked that out I'll never know Buck. Amazing.
Quote:Original post by Buckeye
I'm not sure how your math library works for matrices, and this could be totally incorrect, but it appears you're multiplying matrices in one order in some places and a different order in the shader.
// in your codefinal = orient * trans; //rotation followed by translation

// in your shadergl_Position = perspectiveModelViewMatrix * pos;

You might try reversing the order of matrix multiplication in one or the other of those instances.

As I remember, OpenGL functions multiply matrices in TRS order (translate, rotate, scale) and expects matrices in column-major order (rather than row-major).


I did try switching the order of the transformations many times before to see if I was messing up the order or something but none of them really gave me too much luck.

I completely got the the layout of the matrices wrong.
Quote:
All matrices in the library are row-major. That means that the matrices are stored row by row in memory, which is similar to the OpenGL matrix layout.

Should have double checked this, thank you for pointing this out Buckeye.

My animations are behaving a lot better now, however it seems as if not all the bones are being transformed or the offsets seem to be off a little bit. I wonder if there's something wrong with my skeleton layout or node transformations. I'll do an extensive check on this in a bit.

Thank you for all the help so far.



EDIT:

Okay, I got it all working now. I just had to transpose the rotation matrix, and fix some of the other matrix-layout problems. Thank you for the help guys.

[Edited by - lmffs on August 30, 2010 9:44:44 PM]

This topic is closed to new replies.

Advertisement