M3G 1.1 -- Jun 22, 2005

javax.microedition.m3g
Class KeyframeSequence

java.lang.Object
  extended byjavax.microedition.m3g.Object3D
      extended byjavax.microedition.m3g.KeyframeSequence

public class KeyframeSequence
extends Object3D

Encapsulates animation data as a sequence of time-stamped, vector-valued keyframes. Each keyframe represents the value of an animated quantity at a specific time instant.

A KeyframeSequence can be associated with multiple animation targets, that is, animatable object properties, via multiple AnimationTrack objects. Available animation targets include node and texture transformations, Material parameters, Camera parameters, and so on. When applying an animation to its target, the actual value for the target is derived by interpolating the keyframe values in the associated KeyframeSequence object.

The number of vector components per keyframe is specified in the constructor and is the same for all keyframes in the sequence. The interpretation of the keyframes is determined by the animation target(s) the sequence is attached to. For example, 4-component keyframes are interpreted as quaternions when applied to the ORIENTATION target.

Five different functions are available for interpolating the keyframe values: LINEAR and SPLINE, their quaternion equivalents SLERP and SQUAD; and the simple STEP function. Each of these is described in the Field Summary. There are also two repeat modes, LOOP and CONSTANT, that affect the interpolation.

Sequence time vs. world time

The internal sequence time t of a KeyframeSequence is derived from world time by its associated AnimationController(s). The formula for mapping world times to sequence times is given in the "Timing and speed control" section of the AnimationController class description. The sequence time is then used for interpolating between keyframe values as defined by the chosen interpolation function.

All (valid) keyframes in a KeyframeSequence must fall within a sequence time range of [0, D], where D is the duration of the keyframe sequence. The duration can be set with the setDuration method. For sequences using the LOOP repeat mode, the sequence time t is restricted into this range via a modulo operation, that is, by adding or subtracting a multiple of D such that 0 <= t < D. For sequences using the CONSTANT mode, the value of t is unrestricted.

Sequence repeat modes

The first valid keyframe in a CONSTANT sequence defines the interpolated value returned before this point in time. That is, with initial value v0 at time t0, the interpolated value v = v0 for values of time t such that t < t0.

The final valid keyframe in a CONSTANT sequence defines the interpolated value returned after this point in time. That is, with final value vN-1 at time tN-1, the interpolated value v = vN-1 for values of time t such that t >= tN-1.

A sequence using the LOOP repeat mode is interpolated as if the keyframes were replicated backward and forward indefinitely at a spacing equal to the given duration of the sequence. In this case, a keyframe which appears at time t will be treated as if it also appeared at time t + nD where n is any positive or negative integer and D is the duration of a single loop of the animation, given in setDuration. Note that this is not achieved by just the modulo operation on the sequence time described above.

In a looping sequence with N keyframes numbered [0, N-1], the successor of keyframe N-1 is keyframe 0, and the predecessor to keyframe 0 is keyframe N-1.

Coincident keyframes

The specification allows several keyframes to coexist at the same position in time. This allows discontinuities in the animation sequences, which can be useful for example in incorporating cuts to camera animation. In the case of several keyframes coinciding, the one with the lowest index is always used for the final value of segments ending at that position in time; for segments starting at that position, the keyframe with the highest index is used for the starting value. For sequences in LOOP mode, the keyframes from the next or previous repeat of the sequence may also coincide with the keyframes of the current repeat if they are at the very end or very beginning of the sequence. The keyframes in the previous repeat are then treated as having lower indices, and the keyframes in the next repeat as having higher indices, than the keyframes in the current repeat.

Note that although any number of coincident keyframes can be specified, a maximum of four will ever be used in SPLINE or SQUAD interpolation; two in LINEAR or SLERP interpolation; and only the one with the highest index in STEP interpolation.

Deferred exceptions

The validity of a keyframe sequence can be fully verified only when it is applied to an animation target, that is, in the animate method of Object3D. Any of the following conditions in a KeyframeSequence will then trigger an IllegalStateException:

Implementation guidelines

Although independent of the keyframe values as such, the interpolation type and the repeat mode of a sequence are set here rather than in the AnimationTrack objects using the sequence. This is so that the implementation can sensibly cache spline tangents or other auxiliary data potentially required at runtime.

See Also:
Binary format, Example, AnimationTrack, AnimationController

Field Summary
static int CONSTANT
          A parameter to setRepeatMode, specifying that this sequence is to be played back just once and not repeated.
static int LINEAR
          A constructor parameter that specifies linear interpolation between keyframes.
static int LOOP
          A parameter to setRepeatMode, specifying that this sequence is to be repeated indefinitely.
static int SLERP
          A constructor parameter that specifies spherical linear interpolation of quaternions.
static int SPLINE
          A constructor parameter that specifies spline interpolation between keyframes.
static int SQUAD
          A constructor parameter that specifies spline interpolation of quaternions.
static int STEP
          A constructor parameter that specifies stepping from one keyframe value to the next.
 
Constructor Summary
KeyframeSequence(int numKeyframes, int numComponents, int interpolation)
          Constructs a new keyframe sequence with specified interpolation method, number of components per keyframe, and number of keyframes.
 
Method Summary
 int getComponentCount()
          Returns the number of components per keyframe in this sequence.
 int getDuration()
          Gets the duration of this sequence.
 int getInterpolationType()
          Returns the type of interpolation for this sequence.
 int getKeyframe(int index, float[] value)
          Retrieves the time stamp and value of a single keyframe.
 int getKeyframeCount()
          Returns the total number of keyframes in this sequence.
 int getRepeatMode()
          Retrieves the current repeat mode of this KeyframeSequence.
 int getValidRangeFirst()
          Returns the first keyframe of the current valid range for this sequence.
 int getValidRangeLast()
          Returns the last keyframe of the current valid range for this sequence.
 void setDuration(int duration)
          Sets the duration of this sequence in sequence time units.
 void setKeyframe(int index, int time, float[] value)
          Sets the time position and value of the specified keyframe.
 void setRepeatMode(int mode)
          Sets the repeat mode of this KeyframeSequence.
 void setValidRange(int first, int last)
          Selects the range of keyframes that are included in the animation.
 
Methods inherited from class javax.microedition.m3g.Object3D
addAnimationTrack, animate, duplicate, find, getAnimationTrack, getAnimationTrackCount, getReferences, getUserID, getUserObject, removeAnimationTrack, setUserID, setUserObject
   

Field Detail

LINEAR

public static final int LINEAR

A constructor parameter that specifies linear interpolation between keyframes.

For a keyframe with value vi at time ti, where the following keyframe has a value vi+1 at time ti+1, the interpolated value v is defined only for values of time t such that ti <= t < ti+1, as follows:

where s is an interpolation factor in [0, 1) computed from the keyframe times:

See Also:
Constant Field Values

SLERP

public static final int SLERP

A constructor parameter that specifies spherical linear interpolation of quaternions.

This type of interpolation will interpolate at constant speed along the shortest "great circle" path between two keyframe values along the surface of the hypersphere of unit quaternions.

Spherical linear interpolation between two keyframe values qi and qi+1 is defined as:

where a is the angle between the two quaternions and s is the interpolation factor defined for LINEAR interpolation.

Note that the shortest path between two quaternions is not the same as the shortest path between the corresponding 3D orientations. There are always two quaternions corresponding to a single 3D orientation, each of which denotes a different direction of interpolation along the great circle; thus, quaternions can encode up to 360 degrees of rotation between adjacent keyframes.

It is common practice in some applications to precondition quaternions prior to slerping so that the shorter interpolation path in 3D is always chosen. While this is useful in special cases, it does not yield the same result in general, and is therefore incompatible with more advanced features such as animation blending. Hence, implementations are explicitly disallowed from incorporating this practice, and must implement the general slerp routine instead. Authoring tools, however, are encouraged to present the preconditioning as an option when exporting keyframe data.

Also note that interpolation between diametrically opposed quaternions in successive keyframes is undefined. It is recommended that authoring tools should take steps to warn designers if this case is detected.

More details can be found in "Quaternion Algebra and Calculus" by David Eberly [see Related Literature].

See Also:
Constant Field Values

SPLINE

public static final int SPLINE

A constructor parameter that specifies spline interpolation between keyframes. The keyframes will be interpolated with a Catmull-Rom spline adjusted to accommodate non-constant keyframe intervals.

For each curve segment i, we have the values vi at time ti, and vi+1 at time ti+1. We also define tangents at the end points of the segment: Ti at the start point, and Ti+1 at the end point.

Using the interpolation factor s defined for LINEAR interpolation, we can then express the interpolation of the curve as follows:

The value vs of the curve at position s can be calculated using the formula:

The only thing left to define is the calculation of the tangent vectors T{0,1}i. A standard Catmull-Rom spline assumes that the keyframe values are evenly spaced in time, and calculates the tangents as centered finite differences of the adjacent keyframes:

We apply additional scaling values to compensate for irregular keyframe timing, and the final tangents are:

where:

It is relatively easy to convert to this representation from piecewise Bezier splines (as used by 3ds max, for example) as long as the tangents are set up according to the above scheme. Conversion from other interpolating spline forms may not be exact, although any interpolating spline is guaranteed to pass through the keyframe values.

See Also:
Constant Field Values

SQUAD

public static final int SQUAD

A constructor parameter that specifies spline interpolation of quaternions.

This interpolation method is similar to the SPLINE method, but using equivalent quaternion operations. The tangents for each keyframe are computed as centered finite differences, only this time via quaternion logarithms:

Note that the operations above are not to be confused with scalar or vector operations. The notation q-1 denotes the inverse of quaternion q; the multiplications are quaternion multiplications; and the logarithm is a quaternion logarithm, which essentially yields a 3-vector as a result.

Keyframe tangents are scaled to compensate for irregular keyframe timing as specified for SPLINE interpolation. This yields the "incoming" tangent T0i and the "outgoing" tangent T1i. From the scaled tangents, intermediate quaternion values a and b are computed for use in interpolating the curve segments starting and ending at each keyframe:

Finally, the interpolated value q at position s (as defined in LINEAR) for a curve segment between keyframes i and i + 1 is obtained by using SLERP interpolation, as follows:

For more information, refer to "Key Frame Interpolation via Splines and Quaternions" by David Eberly [see Related Literature].

See Also:
Constant Field Values

STEP

public static final int STEP

A constructor parameter that specifies stepping from one keyframe value to the next. The actual value of each keyframe is used, without further interpolation, from the time position of that keyframe until the time of the next keyframe.

For a keyframe with value v at time ti, where the following keyframe is at time ti+1, the value v is valid for all values of time t such that ti <= t < ti+1.

See Also:
Constant Field Values

CONSTANT

public static final int CONSTANT

A parameter to setRepeatMode, specifying that this sequence is to be played back just once and not repeated.

See Also:
Constant Field Values

LOOP

public static final int LOOP

A parameter to setRepeatMode, specifying that this sequence is to be repeated indefinitely.

See Also:
Constant Field Values
Constructor Detail

KeyframeSequence

public KeyframeSequence(int numKeyframes,
                        int numComponents,
                        int interpolation)

Constructs a new keyframe sequence with specified interpolation method, number of components per keyframe, and number of keyframes. All keyframes are initialized to the zero vector, with a time stamp of zero. The repeat mode is initially CONSTANT (not looping), with an undefined duration and the valid range spanning all keyframes.

A newly constructed sequence cannot be used in animation until the duration of the sequence has been set. The valid range, that is, the range of keyframes that are included in the animation, can be set with setValidRange. This may be desirable if keyframes are generated dynamically or streamed over the network.

The interpolation method is one of the symbolic constants defined above. The method must be compatible with the number of components in the keyframes. STEP, LINEAR and SPLINE can be specified for any type of keyframes. On the other hand, SLERP and SQUAD can only be specified for 4-component keyframes, which are then interpreted as quaternions.

Parameters:
numKeyframes - number of keyframes to allocate for this sequence
numComponents - number of components in each keyframe vector
interpolation - one of the interpolation modes listed above
Throws:
java.lang.IllegalArgumentException - if numKeyframes < 1
java.lang.IllegalArgumentException - if numComponents < 1
java.lang.IllegalArgumentException - if interpolation is not one of LINEAR, SLERP, SPLINE, SQUAD, STEP
java.lang.IllegalArgumentException - if interpolation is not a valid interpolation mode for keyframes of size numComponents
Method Detail

getComponentCount

public int getComponentCount()
Returns the number of components per keyframe in this sequence.

Returns:
the number of components
Since:
M3G 1.1

getKeyframeCount

public int getKeyframeCount()
Returns the total number of keyframes in this sequence. Note that there may be fewer keyframes currently used for animation, controlled by the valid range.

Returns:
the number of keyframes
Since:
M3G 1.1
See Also:
setValidRange

getInterpolationType

public int getInterpolationType()
Returns the type of interpolation for this sequence.

Returns:
the interpolation type; one of LINEAR, SLERP, SPLINE, SQUAD, STEP
Since:
M3G 1.1

setKeyframe

public void setKeyframe(int index,
                        int time,
                        float[] value)

Sets the time position and value of the specified keyframe. The keyframe value is copied in from the given array. The length of the array must be at least equal to the size of a keyframe (numComponents). Refer to AnimationTrack documention for the order in which the keyframe components should be stored in the array for a particular target property.

If the interpolation type is SLERP or SQUAD, the keyframes are automatically normalized to yield unit quaternions for interpolation.

Parameters:
index - index of the keyframe to set
time - time position of the keyframe, in sequence time units
value - float array containing the keyframe value vector
Throws:
java.lang.NullPointerException - if value is null
java.lang.IndexOutOfBoundsException - if (index < 0) || (index >= getKeyframeCount)
java.lang.IllegalArgumentException - if value.length < getComponentCount
java.lang.IllegalArgumentException - if time < 0
See Also:
getKeyframe

getKeyframe

public int getKeyframe(int index,
                       float[] value)
Retrieves the time stamp and value of a single keyframe.

Note that if the interpolation type is SLERP or SQUAD, the keyframes are automatically normalized upon setting. The values returned here may therefore be different from the original input values.

Parameters:
index - index of the keyframe to retrieve
value - float array to store the keyframe value vector, or null to only return the time stamp
Returns:
the time value of the keyframe
Throws:
java.lang.IndexOutOfBoundsException - if (index < 0) || (index >= getKeyframeCount)
java.lang.IllegalArgumentException - if (value != null) && (value.length < getComponentCount)
Since:
M3G 1.1
See Also:
setKeyframe

setValidRange

public void setValidRange(int first,
                          int last)

Selects the range of keyframes that are included in the animation. Keyframes outside of that range are ignored by the animate method in Object3D.

Setting the valid range shorter than the whole sequence enables the application to use the sequence as a circular buffer when generating new keyframe data on the fly, for example. In a typical case, however, the valid range would span the whole sequence.

The valid keyframe range is always interpreted in the direction of ascending indices. If first <= last, the valid keyframes are those at the indices:

If last < first, the valid range wraps around and the valid keyframe indices are:

The time position of each keyframe in the active range must be greater than or equal to that of the preceding keyframe; if this is not the case, Object3D.animate will throw an exception. The time stamps must be in non-decreasing order, because otherwise the interpolated values between keyframes would be undefined. Note that having two or more keyframes with the same time stamp is specifically allowed.

Parameters:
first - index of the first valid keyframe
last - index of the last valid keyframe
Throws:
java.lang.IndexOutOfBoundsException - if (first < 0) || (first >= getKeyframeCount)
java.lang.IndexOutOfBoundsException - if (last < 0) || (last >= getKeyframeCount)
See Also:
getValidRangeFirst, getValidRangeLast

getValidRangeFirst

public int getValidRangeFirst()
Returns the first keyframe of the current valid range for this sequence.

Returns:
the index of the first valid keyframe
Since:
M3G 1.1
See Also:
setValidRange

getValidRangeLast

public int getValidRangeLast()
Returns the last keyframe of the current valid range for this sequence.

Returns:
the index of the last valid keyframe
Since:
M3G 1.1
See Also:
setValidRange

setDuration

public void setDuration(int duration)

Sets the duration of this sequence in sequence time units. The duration of a keyframe sequence, as used in animation playback, is determined by the value set here, irrespective of the time stamps of individual keyframes, and irrespective of which keyframes happen to be in the valid range at any given time.

The duration D is also used when interpolating looping keyframe sequences. The time interval from the last valid keyframe to the first valid keyframe of the next cycle is calculated as follows:

where tfirst and tlast are the time stamps of the first and last keyframe, respectively, in the valid range (see setValidRange). Note that they are not necessarily the first and last keyframe of the whole sequence.

The duration of the sequence must not be less than the time stamp of the last valid keyframe (tlast), as otherwise the above formula would yield a negative time interval. Since the duration and the valid range can both be changed at any time, this condition is only enforced by the animate method in Object3D.

Parameters:
duration - duration of the valid range of the sequence
Throws:
java.lang.IllegalArgumentException - if duration <= 0
See Also:
getDuration

getDuration

public int getDuration()

Gets the duration of this sequence.

Returns:
the duration of this sequence in sequence time units
See Also:
setDuration

setRepeatMode

public void setRepeatMode(int mode)

Sets the repeat mode of this KeyframeSequence. There are two alternatives, LOOP and CONSTANT.

A looping sequence always loops back to the beginning from the end and has an interpolated segment from the last valid keyframe to the first.

A constant sequence maintains the first valid keyframe value from the beginning of the sequence to the actual time of that keyframe, and the last valid keyframe value from that keyframe to the end time of the sequence and beyond.

Parameters:
mode - the repeat mode to set
Throws:
java.lang.IllegalArgumentException - if mode is not one of CONSTANT, LOOP
See Also:
getRepeatMode

getRepeatMode

public int getRepeatMode()

Retrieves the current repeat mode of this KeyframeSequence.

Returns:
the current repeat mode; CONSTANT or LOOP
See Also:
setRepeatMode

M3G 1.1 -- Jun 22, 2005

Copyright © 2005 Nokia Corporation. See the Copyright Notice for details.