Been There, Scene That: Part 2
(This is the conclusion of a two-parter that was begun last week and split in half for no particularly good reason. If you didn't read last week's entry yet, please do. I'll wait. ... Now, are you ready? Then let's get started.)
New Stuff
Most of the changes between TimingFramework and the scene graph animation library are tweaks on existing functionality, as described above. But there is also new functionality in the scene graph animation engine. Some of it is functionality that we have wanted in the TimingFramework for some time - we just happened to get around to it in this animation engine first.
Timeline
The Timeline class is probably the biggest new thing since the
Timing Framework. It adds a crucial missing piece of functionality from the
original library: the ability to group animations, schedule them in a
coordinated fashion, and use one, single heartbeat for all animations.
"Nice Grouping!"
The previous approach of daisy-chaining animations one-by-one with TimingTrigger
was quite useful for individual sequences of animations. And the new
addBeginAnimation()/addEndAnimation() methods of Clip enhance this capability
significantly. But it's still not what you want for larger systems with entire
groups of animations that need to be coordinated. Instead, you want some
way to create groups of animations
that operate on a single timeline relative to
each other and then schedule that group appropriately
with other animations or other
animation groups. This functionality makes it much easier to build up
more complex and interdependent models of animations.
Timeline enables this capability by allowing you to schedule animations on a given Timeline relative to when the Timeline itself starts. So, for example, if you want to fire off animations a, b, and c 100, 200, and 300 ms after some even occurs, then you can schedule these animations on a single Timeline and start the Timeline when that event occurs:
// Create the animation group
Timeline timeline = new Timeline();
timeline.schedule(a, 100);
timeline.schedule(b, 200);
timeline.schedule(c, 300);
// Later, when the event occurs
timeline.start();
"Two Hearts Beat as One"
One of the biggest recurring constraints that I ran up against with the
TimingFramework was the fact that each Animator started its own Swing Timer by
default. You could change this behavior, with the late-addition class
TimingSource, but it wasn't a convenient way to get what you really
wanted: a single timer for the whole system. You could also get a single-timer kind of behavior by adding multiple
TimingTargets to a single Animator, but this approach only works easily in
situations where you want similar timing and behavior characteristics from all
of these targets; for example, animations of different durations or interpolation
are difficult to
synchronize in this way.
What the system really needed was a single timing source that sent a heartbeat pulse to all animations. Each animation could then turn that pulse into an appropriate timing fraction, just as Animator does with its internal Swing Timer events. But there are a couple of excellent reasons why the single-pulse-generator model is superior to the multiple-Swing-Timer approach:
- Synchronized animations: If you have several animations in the system that are affecting the GUI, or are otherwise related in some way, you probably want them all to receive their timing events at the same time instead of at slightly different times because their internal Timers are kicking off at different intervals. Coordinating rendering changes in the single GUI display is a Good Thing; each element animating separately from everything else around it could contribute to a more chaotic user experience.
-
Resolution and frame rate: Anyone that worked through the gorey
details in the Resolution section of chapter 12 of Filthy
Rich Clients (or anyone that's
just worked closely with the Swing Timer) knows that the performance of that
Timer is often gated by constraints on the native platform. For example, on
Windows XP, the Swing Timer typically has an inter-event rate of about 16
milliseconds. This is because that's the highest rate achievable by the native
low-resolution timer upon which the Swing Timer depends (through its use of
Object.wait()). This problem is compounded when there are several Timers firing off at the same time, because the timing events are all gated by that underlyingwait()resolution, and cannot actually process thewait()'s in parallel.
For example, say you have one Animator that you'd like to set up with a resolution of 10 ms. On Windows XP, you'd actually get timing events at a resolution of 16 ms instead. Now, suppose you create a second Animator, also with a resolution of 10 ms. Since the underlying Swing Timer processes the timing events one by one, and since the gating resolution of the timer is what it is, you'll actually end up with an effective resolution of 32 ms for each of these Animators.
Now consider the model of the new animation engine, where there is just one single underlying timer running, sending out timing pulses to all animations in the system. This is more like the multiple-TimingTargets-per-Animator model where the only gating factor in resolution is that of the core timer itself, not how many Animators are waiting for the timing events.
Both of these capabilities of Timeline, grouping and the system-wide heartbeat,
are managed through the various schedule() methods of Timeline. You schedule an
animation to run with some offset from the beginning of a Timeline, and the
Timeline ensures that that animation will start when it needs to and thereafter
receive
the master heartbeat events from the system. You can schedule other animations
all on that same Timeline or on other Timelines and then schedule
the Timelines themselves to start when appropriate.
Timeline t1 = new Timeline();
// ... schedule animations on Timeline t1 ...
Timeline t2 = new Timeline();
// ... schedule animations on Timeline t2 ...
// Timeline t3 = new Timeline();
// schedule t1 to start 100 ms after t3 starts
t3.schedule(t1, 100);
// schedule t2 to start 200 ms after g3 starts
t3.schedule(t2, 200);
// start t3
t3.start();
An important point to note here is that Timelines and Clips may both be
scheduled on a Timeline. The schedule() methods actually
take an Animation
parameter, where Animation is a superclass of both Clip and Timeline. So a
Timeline itself can be started relative to some point in another
Timeline. In this way, we can create hierarchical groups of animations
that are automatically triggered according to how we scheduled them together.
MotionPath
One constraint of the TimingFramework is that while time could be interpolated non-linearly (using a non-linear Interpolator object), space was always interpolated linearly. For example, if you set up an animation between points (x0, y0) and (x1, y1), then the system would interpolate intermediate (x, y) points linearly between these points; all points calculated by the system (by the old Evaluator class) would lie along a straight line drawn between the two endpoints.
The new MotionPath class makes it possible to create keyframes, and an Evaluator
to interpolate between them, for curved paths.
What Now? Whither TimingFramework?
A logical question to ask now is, what about the Timing Framework? Is there a future in that project? Or should I start using the scene graph animation library instead?
I think the answer to these questions is still being figured out (since the scene graph library itself is still very much in-development), but here are a couple of reasonable ways to think about it, depending on your timeframe:
Short-term
The TimingFramework is in good shape in general. There was a reason that I declared it 1.0 (I didn't just randomly decide to add .44 to the previous release numbered 0.56). So please continue to use it as you see fit in your work for now. There are some minor issues that crop up occasionally that should probably be addressed in that library (although I admit I have been a bit preoccupied on Scene Graph and other things for a while and haven't been as responsive to issues as I'd like).
Scene Graph animation, on the other hand, is very much in flux right now. We're reasonably happy with the functionality of the library, but I wouldn't be shocked to see some more refactoring take place as we continue working on the Scene Graph project in general. So while I encourage you to take a look at it and play around with it, I wouldn't bet on the current implementation of it quite yet.
Long-term
I think (and this is where it gets fuzzy, because we're a bit busy focusing on the short-term right now and just trying to finish up the Scene Graph library in general) that the scene graph animation engine, or something very like it, will probably be the single library for animation eventually. It just doesn't make sense to have two such libraries, at least not coming out of the same group at Sun and not when one is essentially a subset of the other. When we get there and what the eventual, single library looks like when we're there is still a mystery. But long term, I see these libraries converging, and probably looking more like the Scene Graph version than Timing Framework.
But in the meantime, please use the Timing Framework while you investigate and starting playing with the Scene Graph animation engine. Send us feedback on what we could improve to make sure that the library we eventually end up with supports what you need from it.
By the Way
With all of this power to do cool, whizzy animations in Desktop Java applications, I'm thinking that "Scene Graph" isn't really a good enough name. Here's a possible alternative that I'm proposing, as of now:
Obscene
But it still feels like something's missing. Maybe it's just not graphic enough.
- Login or register to post comments
- Printer-friendly version
- chet's blog
- 1808 reads







Comments
by vdaburon - 2008-01-14 03:53
Hello, Obscene name is not a good idea for google search. You will find some "specials" web sites ... I suggest : 1) Scenatime 2) Anitime Vincent D.by chet - 2008-01-14 09:20
spiff: We're still working on performance (including GC issues), along with a host of other issues; we're clearly still mid-development with this project.
vdaburon: Apparently my joke mis-fired; I wasn't actually proposing a name change. The project name will stay the same fascinating, clever, and unique name that it is now: Scene Graph.
by spiff - 2008-01-09 00:16
Are there any plans to address garbage collection pauses? A GC pause in the middle of a smooth animation can be very noticeable and cause the animation to look jerky.by kishoresjava - 2008-01-11 01:43
Timeline is very useful. for my previous project, I wrote a wrapper class around Animator, called it Animator2, which links one Animator to other with specified time.
I started using this new API in my application.
by i30817 - 2008-01-10 05:26
I want to thank you for coming up with this integrated framework. Btw, really smart move to create this outside of the JDK process. Could you imagine the (good) refactoring that you're making in public jdk classes? If only swing text was a external package...