Keyframes and Motion


Introduction
Keyframes
In messiah keyframes are handled slightly differently than in most other systems. The system we use is a hybrid of independent and grouped channel keying. If you create a key on a single channel of an item, then a key is created for all of the channels. However the only "included" key will be the one on the channel that was keyed. By "included" we mean that it is included in the motion curve (i.e. it affects the shape of the curve). You can, at a later time, include an excluded key on one of the other channels if you wish.
KeyIndexExample.gif

Consider the example above. The item has a keyframe set on frames 0, 10, 20, 30 and 40. Notice that only the xpos channel has included keys on all of these frames, ypos only has frame 0 included, while zpos has 0, 10 and 30 included. It is important to note that the total number of keyframes here is 5, and this is the value that will be returned by fxMotionNumKeys(). However if you were to use fxChannelNumKeys() for zpos it will return 3 indicating that there are 3 included keys for this channel.
Keyframe Channel Inclusion
You can get and set the inclusion status of keys using the fxKeyInclusionGet() and fxKeyInclusionSet() functions. For example, to add to the inclusion the xpos and zpos channels of an object on keyID=2 you would use:

FXint included = 0;

// get the existing "included" channels
fxKeyInclusionGet( obj, 2, &included, FX_NOFLAG );

// add xpos and zpos to it
included |= (FX_X_POSITION_BIT|FX_Z_POSITION_BIT);

// set the new inclusion
fxKeyInclusionSet( obj, 2, included, FX_NOFLAG );
Creating Keyframes
Keyframes are always referenced by their keyID. In the image above you can see the keyID indicated to the right of the keys, starting with keyID=0 at frame 0. Keyframe ID's are not constant, if a new key was created at frame 5 then it would become keyID=1 and the key at frame 10 would become keyID=2 and so on. When you create a new keyframe you will need to pass fxKeyCreate() the address of an FXint to hold the keyID of the newly created key. The function will return FX_TRUE if the key was created or 2 if a key already existed. In either case the keyID will be retrieved:

FXint keyID = 0;
FXint created = FX_FALSE;

created = fxKeyCreate( obj, 5.0, &keyID, FX_NOFLAG );

if( created == FX_TRUE )        // new key created
{
        // ...
}
else if( created == 2 )         // key already existed
{
        // ...
}
Setting Keyframe's Values
To set the value of a keyframe on one or more channels you will use the fxKeyChannelsSet() function. You will need to pass a flag indicating which channel(s) you want to change as well as an array of FXdouble's that contain the values for each channel. For example, to set the Y position channel of the first keyframe you would use:

fxKeyChannelsSet( object, 0, FX_Y_POSITION, &value, FX_NOFLAG );
where value is an FXdouble that contains the new value.
To set the values of all of the rotation channels you would use:

FXvecd values;
// ...
fxKeyChannelsSet( object, 0, FX_ROTATION, values, FX_NOFLAG );
Keeping in mind that FXvecd is really an array of three FXdouble's.
You can also set all of an object's channels:

FXchannels allValues;
//...
fxKeyChannelsSet( object, 0, FX_ALL_CHANNELS, allValues, FX_NOFLAG );
Undo and Keyframe Operations
All key editing operations that your module performs should be placed between calls to fxKeyEditBegin() and fxKeyEditEnd(). The reason for this is that messiah will treat all keyframe operations between those calls as one undo level, that is after running your module the user can undo the operations it performs with only a single undo. If you created 50 keyframes and did not place the calls to fxKeyCreate() between fxKeyEditBegin() and fxKeyEditEnd() then the user would need to undo 50 times to get back to the state they were in before running your module.
Motion
You may not always want to create keyframes to alter an object's motion. In the case of an Effect Module you would want to change the motion of an object after it's keyframed motion has already been taken into account. From there you can either add to that motion, or completely replace it.
There are three possible stages in the Animation Pipeline that your Effect Module can alter an object's motion. The first stage is immediatly following keyframe motion. This stage is referred to as "Post Motion", and is identified by the P_POST_MOTION() AN. The next stage in the pipeline is "Pre IK" which calculates before IK and is identified by P_PRE_IK(). The last stage in the pipeline where you can alter an object's motion is "Post IK" which will allow your Effect Module to take IK calculations into effect; this is identified by P_POST_IK().
Setting the values of an object's channels is almost identical to setting the values of its keyframes. Instead of fxKeyChannelsSet() you will use fxChannelsSet(), and since you are only changing the value of the channel(s) at the current point in the Animation Pipeline there is no keyID argument. So to set the position of an object to <1,1,1> you would use:

FXvecd values = { 1.0, 1.0, 1.0 };

fxChannelsSet( object, FX_POSITION, values, FX_NOFLAG );
Channel Blending
Let's say that you wanted to offset an object's motion by some value rather than replacing its value. For example we could shift an object's Y position channel up by 2 units. We could use fxChannelsGet() to first get the Y position channel value at the current frame, then add 2 to that value, and finally use fxChannelsSet() to set the new value. Instead we can simplify the process a bit by using the fxChannelsBlend() function. This function is almost identical to fxChannelsSet() with the addition of a "blend operator". The blend operator determines how the channel value(s) being passed will be combined with the existing channel values. In the case of our example we could use the FX_CHANOP_ADD() operator to cause the value we pass to be added to the current channel value:

FXdouble val = 2.0;

fxChannelsBlend( object, FX_Y_POSITION, &val, FX_CHANOP_ADD, FX_NOFLAG );
Other operator types will allow you to replace, subtract, multiply, divide or take the min or max of the two values.


© 2003 pmG WorldWide, LLC.


www.projectmessiah.com

groups.yahoo.com/pmGmessiah

Last Updated on Thu Jul 10 04:49:36 2003