|
M3G 1.1 -- Jun 22, 2005 | |||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Object javax.microedition.m3g.Object3D javax.microedition.m3g.AnimationController
Controls the position, speed and weight of an animation sequence.
In anything other than the simplest scenes, an animation sequence will require control of more than one property of more than one object. For example, a jointed figure performing a single gesture is usually thought of as a single animation, yet it involves the coordinated control of the position and orientation of many different objects.
We define an animation sequence to mean a set of individual AnimationTracks that are controlled by a single AnimationController. Each AnimationTrack object contains all the data required to control a single animatable property on one target object.
An AnimationController object enables its associated animation sequence as a whole to be paused, stopped, restarted, fast-forwarded, rewound, arbitrarily repositioned, or deactivated. More formally, it defines a linear mapping from world time to sequence time.
The detailed behaviour of how the data flows through the animation
system as a whole is documented in the AnimationTrack
class.
In both immediate and retained mode, animations are explicitly applied
to target objects by calling the animate
method on the target
Object3D itself. This re-evaluates the values of all object properties that
have one or more animations attached. Animations are also applied to the
children of the target object, so the application is free to choose
between calling myWorld.animate
to animate everything in
myWorld
at once, or applying animations to more fine-grained
groups of objects individually.
Animation controllers have an active interval, specified by minimum and maximum world time values, during which the animation controller is active. Animations controlled by inactive animation controllers have no effect on their target objects and are simply ignored during animation application.
Each animation controller has a weight associated with it. The contributions of all active animations targeting the same property at the same time are blended together by their respective weights. Formally, the value of a scalar property P as a function of weights wi and contributions Pi is:
For vector-valued properties, the above formula is applied for each vector component separately.
For most types of animation, the simple weighted sum as shown above is sufficient, but for orientation values the implementation is required to normalize the resulting quaternion. The quaternion must be normalized even if there is only one active animation controller, and that controller has unit weight, so that no actual weighting or blending takes place. Note also that the individual contributing quaternions Pi must not be normalized prior to weighting.
AnimationController specifies a linear mapping between world
time, passed in to Object3D.animate
, and sequence
time that is used in sampling the associated keyframe data.
The sequence time is calculated directly from the given world time
at each call to animate
, instead of storing it internally.
This is to avoid undesirable accumulation of rounding errors and any
artifacts potentially resulting from that. It also simplifies the usage
of the animation system by making it effectively stateless (as opposed
to a traditional state machine design).
The mapping from world time to sequence time is parameterized by
three constants, specified in AnimationController, and one variable,
the world time, that is passed in to animate
. The formula
for calculating the sequence time ts corresponding to a
given world time tw is:
where
The reference point (twref, tsref) is
specified with the setPosition
method and the speed with
the setSpeed
method (note that setting the speed may also
change the reference point).
Sequence time can be visualized, in a coordinate system where world time is on the horizontal and sequence time on the vertical axis, as a line having slope s and passing through the point (twref, tsref).
As an example of the relationship between world time and sequence time, imagine a world where the current time is 5000 milliseconds since the start. An animation was started (from 0 ms sequence time) at 3000 ms, running at half speed. The animation was started 2000 ms ago, but because the speed is 0.5, the actual required sequence time tsref is 1000 ms. Here, we would have tw = 5000 ms, twref = 3000 ms, tsref = 0 ms, and s = 0.5 in the formula above.
Note that the unit of time is not explicitly specified anywhere in the API or the file format. It is strongly recommended that applications and content creation tools express times in milliseconds by default. Arbitrary units can, however, be used in specific applications if mandated by range or precision requirements.
We assume that synchronization of animation with other media types is only based on the world time passed from the controlling application. No synchronization events or other mechanisms are provided for this purpose. In the case of synchronizing animation to music, for example, the current elapsed time is often available directly from the music player library.
As an example of using animation, consider a case where we want a light source to pulsate between red and green, moving along a curved path. In both immediate and retained mode, this involves creating keyframe sequences and associating them with the light node, as illustrated in Example 1 below.
To apply the animation to the light object in our rendering
loop, we must call the animate
method, as shown in
Example 2.
AnimationTrack
,
KeyframeSequence
,
Object3D
Light light = new Light(); // Create a light node // Load a motion path from a stream, assuming it's the first // object there Object3D[] objects = Loader.load("http://www.ex.com/ex.m3g"); KeyframeSequence motion = (KeyframeSequence) objects[0]; // Create a color keyframe sequence, with keyframes at 0 ms // and 500 ms, and a total duration of 1000 ms. The animate // method will throw an exception if it encounters a // KeyframeSequence whose duration has not been set or whose // keyframes are out of order. Note that the Loader // automatically validates any sequences that are loaded from // a file. KeyframeSequence blinking = new KeyframeSequence(2, 3, KeyframeSequence.LINEAR); blinking.setKeyframe(0, 0, new float[] { 1.0f, 0.0f, 0.0f }); blinking.setKeyframe(1, 500, new float[] { 0.0f, 1.0f, 0.0f }); blinking.setDuration(1000); AnimationTrack blink = new AnimationTrack(blinking, AnimationTrack.COLOR); AnimationTrack move = new AnimationTrack(motion, AnimationTrack.TRANSLATION); light.addAnimationTrack(blink); light.addAnimationTrack(move); // Create an AnimationController and make it control both the // blinking and the movement of our light AnimationController lightAnim = new AnimationController(); blink.setController(lightAnim); move.setController(lightAnim); // Start the animation when world time reaches 2 seconds, stop // at 5 s. There is only one reference point for this // animation: sequence time must be zero at world time 2000 // ms. The animation will be running at normal speed (1.0, the // default). lightAnim.setActiveInterval(2000, 5000); lightAnim.setPosition(0, 2000);
appTime += 30; // advance time by 30 ms each frame light.animate(appTime); // Assume 'myGraphics3D' is the Graphics3D object we draw into. // In immediate mode, node transforms are ignored, so we get // our animated transformation into a local Transform object, // "lightToWorld". As its name implies, the transformation is // from the Light node's local coordinates to world space. light.getTransform(lightToWorld); myGraphics3D.resetLights(); myGraphics3D.addLight(light, lightToWorld);
Constructor Summary | |
AnimationController()
Creates a new AnimationController object. |
Method Summary | |
int |
getActiveIntervalEnd()
Retrieves the ending time of the current active interval of this animation controller, in world time units. |
int |
getActiveIntervalStart()
Retrieves the starting time of the current active interval of this animation controller, in world time units. |
float |
getPosition(int worldTime)
Retrieves the sequence time that corresponds to the given world time. |
int |
getRefWorldTime()
Returns the current reference world time. |
float |
getSpeed()
Retrieves the currently set playback speed of this animation controller. |
float |
getWeight()
Retrieves the currently set blending weight for this animation controller. |
void |
setActiveInterval(int start,
int end)
Sets the world time interval during which this animation controller is active. |
void |
setPosition(float sequenceTime,
int worldTime)
Sets a new playback position, relative to world time, for this animation controller. |
void |
setSpeed(float speed,
int worldTime)
Sets a new playback speed for this animation. |
void |
setWeight(float weight)
Sets the blending weight for this animation controller. |
Methods inherited from class javax.microedition.m3g.Object3D |
addAnimationTrack, animate, duplicate, find, getAnimationTrack, getAnimationTrackCount, getReferences, getUserID, getUserObject, removeAnimationTrack, setUserID, setUserObject |
Constructor Detail |
public AnimationController()
Creates a new AnimationController object. The default values for the new object are:
Method Detail |
public void setActiveInterval(int start, int end)
Sets the world time interval during which this animation controller is active.
This animation controller will subsequently be active when
the world time t is such that start <= t < end
, and
inactive outside of that range. As a special case, if start
and end
are set to the same value, this animation
controller is always active.
Note that changing the active interval has no effect on the mapping from world time to sequence time.
start
- the starting time of the active interval, in
world time units (inclusive)end
- the ending time of the active interval, in
world time units (exclusive)
java.lang.IllegalArgumentException
- if start > end
getActiveIntervalStart
,
getActiveIntervalEnd
public int getActiveIntervalStart()
Retrieves the starting time of the current active interval
of this animation controller, in world time units. The value
returned is the same that was last set with
setActiveInterval
, or if it has not been called
yet, the default value set at construction.
setActiveInterval
public int getActiveIntervalEnd()
Retrieves the ending time of the current active interval of
this animation controller, in world time units. The value
returned is the same that was last set with
setActiveInterval
, or if it has not been called
yet, the default value set at construction.
setActiveInterval
public void setSpeed(float speed, int worldTime)
Sets a new playback speed for this animation. The speed is set as a factor of the nominal speed of the animation: 1.0 is normal playback speed (as specified by the keyframe times in the associated animation tracks), 2.0 is double speed, and -1.0 is reverse playback at normal speed. A speed of 0.0 freezes the animation.
The speed setting effectively specifies how much to advance the internal playback position of this animation for a given increment in the global world time.
The internal reference point is modified so that sequence time at
the given world time remains unchanged. This allows the application
to change the speed without causing the animation to "jump" forward
or backward. To get the desired effect, the application should pass
its current world time to this method. This is the time that the
application has most recently used in animate
, or the
time that it is next going to use.
The reference point (twref, tsref) and speed (s) are updated based on the given world time and speed as follows:
Note that the computation of the new reference sequence time
takes place before updating the speed. See the class description
for the formula that getPosition
uses, and for more
discussion on animation timing.
speed
- new playback speed; 1.0 is normal speedworldTime
- reference world time; the value of sequence
time at this point will remain constant during the speed
changegetSpeed
public float getSpeed()
Retrieves the currently set playback speed of this animation controller.
setSpeed
public void setPosition(float sequenceTime, int worldTime)
Sets a new playback position, relative to world time, for
this animation controller. This sets the internal reference
point (twref, tsref) to
(worldTime
, sequenceTime
)
to shift the animation to the new position.
sequenceTime
- the desired playback position in sequence
time unitsworldTime
- the world time at which the sequence time
must be equal to sequenceTime
getPosition
public float getPosition(int worldTime)
Retrieves the sequence time that corresponds to the given world time. The returned value is computed with the formula given in the class description. Note that because the result may be a fractional number, it is returned as a float, not integer.
worldTime
- world time to get the corresponding sequence time of
worldTime
setPosition
public int getRefWorldTime()
setPosition
public void setWeight(float weight)
Sets the blending weight for this animation controller. The blending weight must be positive or zero. Setting the weight to zero disables this animation controller; that is, the controller is subsequently not active even within its active range. If the weight is non-zero, the animations controlled by this controller contribute to their target properties as described in the class description.
weight
- the new blending weight
java.lang.IllegalArgumentException
- if weight < 0
getWeight
public float getWeight()
Retrieves the currently set blending weight for this animation controller.
setWeight
|
M3G 1.1 -- Jun 22, 2005 | |||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |