JSR-184 Public Review Draft - Apr. 30, 2003.

javax.microedition.m3d
Class KeyframeSequence

java.lang.Object
  |
  +--javax.microedition.m3d.Object3D
        |
        +--javax.microedition.m3d.KeyframeSequence

public class KeyframeSequence
extends Object3D

KeyframeSequence 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 the Node transformation, 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 vector keyframes is determined by the animation target(s) the sequence is attached to.

Sequence time vs. world time

The sequence time t of a KeyframeSequence is derived from world time by its associated AnimationController(s). The sequence time is defined as 0 <= t < D, with t running from 0 at the start of the animation, to D, which is the duration of the keyframe sequence. The duration can be set with the setDuration method.

Open and closed sequences

The first valid keyframe in an open 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 an open 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.

If a sequence is closed (looping), then it is treated as if the keyframes were replicated backward and forward indefinitely at a spacing equal to the total duration of the animation. 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.

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.

Note that although independent of the keyframe values as such, the interpolation type and the closed/open state 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, AnimationTrack

Field Summary
static int LINEAR
          Specifies linear interpolation between keyframes.
static int SLERP
          Specifies spherical linear interpolation of quaternions.
static int SPLINE
          Specifies spline interpolation between keyframes.
static int SQUAD
          Specifies spline interpolation of quaternions.
static int STEP
          Specifies stepping from one keyframe value to the next.
 
Fields inherited from class javax.microedition.m3d.Object3D
userObject
 
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 getDuration()
          Gets the duration of this sequence.
 boolean isClosed()
          Queries whether this KeyframeSequence is open or closed (looping).
 void setClosed(boolean closed)
          Make this keyframe sequence closed or open.
 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 setValidRange(int first, int last)
          Validates the given range of keyframes in this KeyframeSequence.
 
Methods inherited from class javax.microedition.m3d.Object3D
addAnimationTrack, animate, clone, find, getAnimationTrack, getAnimationTrackCount, getReferences, getUserID, removeAnimationTrack, setUserID
 
Methods inherited from class java.lang.Object
equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

STEP

public static final int STEP

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 t1, where the following keyframe is at time t2, the value v is valid for all values of time t such that t1 <= t < t2 .

See Also:
Constant Field Values

LINEAR

public static final int LINEAR

Specifies linear interpolation between keyframes.

For a keyframe with value v1 at time t1, where the following keyframe has a value v2 at time t2, the interpolated value v is defined only for values of time t such that t1 <= t < t2, as follows:

v = v1 + (v2 - v1) * (t - t1) / (t2 - t1)

See Also:
Constant Field Values

SPLINE

public static final int SPLINE

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.

The interpolation is determined by the coefficients of the active segment, which for any given sequence time t is the one where ti <= t < ti+1.

We define an interpolation coefficient s on this segment in terms of the sequence time t such that s=(t-ti)/(ti+1-ti).

Tangents at the end points of the segment are also defined, Ti at the start point, and Ti+1 at the end point.

We can then express the interpolation of the curve for the interval s=(0,1) as follows:

|s3| |vi | | 2   -2  1   1  |
S = |s2| C = |vi+1| H = | -3  3   -2  -1 |
|s | |T0i | | 0   0   1   0  |
|1 | |T1i+1| | 1   0   0   0  |

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

vs = ST * H * C

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:

Ti = (vi+1 - vi-1) / 2

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

T0i = F+i * Ti
T1i = F-i * Ti

where:

F-i = 2(ti+1 - ti) / (ti+1 - ti-1)
F+i = 2(ti - ti-1) / (ti+1 - ti-1)

If i = 0 or i = n-1 in an open keyframe sequence, F-i = F+i = 0.

It is relatively easy to convert 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

SLERP

public static final int SLERP

Specifies spherical linear interpolation of quaternions.

Numerous references for spherically interpolating quaternions are available on the web.

Interpolation will take the shortest "great circle" path between keyframe orientations as represented on the surface of a hypersphere.

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

The method for interpolating quaternions in this manner is described in Section 4 of "Quaternion Algebra and Calculus" [Dave Eberley, 1999 - available here].

See Also:
Constant Field Values

SQUAD

public static final int SQUAD

Specifies spline interpolation of quaternions. As with regular spline interpolation, the tangents are adjusted to accommodate non-constant keyframe intervals.

The method for interpolating quaternions in this manner is described in Section 6 of "Quaternion Algebra and Calculus" [Dave Eberley, 1999 - available here].

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 sequence is initially open, with an undefined duration and an undefined valid range. A newly constructed sequence cannot be used in animation until the keyframe data has been input with setKeyframe and, after that, validated with setValidRange.

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. However, 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 - interpolation mode: step, linear, spline, slerp or squad
Throws:
java.lang.IllegalArgumentException - if numKeyframes < 1
java.lang.IllegalArgumentException - if numComponents < 1
java.lang.IllegalArgumentException - if interpolation is not one of STEP, LINEAR, SPLINE, SLERP, SQUAD
java.lang.IllegalArgumentException - if interpolation is not a valid interpolation mode for keyframes of size numComponents
Method Detail

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).

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.IndexOutOfBoundsException - if index < 0
java.lang.IndexOutOfBoundsException - if index >= numKeyframes
java.lang.IllegalArgumentException - if value.length < numComponents
java.lang.IllegalArgumentException - if time < 0

setValidRange

public void setValidRange(int first,
                          int last)

Validates the given range of keyframes in this KeyframeSequence. Only those keyframes that are in the valid range will be used in animation; keyframes outside of that range are ignored.

This method must always be called for a new or updated sequence before using it in an active AnimationTrack. Attempting to use a KeyframeSequence that has not been validated will cause an exception to be thrown by the Object3D.animate method.

A KeyframeSequence is automatically invalidated when any keyframes within the current valid range are updated, or when the duration of the sequence is updated. This is true regardless of whether any of the values actually change. Updating keyframes that are outside of the current valid range does not invalidate the sequence, however. Note also that a newly constructed sequence is always invalid.

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 the 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:

first, first+1, ..., last.

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

first, first+1, ..., numKeyframes-1, 0, 1, ..., last,

where numKeyframes is the total number of keyframes allocated for this sequence.

The time position for each keyframe in the active range must be greater than or equal to that of the preceding keyframe; if this is not the case, this method 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 position is specifically allowed.

Parameters:
first - index of the first valid keyframe
last - index of the last valid keyframe
Throws:
java.lang.IndexOutOfBoundsException - if first or last is not between [0, N-1], where N is the number of keyframes allocated for this sequence
java.lang.IllegalStateException - if any keyframe in the indicated valid range is out of order; that is, if the time stamps of the keyframes are not monotonically increasing

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 is also used when interpolating closed keyframe sequences: The time difference from the last valid keyframe to the first valid keyframe is calculated as follows:

duration - tlast + tfirst,

where ti is the time value for keyframe i in the valid keyframe range.

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

setClosed

public void setClosed(boolean closed)

Make this keyframe sequence closed or open. A closed keyframe sequence always loops back to the beginning from the end and has an interpolated segment from the last valid keyframe to the first.

An open 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:
closed - true to make this KeyframeSequence looping; false to make it open
See Also:
isClosed

isClosed

public boolean isClosed()

Queries whether this KeyframeSequence is open or closed (looping).

Returns:
true if this sequence is closed; false if it is open
See Also:
setClosed

JSR-184 Public Review Draft - Apr. 30, 2003.

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