Jump to content
  • Advertisement
Sign in to follow this  
Paul C Skertich

I love assimp but the animation part is a pain - anyone got it working with DirectX?

This topic is 1204 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

as I said I love assimp - it's a great utility but the animation is a pain. So far my animation is stretched out but plays fine in assimp viewer. I looked at assimp viewer and it's hard to follow because I can't find any header files containing some of the functions. Like one function uses a vector and a boost:tuple for storing the position keys, rotation keys, and scaling keys of the animation. Also the code animation part runs on CPU - the ATSPACE.CO.UK runs on GPU and that's where my code came from.

 

I narrowed it down it's due to the global transformation. the offset transform is fine, the parentnode matrix is fine the nodetransform is fine but the globaltransform martrix going into finaltransformation to be sent to gpu is messing things up.

 

I quickly grabbed ieDoc's MD5 Animation loader and the dancing pill works - just a pill shape mesh dancing back and forth then side to side. I don't like MD5 mesh model because I tried to make a simple vehicle and it only imported just the front chassis of the vehicle not the wheels unlike unreal engine or unity could do.

 

Ah the frustrations!

Share this post


Link to post
Share on other sites
Advertisement


I narrowed it down it's due to the global transformation. ... messing things up

 

Sounds like you're almost there. What global transformation do you have, and what transformation should you have? You should be able to compare the two, and, at least, determine if it's a scale problem, or orientation about the wrong axis (or axes), etc.

 

If you set the global to the identity matrix, how do things look? I.e., is the animation correct, but the mesh isn't oriented correctly? Is the scaling correct?

Share this post


Link to post
Share on other sites

Are you converting the Assimp matrices so that they are in the DirectX row-column orientation?  I can never remember which way is which, but I do recall that the matrices which Assimp loaded needed to be transposed before using them in my DirectX animation code.

 

If another example would be helpful, I wrote up how I did it, with using SlimDX and Assimp.net.  It may not be totally correct - I've got some reports of meshes that are a little weird from some people - but I think I worked out most of it.

Share this post


Link to post
Share on other sites

 


I narrowed it down it's due to the global transformation. ... messing things up

 

Sounds like you're almost there. What global transformation do you have, and what transformation should you have? You should be able to compare the two, and, at least, determine if it's a scale problem, or orientation about the wrong axis (or axes), etc.

 

If you set the global to the identity matrix, how do things look? I.e., is the animation correct, but the mesh isn't oriented correctly? Is the scaling correct?

 

What's weird when going through the debugger - the Z Scale wasn't at 1.0 it was 0.99 or something.  I stepped through over and over again - I'm not sure if this is normal but it seems the globalTransformation is multipled each runthrough.


void SkeletalMesh::readAnimationNode(float animationTime, const aiNode *pNode, XMMATRIX &ParentTransform) {

	std::string NodeName = pNode->mName.data;
	const aiAnimation* pAnimation = scene->mAnimations[0];
	XMMATRIX NodeTransformation;

	ConvertUtil::aiMatrix4x4ToXMMatrix(&pNode->mTransformation, &NodeTransformation);
	const aiNodeAnim* pNodeAnim = FindNodeAnim(pAnimation, NodeName);

	if (pNodeAnim) {
		// Interpolate scaling and generate scaling transformation matrix
		aiVector3D Scaling;
		CalcInterpolatedScaling(Scaling, animationTime, pNodeAnim);
		XMMATRIX ScalingM;
		ScalingM = XMMatrixScaling(Scaling.x, Scaling.y, Scaling.z);

		// Interpolate rotation and generate rotation transformation matrix
		aiQuaternion RotationQ;
		CalcInterpolatedRotation(RotationQ, animationTime, pNodeAnim);
		XMMATRIX RotationM;
		ConvertUtil::aiMatrix3x3ToXMMatrix(&RotationQ.GetMatrix(), &RotationM);


		// Interpolate translation and generate translation transformation matrix
		aiVector3D Translation;
		CalcInterpolatedPosition(Translation, animationTime, pNodeAnim);
		XMMATRIX TranslationM;
		TranslationM = XMMatrixTranslation(Translation.x, Translation.y, Translation.z);

		// Combine the above transformations
		NodeTransformation = TranslationM * RotationM * ScalingM; 

	}

	XMMATRIX GlobalTransformation =  ParentTransform *  NodeTransformation; //-- this is where everything gets funky.
	
	if (m_Bonemapping.find(NodeName) != m_Bonemapping.end()) {
		UINT BoneIndex = m_Bonemapping[NodeName];
		XMMATRIX offset = m_BoneInfo[BoneIndex].boneOffset;
		XMMATRIX worldinv = XMLoadFloat4x4(&worldInverse);

		m_BoneInfo[BoneIndex].finalTransform = worldinv * GlobalTransformation * m_BoneInfo[BoneIndex].boneOffset; 
	}

	for (UINT i = 0; i < pNode->mNumChildren; i++) {
		readAnimationNode(animationTime, pNode->mChildren[i], GlobalTransformation);
	}
}

void SkeletalMesh::EvaluateAnimation(float animationtime, std::vector<XMMATRIX> & transforms) {
	
	XMMATRIX Identity =  XMMatrixIdentity();
	float TicksPerSecond = (float)(scene->mAnimations[0]->mTicksPerSecond !=0.0f ? scene->mAnimations[0]->mTicksPerSecond : 25.0f);

	animationtime *= TicksPerSecond;
	float animationTick = fmod(animationtime, (float)scene->mAnimations[0]->mDuration);

	readAnimationNode(animationTick, scene->mRootNode, Identity);
	transforms.resize(numBones);

	for (unsigned int i = 0; i < numBones; i++) {
		transforms[i] = XMMatrixIdentity(); //-- maybe bad idea - original idea was to flatten then transpose it.
		transforms[i] = m_BoneInfo[i].finalTransform;
	}
}

If anyone was asking what was worldInv matrix inside the m_boneInfo[x].finalTransformation - it's when the model gets loaded it gets tranposed into a Float4x4.

 

The whole skeletal reading I got from this :

http://ogldev.atspace.co.uk/www/tutorial38/tutorial38.html

 

I looked at some others and even the assimp_viewer when you build assimp - i can't find the header files inside VStudio project files. It was in pieces and I kept on looking over it and over it.

 

Maybe if I get around to it - I'll send the data to CPU than GPU and see how it does. IF it goes through the CPU without no problem then I will definately know the globaltransform is to blame.

 

Another thing to mention while debugging - the global transform gave me some weird floating points like 5.484884e-05 for instance in one of the rows; i'm not entirely sure what the whole e-05 bit i'm guessing it's exponent -5?  All I know is I never saw that before.  Another to mention is I'm transposed before going to shader inside render loop.

 

The shader code inside the vertex shader:

float4 weights = input.boneWeight;
	float4 boneID = input.boneID;
	
	input.position.w = 1.0f;
	float4x4 animationmat = gBones[boneID.x] * weights.x;
			 animationmat +=   gBones[boneID.y] * weights.y;
			 animationmat +=   gBones[boneID.z] * weights.z;
			 animationmat +=   gBones[boneID.w] * weights.w;
						   
	float4 localPos = mul(input.position,mWorld);
	float4x4 viewProj = mul(mView, mProj);
	output.position = mul(float4(localPos.xyz,1.0f), viewProj);
	output.position = mul(output.position, animationmat);
	

There's only three bones or four - can't remember but gBones is configured to allow 100 bones. Which the gBones get fed into by m_boneInfo[x].finalTransform.

 

the input element description for the bonesID and boneweights are (BoneID : DXGI_FORMAT_R32G32B32_FLOAT; BoneWeight: DXGI_FORMAT_R32G32B32_FLOAT).

 

I just wanted to fill out possibly all what could be raising issue.

Share this post


Link to post
Share on other sites

Trying to help you out here - but you didn't respond to questions asked. However, from the wall of code you did post in response, and your comments indicating a lot of confusion, it appears you need to take one thing at a time. You may want to take a look at this debugging method to help your focus. Don't use a shotgun approach, posting bunches of stuff to "to fill out possibly all what could be raising issue." You need to determine where the problem may lie, and that will require you to understand what data you should have, and what the code should do with it.

 

Take a breath, and, as suggested in the debugging link, start at one point in your code. Determine if both the data and the code at that point are correct. Continue slowly, one step at a time, until, at a minimum, you can post something (brief) like "At this point in my code, I have such-and-such data." Then ask a specific question about the code and/or the data that you don't understand.

 

EDIT: FYI, the link you posted about "skeletal reading" is an OpenGL tutorial. You have to be careful and ensure you understand the differences between implementations in OGL and DirectX - things like column- versus row-major matrices, etc.

Edited by Buckeye

Share this post


Link to post
Share on other sites

Trying to help you out here - but you didn't respond to questions asked. However, from the wall of code you did post in response, and your comments indicating a lot of confusion, it appears you need to take one thing at a time. You may want to take a look at this debugging method to help your focus. Don't use a shotgun approach, posting bunches of stuff to "to fill out possibly all what could be raising issue." You need to determine where the problem may lie, and that will require you to understand what data you should have, and what the code should do with it.

 

Take a breath, and, as suggested in the debugging link, start at one point in your code. Determine if both the data and the code at that point are correct. Continue slowly, one step at a time, until, at a minimum, you can post something (brief) like "At this point in my code, I have such-and-such data." Then ask a specific question about the code and/or the data that you don't understand.

 

EDIT: FYI, the link you posted about "skeletal reading" is an OpenGL tutorial. You have to be careful and ensure you understand the differences between implementations in OGL and DirectX - things like column- versus row-major matrices, etc.

I understand openGL and DirectX run things differently - so I can understand translating openGL to DX will be a challenge to some extent. I don't know how to validate if the matrixes I'm looking at are valid because I don't have a working one to validate with. I went through the debugging process but the matrices are confusing.  So from telling apart from the matrices I'm unable to understand at all what the matrices are suppose to mean - what is correct vs what is not.

Share this post


Link to post
Share on other sites


I don't have a working one to validate with.

 

You said the file you're using (unspecified) works in the assimp viewer, so you do have a model that "works." If you're recoding OGL to DirectX 11, you're definitely going to need known data to test your code, as, at this point, it appears you may be writing code you're not sure of, and hoping it works with data you don't understand. Not a good thing.

 

Others may have better suggestions, but writing code without being able to test it is definitely not the way to go.

 

1. Use a very basic model, perhaps something with just 1 or 2 bones, with a very simple animation, perhaps just 1 or 2 frames of simple rotation. That may require working with a modeling program, such as Blender. Export it in a format that Assimp accepts, and which you can examine in text format. I.e., look at the matrices in the file and see if that's what you import.

 

2. google for something like "directx 11 animation example" and find code that is likely to work (rather than writing your own).

 

Just my opinion, but debugging code without a way to tell if the code is good or bad, with data that you don't know is good or bad ... futile.

Share this post


Link to post
Share on other sites

 


I don't have a working one to validate with.

 

You said the file you're using (unspecified) works in the assimp viewer, so you do have a model that "works." If you're recoding OGL to DirectX 11, you're definitely going to need known data to test your code, as, at this point, it appears you may be writing code you're not sure of, and hoping it works with data you don't understand. Not a good thing.

 

Others may have better suggestions, but writing code without being able to test it is definitely not the way to go.

 

1. Use a very basic model, perhaps something with just 1 or 2 bones, with a very simple animation, perhaps just 1 or 2 frames of simple rotation. That may require working with a modeling program, such as Blender. Export it in a format that Assimp accepts, and which you can examine in text format. I.e., look at the matrices in the file and see if that's what you import.

 

2. google for something like "directx 11 animation example" and find code that is likely to work (rather than writing your own).

 

Just my opinion, but debugging code without a way to tell if the code is good or bad, with data that you don't know is good or bad ... futile.

 

The assimp viewer program plays back the animation perfectly - so I know it's my app that's messing it up. You're right on that. I'll be exporting the offset transformations from the assimp imported animation to txt file then comparing the two.Also will be explorting global transformation, parent transformation and offset matrices as well.

 

The dancing pill only has three bones I believe that just goes side to side then back to front. That's as simple as it gets actually inside 3DS Max. I'll keep you posted.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!