What is this post about?
Our artists want to know how they are supposed to skin the characters (setup a skeleton and assign the vertices of the mesh to one or more bones) so we can do what we want to do without running into problems. Despite being very new to Ogre I have to answer that question now...
So let me explain a bit about what we want and how I think it could be achieved in Ogre. If we take a wrong approach now it's probably hard to fix without losing a lot of work.
What we want...
Imagine a character walking. The way he moves his feet kinda defines how the characters world position needs to be adapted. And its not a constant movement. When a feet touches the ground there's friction, so the relative position between feet and ground has to remain the same. Mess up with that and the feet end up sliding.
So you can't just loop a walking animation and move the character linearly. Instead the information about how the characters world position and orientation changes has to be derived from the animation data. But as far as I've seen it the skeleton file format used by Ogre doesn't include such informations.
This becomes even more complex when you need to blend multiple animations. Like running, walking and turning animations. What we want is a system where we can arbitrary combine various skeletal animations that may or may not loop and where it's possible to change the animation weights at runtime. And based on the combination of active animations the characters world position and orientation has to be updated correctly.
How I'd do it...
My approach would be to encode character movement in the characters root bone. Let's say the characters hip would be his skeletons root. I'd add another bone to the hirarchy that might start at the ground level and connects to the characters hip. Animate the characters walk animation or whatever and then move this root bone (like the handle of a stick puppet) so the feet remain in place when they touch the ground.
Now the animators can control how the characters move in the world. When the animation loops however the character would jump to it's initial position. This is where my animation system needs to kick in and adapt the scene node so the characters position and orientation in world space remains unchanged.
All this needs to support multiple blended animations and it may not result in any noticable performance hit. Whenever one of the blended animations loops, is removed or gets it's weight changed by a noticable amount I need to detect the resulting "disruption" that would happen and counter it by adapting the scene nodes position and orientation.
How to implement it...
Each character may have multiple frame listener objects responsible for one or more active AnimationStates. The AnimationState can be advanced using the following code:
Code: Select all
float overlap = pAnimState->getTimePosition() + timeDelta - pAnimState->getLength();
if (overlap >= 0)
{
pAnimState->setTimePosition(pAnimState->getLength());
m_pPuppet->StoreSpatialState();
pAnimState->setTimePosition(0);
m_pPuppet->RestoreSpatialState();
pAnimState->setTimePosition(overlap);
}
else
pAnimState->addTime(timeDelta);
It's StoreSpatialState could work like this:
Code: Select all
//update the skelleton
m_pEntity->getSkeleton()->setAnimationState(*m_pEntity->getAllAnimationStates());
//read infos from the root bone
m_StoredOrientation = m_pRootBone->getOrientation();
m_StoredPosition = m_pSceneNode->getOrientation() * m_pRootBone->getPosition();
Code: Select all
//update the skeleton
m_pEntity->getSkeleton()->setAnimationState(*m_pEntity->getAllAnimationStates());
//revert the change
Quaternion newOrientation = m_pSceneNode->getOrientation() * m_StoredOrientation * m_pRootBone->getOrientation().Inverse();
m_pSceneNode->setOrientation(newOrientation);
Vector3 newPosition = m_pSceneNode->getPosition() + m_StoredPosition - m_pSceneNode->getOrientation() * m_pRootBone->getPosition();
m_pSceneNode->setPosition(newPosition);
/edit: some clarifications