Exploring 3D animation further

Congratulations! You're now able to render fully animated 3D models! While this is a pretty cool achievement, the functionality we've seen so far has only scratched the surface of what the IwAnim API allows us to do. The following sections describe some of the other features that we have at our disposal.

Playing an animation backwards

There are some occasions when it is useful to be able to play an animation backwards. As an example, imagine a character kneeling down to examine an object. Rather than create a whole new animation to enable them to stand up again, we could just play the kneeling animation backwards instead.

Playing an animation backwards is achieved simply by passing a negative animation speed into the call to PlayAnim, so a value of -1 will play the animation backwards at normal speed.

Blending between animations

When transitioning between two animations, we often don't want to just snap straight to the beginning of the new sequence, as this can result in a noticeable jump between the current frame of animation and the first frame of the new animation. We can solve this problem by blending between animations.

We touched on how to achieve this earlier, when we first introduced the PlayAnim method. The final parameter in this method is the blending time, which is specified as a value in seconds using a floating point number.

By specifying a non-zero blending interval, the animation player will calculate the frames of animation required for both the old and new animations, then generate a third transition frame by interpolating between these two frames over the specified time. The transition frame is what is then used to draw the 3D model. Once the blend interval is over, the original animation will stop being calculated as it is no longer required.

Detecting animation playback events

Being able to detect when an animation has looped or has finished playing is important because we can start to link animations together or prevent the user from performing a task until an animation has completed. For instance, imagine a player has to reload a weapon and an animation is played to show this happening. We need to know when the animation has completed so we can allow the player to start attacking again.

The CIwAnimPlayer class allows us to detect when a one shot animation has completed, by calling the IsCurrentAnimComplete method that will return true when the animation has finished.

There is also the IsCurrentBlendComplete method that will return true when the animation player has finished blending between two animations.

Detecting when an animation has looped is also possible, although CIwAnimPlayer does not provide us with a quick shortcut way of detecting this event. Instead, we have to do a little manual flag testing.

At any time, the animation player can be updating two main animations: current animation (defined as the animation that was last specified using the PlayAnim method) and the previous animation (the one that was playing at the time PlayAnim was last called with a blending interval).

The current status of these two animations are stored in instances of the CIwAnimBlendSource class, which we can access using the CIwAnimPlayer class' methods named GetSourceCurr and GetSourcePrev. The CIwAnimBlendSource class has a method called GetFlags that returns playback status information as a bitmask. To detect if the animation has looped, we just need to see if the flag CIwAnimBlendSource::LOOPED_F is set. The following source code shows this in action:

if (lpAnimPlayer->GetSourceCurr()->GetFlags() &
                      CIwAnimBlendSource::LOOPED_F)
{
  // Animation has looped!
}

If you prefer this approach, you can also use the flag CIwAnimBlendSource::COMPLETE_F to detect when a single shot animation has finished.

Optimizing animation playback

Do you remember that we calculated the current animation frame by calling the Update method of CIwAnimPlayer? This method has to do quite a lot of work, some of which we might not actually need to do on a frame-by-frame basis. For example, if an in-game character is currently not visible on the screen, we might want to ensure that we still step through its animation; but calculating the bone positions for the current frame of animation is a waste of processor time as we won't be rendering the animation.

The Update method is actually implemented by calling three other methods of CIwAnimPlayer, which we can call independently if we so wish.

The first method is UpdateParameters, which takes the time increment we need to update the animation by as its sole parameter. This method will update the current time indexes of all the animations currently in use by the animation player and set flags to indicate whether those animations have completed or looped.

The UpdateSources method takes no parameters and is used to work out the current bone orientations for each animation, applying any blending between animations as required.

Finally there is the UpdateMatrices method, which again takes no parameters. This performs the final step of converting all the positions and orientations of each bone into a matrix that will be used to update the vertex stream of the 3D model during rendering.

These methods need to be called in the order presented previously, but there is no need to call all three methods in every frame if we do not need the results of that method to be calculated.

Playing sub-animations

Sub-animations allow us to animate only a part of the entire skeleton, which can be useful when we want an in-game character to be able to perform two different actions at once. For example, a character might be able to wield several different weapons while moving around the game world. The main animation applied to the character would be an animation for walking, running, or just standing still. Sub-animations can then be overlaid on top of the main animation to show the player holding, firing, or reloading the different weapon types.

In order to export a sub-animation, all we need to do is specify the name of the bone that is the root of the sub-animation in the Sub Anim Root field of the Marmalade exporter plugin. In the example situation given previously, you might choose to export the sub-animation starting at a bone that has the two arm bones as children.

The Blender plugin does not currently support this feature unfortunately, though you could potentially export the entire animation and then delete by hand any references to bones higher in the hierarchy than the sub-animation root bone in the ANIM file.

With the sub-animation exported, all we have to do to play it back is call the PlaySubAnim method of CIwAnimPlayer. An example of how to use this function is as follows:

lpAnimPlayer->PlaySubAnim(0, lpFlagWave, 1.0f,
CIwAnimBlendSource::LOOPING_F, 0.0f);

As you can see, it is almost identical in structure to the PlayAnim method. The only difference is an extra initial parameter, which is the sub-animation index number. The animation player can support two different sub-animations at the same time and the index number should be 0 or 1 to indicate which sub-animation you wish to change.

To detect the current playback status of a sub-animation, we can get hold of the CIwAnimBlendSource instance using the GetSourceSub method of CIwAnimPlayer. This method takes a single parameter, which is the index number of the sub-animation required.

Offset animations

When dealing with animations that cause a game character to move, such as walking, running, or making an attacking move, it is desirable to update the position of the character with respect to the animation being played so that the character's feet do not appear to slip on the ground.

Marmalade provides a method of doing this by way of an offset animation, which is an animation that consists of a single bone whose position and rotation can be used to move an object around the game world. Offset animations are exported using the same export process as any other animation.

To use an offset animation, we use the PlayOfsAnim method of CIwAnimPlayer, as shown in the following code:

lpAnimPlayer->PlayOfsAnim(lpMovementAnim, 1.0f, 0);

The parameters of this function are pointers to the offset animation instance, the speed of playback (again a value of 1 will play back at normal speed), and the required animation flags; so it is possible to play back offset animations as one shot or looped.

To find the current status of the offset animation, we can use the GetSourceOfs method on CIwAnimPlayer to retrieve the CIwAnimBlendSource instance that maintains it.

We can also find out position and rotation information for the start, end, and current offsets using the methods GetMatOfsInitial, GetMatOfsFinal, and GetMatOfs of CIwAnimPlayer. Each of these methods allows access to a CIwFMat object representing the current orientation of the offset. We can then use this information to allow us to update the position of a game character accordingly, so that other game functions such as collision detection continue to work correctly.

Obtaining bone positions and rotations

When discussing sub-animations earlier, we presented the example of a character being able to hold a variety of different weapons. Sub-animations will, of course, only provide half the solution to this problem, as they will move the character's arms to the correct pose; but, because the weapon is not part of the source 3D model, the character will just appear to be clutching at thin air.

We need some way of drawing a further model depicting the weapon, but how can we get it positioned in the correct place?

The answer is to ask the animation player to provide us with the current orientation and position of a bone that is located at the point where the weapon model would need to be drawn. We can do this by calling the GetBoneNamed method of CIwAnimPlayer, which will return a pointer to a CIwAnimBone instance representing the current orientation of the requested bone.

The position and rotation of the bone can be found using the GetPos and GetRot methods of CIwAnimBone, which allow us to generate a matrix in model space, or alternatively the GetMat method will return a model space matrix representing both the position and rotation of the bone if it has been calculated during the update of the CIwAnimPlayer instance.

Using the bone information, we can easily calculate a model matrix for rendering the weapon model in the correct place. First we use the bone information to generate a matrix in model space, we then multiply this by any rotation matrix needed to orient the character in the game world. Finally, add the world position of the character and the weapon model can be rendered in the character's hand.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.131.10