🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Animation from scratch, problem with meshes

Started by
1 comment, last by h3ro 3 years, 10 months ago

Hallo,

I am trying to make animations work for my program, but I am running into some problems and as a bit unsure where it goes wrong for me.

Step 1:

I load the skeleton, if I try to render all the bone positions in world space (parent transform applied to children), I get a stick figure in the bind pose, so I think this part is ok.

 for (int i = 0; i < skeleton.Bones.Count(); i++)
                {
                    var x = new Microsoft.Xna.Framework.Quaternion(
                        skeleton.Bones[i].Rotation_X,
                        skeleton.Bones[i].Rotation_Y,
                        skeleton.Bones[i].Rotation_Z,
                        skeleton.Bones[i].Rotation_W);
                    x.Normalize();

                    var pos = Matrix.CreateFromQuaternion(x) * Matrix.CreateTranslation(skeleton.Bones[i].Position_X, skeleton.Bones[i].Position_Y, skeleton.Bones[i].Position_Z);
                    var info = new BoneInfo()
                    {
                        Index = skeleton.Bones[i].Id,
                        ParentIndex = skeleton.Bones[i].ParentId,
                        Position = pos,
                        WorldPosition = pos
                    };
                    model.Bones.Add(info);
                }


                for (int i = 0; i < model.Bones.Count(); i++)
                {
                    if (model.Bones[i].ParentIndex == -1)
                        continue;
                    model.Bones[i].WorldPosition = model.Bones[i].WorldPosition * model.Bones[model.Bones[i].ParentIndex].WorldPosition;
                }

Step 2:
I load the animation file, and do the following:

  • Copy the bind pose bones into my AnimationTransform array. Then I do the following:
  • For each bone that has an animation, replace that bones transformation with the animation information. At this point, we are in local space.
  • Move into world space, but multiplying each child transform by its parent.
  • For each AnimationTransform, multiply it with the inverse bind position for this bone.
Code removed...Updated in later post

If I at this stage apply the animation transform to the skeleton, I get a skeleton that looks like its animated correctly for its frame.

Step 3:

I now try to apply the animationFrames to the mesh, but he mesh ends up looking all messed up.

Code removed...Updated in later post

Since my skeletons are rendering ok I feel fairly certain that the animation transforms are ok, but I am not sure. Any idea where I am messing it up?

Advertisement

I think I am getting closer. The lower body looks ok, but upper body is still very wrong. I think my problem is that I have introduced some scaling somewhere, but I dont know where or how. Any ideas? If I dont apply the animation data to the mesh, then the mesh is the correct size relative to the skeleton.



This is my current animation key frame builder code, does it look correct in terms of matrix transformations?

public static AnimationInformation Create(Animation animation, SkeletonModel skeletonModel)
{
	AnimationInformation model = new AnimationInformation();
	for (int frameIndex = 0; frameIndex < animation.Frames.Count(); frameIndex++)
	{
		var animationKeyFrameData = animation.Frames[frameIndex];
		var currentFrame = new AnimationFrame();
		
		// Copy base pose
		for (int i = 0; i < skeletonModel.Bones.Count(); i++)
		{
			currentFrame.BoneTransforms.Add(new AnimationKeyFrame()
			{
				Transform = (skeletonModel.Bones[i].Position),
				BoneIndex = skeletonModel.Bones[i].Index,
				ParentBoneIndex = skeletonModel.Bones[i].ParentIndex
			});
		}

		// Apply animation translation
		for (int i = 0; i < animationKeyFrameData.Transforms.Count(); i++)
		{
			var index = animation.posIDArr[0][i];
			var pos = animationKeyFrameData.Transforms[i];
			var temp = currentFrame.BoneTransforms[index].Transform;
			temp.Translation = new Vector3(pos.X, pos.Y, pos.Z);
			currentFrame.BoneTransforms[index].Transform = temp;
		}

		// Apply animation rotation
		for (int i = 0; i < animationKeyFrameData.Quaternion.Count(); i++)
		{
			var animQ = animationKeyFrameData.Quaternion[i];
			var q = new Microsoft.Xna.Framework.Quaternion(animQ[0], animQ[1], animQ[2], animQ[3]);
			q.Normalize();

			var mappingIdx = animation.RotationMapping[0][i];
			var translation = currentFrame.BoneTransforms[mappingIdx].Transform.Translation;
			currentFrame.BoneTransforms[mappingIdx].Transform = Matrix.CreateFromQuaternion(q) * Matrix.CreateTranslation(translation);
		}

		// Move into world space
		for (int i = 0; i < currentFrame.BoneTransforms.Count(); i++)
		{
			var parentindex = currentFrame.BoneTransforms[i].ParentBoneIndex;
			if (parentindex == -1)
				continue;

			currentFrame.BoneTransforms[i].Transform = currentFrame.BoneTransforms[i].Transform * currentFrame.BoneTransforms[parentindex].Transform;
		}

		// Mult with inverse bind matrix, in worldspace
		for (int i = 0; i < skeletonModel.Bones.Count(); i++)
		{
			var inv = Matrix.Invert(skeletonModel.Bones[i].WorldPosition);
			currentFrame.BoneTransforms[i].Transform = Matrix.Multiply(inv, currentFrame.BoneTransforms[i].Transform);
		}

		model.Animation.Add(currentFrame);
	}

	return model;
}

This is my mesh builder code:

for (int index = 0; index < lodModel.IndicesBuffer.Length; index++)
{
	var vertIndex = lodModel.IndicesBuffer[index];
	var vertex = lodModel.VertexArray[vertIndex];
	
	var combinesTransformationMatrix = Matrix.Identity;

   foreach (var boneActingOnVertex in vertex.BoneInfos)
   {
	   var boneTransform = currentFrame.BoneTransforms[boneActingOnVertex.BoneIndex];
		var weightedMatrix = boneTransform.Transform * boneActingOnVertex.BoneWeight;
	   combinesTransformationMatrix += weightedMatrix;
   }

	Vector3 animatedVertexPos = Vector3.Transform(new Vector3(vertex.X, vertex.Y, vertex.Z), combinesTransformationMatrix);

	Vector3 normal = new Vector3(vertex.Normal_X, vertex.Normal_Y, vertex.Normal_Z);
	vertices[index] = new VertexPositionNormalTexture(animatedVertexPos, normal, new Vector2(0.0f, 0.0f));
}

This topic is closed to new replies.

Advertisement