I read an article where there were pros and cons for both. FBX is good for later editing and glTF if you just want to render it and / or send the animation over the internet.
How does the animation blending work? Are you blending keyframes of both animations?
I have a current clip, and previous clip.
When I start a clip, if one is already running, that get’s made the prev clip.
While getting the transforms, I get both sets, and blend them.
Simple as that really.
Not used to the terminology in animation what is a clip? The set of keyframes? So you do calculate both animations (interpolation between keyframes) and then interpolating the results again with linear interpolation?
Good to see something happening in this topic / area (animation) in MonoGame.
I played around with animation in XNA but when trying to port it over to MonoGame the content pipeline was lacking some classes and I couldn’t easily figure out how to implement the stuff myself. Maybe I will revisit the animation stuff.
Here is an older video showing some test animation.
Nice
I don’t have my code in front of me, but my clip is the collection of frames, the frames are the bone transforms for each bone for that clip.
So, when transitioning, I lerp based on a blend factor, beween the previous bone and the current bone in the two animation clips.
It will be a post on my Patreon page at some point I have already posted on how I am doing the pipeline extension, it’s based on one I did in my old XNA engine, which, as I say was based on the XNA Skinned mesh sample, only I use it to also pull a lot more data out of the mesh
That’s soft-shadowed right? - looks really good.
I think I might be doing it in very similar way to Charles (?)
Initializer:
idleTransforms = new Matrix[bones_count];
walkTransforms = new Matrix[bones_count];
blendTransforms = new Matrix[bones_count];
// COPY BONE TRANSFORMS
hero[IDLE].CopyAbsoluteBoneTransformsTo(idleTransforms);
hero[WALK].CopyAbsoluteBoneTransformsTo(walkTransforms);
// START AN ANIMATION
AnimationClip idleClip = skinDataIdle.AnimationClips["Take 001"]; // "Take 001"
AnimationClip walkClip = skinDataWalk.AnimationClips["Take 001"];
idleAnimPlayer.StartClip(idleClip);
walkAnimPlayer.StartClip(walkClip);
Update:
playspeed = speed * 6f + 0.8f;
TimeSpan elapsedTime = TimeSpan.FromSeconds(gameTime.ElapsedGameTime.TotalSeconds * playspeed);
idleAnimPlayer.Update(elapsedTime, true, Matrix.Identity);
walkAnimPlayer.Update(elapsedTime, true, Matrix.Identity);
DrawPrep [(3 animations(idle, walk, run) depending on speed]:
// START SKINNEDMESH ANIMATION BLEND
Matrix[] bones1;
Matrix[] bones2;
float percent;
if (speed <= 0.2f) {
bones1 = idleAnimPlayer.GetSkinTransforms();
bones2 = walkAnimPlayer.GetSkinTransforms();
percent = 1f / 0.2f * speed; // first 20%
}
else {
bones1 = walkAnimPlayer.GetSkinTransforms();
bones2 = runAnimPlayer.GetSkinTransforms();
percent = 1f / 0.8f * (speed - 0.2f); // remaining 80%
}
int i = 0;
while (i < bones1.Length) {
blendTransforms[i] = Matrix.Lerp(bones1[i], bones2[i], percent);
i++;
}
Draw :
(this may look slightly different than usual because I’m using a customized version of skinnedEffect - so I extract a few shader/material values out of the default effect settings attached to each mesh):
// RENDER CHARACTER
foreach (ModelMesh mesh in hero[IDLE].Meshes) {
foreach (ModelMeshPart part in mesh.MeshParts) {
SkinnedEffect oldEffect = (SkinnedEffect)part.Effect;
heroFX.alpha = oldEffect.Alpha;
if (heroFX.alpha < 0.6f) continue;
heroFX.preferPerPixelLighting = true;
heroFX.SetDiffuseCol(Color.White.ToVector4());
heroFX.SetSpecularCol(new Vector3(0.2f, 0.3f, 0.05f));
heroFX.SetSpecularPow(256);
heroFX.SetBoneTransforms(blendTransforms);
heroFX.world = mtx_hero_rotate * Matrix.CreateTranslation(hero_pos);
heroFX.SetDrawParams(cam, oldEffect.Texture);
gpu.SetVertexBuffer(part.VertexBuffer);
gpu.Indices = part.IndexBuffer;
gpu.DrawIndexedPrimitives(PrimitiveType.TriangleList, part.VertexOffset, part.StartIndex, part.PrimitiveCount);
}
}
Similar yes, in principle, that is what I am doing
Thank you. Yes, I had soft shadows on for a point light in this case if I remember right. Maybe I can record newer videos when I revisit the project sometime.