- Author: Tarek Sherif
- Date: April, 2019
- Status: Implemented
This RFC specifies a timeline management system to facilitate coordination of disparate animation systems in a way that is easily controlled by the application.
luma.gl and deck.gl currently support a variety of animation types such as deck.gl attribute transitions and glTF asset animations. Currently, these animations are all driven by the luma.gl AnimationLoop
's time
animation property, which essentially maps to wall time. The problem with this architecture is twofold:
- Applications have no control over animations.
- There is no way to coordinate multiple animations from these various systems. Application control would further exacerbate this, as all animations would have to independently track the current "animation time".
Animation systems generally consist of the of the following components, either implicitly or explicitly:
- A
time
value that is used as input to the system. - A
target
value that is updated based ontime
, such as a uniform value or transform parameter. The update can be a simple simulation based directly ontime
or a more complex system involving interpolation between key frames using a function such as linear or bezier interpolation.
The timeline management system proposed in this RFC addresses the problem of coordinating animations solely by manipulating the first component, input time
. A simple system that introduces application control of this value and allows it to be remapped using simple offset and scaling operations would allow for significantly richer animations to be used in deck.gl and luma.gl.
The Elevate team has requested the ability to control transitions in deck.gl, specifically the ability to pause, play and scrub through an attribute transition.
A timeline manager that can provide time
values to be used in animations that are independent of wall time. The timeline manager should support the following features:
- play: provide a
time
value that elapses at the same rate as wall time - pause:
time
remains constant at the current value - set: set
time
to a specific value - multiple
channels
that providechannelTime
values, related totime
, but with the following additional properties (all optional):rate
: (default1
) a scaling factor that indicates how quicklychannelTime
elapses relative totime
delay
: (default0
) an offset intotime
at whichchannelTime
begins elapsing (in units oftime
)duration
: (defaultInfinity
) how longchannelTime
runs for (in units oftime
)repeat
: (default1
) Number of times to repeatchannelTime
(only meaningful ifduration
has been set)
The channels
provide a mechanism for orchestrating complex animations that elapse differently but all relative to the same base timeline.
A timeline with two channels:
- Channel 1:
- rate: 0.5
- delay: 1
- duration: 4
- repeat: 3
- Channel 2:
- rate: 2
- delay: 5
- duration: 5
- repeat: 1
pause play
| |
Wall time: 0----5----10----15----20
time: 0----5 5----10----15
channelTime 1: 0---2 2---2---2
channelTime 2: 0----10
AnimatonLoop
will have a new timeline
property which is an instance of the class Timeline
. The Timeline
class will provide the following methods:
play
: elapsetime
automatically with wall timepause
: stop elapsingtime
automatically with wall timereset
: settime
to 0setTime(time)
: settime
to a specific valuegetTime(handle)
: get the currentchannelTime
from thechannel
indicated byhandle
. If no handle provided, get currenttime
addChannel(props)
: create a new channel with given properties and return a handle to itremoveChannel(handle)
: remove a channel from the timeline
The AnimationLoop
will update timeline
each frame with the current engineTime
(time since startup), which the timeline
can use to update time
if it is playing.
The time
property provided in animationProps
will be the value returned by AnimationLoop.timeline.getTime()
. This will ensure that all animations tracking animationProps.time
will follow timeline controls rather than wall time.
AnimationLoop.timeline
will also be passed in animatonProps
so that applications can easily manipulate it.
Integration with GLTFAnimation
should amount to simply passing the timeline object, and optionally a channel handle to the constructor. Then the animate method would simply use timeline.getTime()
to update rather than receiving the timeMs
argument.
Significant advantages of this approach over the current one are that animation become controlable by the application and it becomes straightforward to orchestrate multiple glTF animations of arbitrary duration into customizable application-defined animation sequences.