Search |
||
Been There, Scene ThatPosted by chet on January 4, 2008 at 2:27 PM PST
(This is Part 1 of a two-part blog. It's been broken in two for no particularly good reason other than it was getting a bit long for a single entry and I always like a bit of suspense and tension in my technical articles - don't you? . Look for Part 2 in the next few days) You may have already heard about the Scene Graph project that we released last month on java.net. In case you haven't heard about it yet, here's some information about it: We released the project last month on java.net. Since the team was pretty busy at the time (I was at JavaPolis talking about the project, among other things, and the team was cranking away on the actual code), we haven't really gotten around to blogging about it yet to tell people more about the project (hey, the code's out there - does anyone need anything more?). Fortunately for us, Josh seems to blog in his sleep, so there's at least been some information floating out there in the blogosphere. But maybe now that the library is available, we should actually talk about it to help everyone understand what it is, how it works, and what you can do with it. Hans Muller is working an intro/overview on the subject. Chris Campbell has a blog in the works on scene graph image effects. And I was tasked with (surprise, surprise) a discussion of animation. TimingFramework++I think that the best way to describe the animation engine in the scene graph project is that it is like the next major version of the Timing Framework. Maybe it's because I'm a graphics geek, but I always find it easier to understand concepts through pictures. So here's a technical diagram illustrating how the scene graph animation engine relates to the Timing Framework. It's a bit technical, but hopefully you'll get the point.
The similarlity between the two libraries is not, obviously, a coincidence. We started with the 1.0 version of the Timing Framework and changed it to suit our needs for the scene graph, where "suit our needs" means that we refactored the API to improve upon various things and added functionality that has so far been lacking in the Timing Framework. Rather than explain how the Timing Framework works, I'd encourage you to check out the project, the docs linked on the project site, the demos for that project, and the copious other amounts of information on the library (including demos, chapters in the Filthy Rich Clients book, and so on). I'll assume that anyone reading past here has some passing familiarity with the Timing Framework. I'll step through the major categories of differences between the TimingFramework and this new animation library, to give a sense of what's new in the scene graph. I'll show some sample code along the way, although I'd encourage you to check out the Nodes example on the scene graph site to see animation usage in action. Refactoring: What's Changed?Clip is the new AnimatorAfter living for way too long with the bureaucratically dull name
Besides, Clip has a handful of factory methods for the common cases:
create(int duration, double repeatCount, Object target,
String property, T... keyValues)
create(int duration, double repeatCount, Property property, T... keyValues)
create(int duration, double repeatCount, TimingTarget target)
create(int duration, Object target, String property,
T... keyValues)
create(int duration, Property property, T... keyValues)
create(int duration, TimingTarget target)
(The Property object will be explained later, but think of it as a replacement for the previous PropertySetter object in the Timing Framework). Like Animator, Clips begin running when the start() method is called (although Clip also has more involved and powerful scheduling capabilities, discussed later): // Fade in myObject over a half second
Clip clip = Clip.create(500, myObject, "opacity", 0f, 1f);
clip.start();
PropertySetter is now BeanPropertyThe old way of having the animation engine automatically set object/property values was through the PropertySetter class, which was constructed with a given object and property-name pair. We felt that this was a bit too constrictive in a world where there might be other ways that one might want to set values on objects; what if someone has an object without JavaBean-like getter/setters on it? So we defined a new interface, public interface Property<T> {
public <T> getValue();
public void setValue(T value);
}
Then we refactored the old public class BeanProperty<T> implements Property<T> {
public BeanProperty(Object object, String propertyName);
public <T> getValue();
public void setValue(T value);
}
Also, note that we separated the functionality of setting values on a Property object from animating those values. These concepts overlapped in the previous PropertySetter object, which was an implementation of TimingTarget and handled both animating the value in question as well as setting it on the specified object. Now, the new KeyFrames object handles animating a property, and the resulting value is then sent into the appropriate Property object. InterpolatorsOne of my favorite refactorings from the TimingFramework was the change that Chris
Campbell made to interpolators. The base interface, public interface Interpolator {
public float interpolate(float fraction);
}
The change is that there used to be several implementation classes of
Interpolator ( public class Interpolators {
static Interpolator getLinearInstance();
static Interpolator getDiscreteInstance();
static Interpolator getSplineInstance(float x1, float y1, float x2, float y2);
static Interpolator getEasingInstance();
static Interpolator getEasingInstance(float acceleration, float deceleration);
}
The linear, discrete, and spline interpolators are virtually the same as
before, in both construction and
operation. But there is now an additional "easing" variety that takes the place
of the Also, note that Clip uses an easing interpolator by default (with the default factors of .2f/.2f), as opposed to the old linearly-interpolated Animator object. Linear interpolation makes more sense as a default from an analytical standpoint (it seems less arbitrary than some particular choice of easing factors), but frankly most of the animations that you'll create should be non-linearly interpolated, which means that you would either not get the behavior you should if you used the linear default or (as in all of my animation demos) you'd have to keep writing the same boilerplate code to set the easing factors to get the behavior right. KeyFramesThe previous structure of
Now there is a KeyFrames implement the TimingTarget interface, and are used as targets of an animation to animate a value and then set it on the Property object with which they were constructed. Note that KeyFrames objects are created either with an explicit Property object or with the object/property pair that is used to construct a BeanProperty object internally: static KeyFrames<T> create(Object target, String propertyName, KeyFrame<T>... keyFrames);
static KeyFrames<T> create(Object target, String propertyName, T... keyValues);
static KeyFrames<T> create(Property<T> property, KeyFrame<T>... keyFrames);
static KeyFrames<T> create(Property<T> property, T... keyValues);
Evaluator is now ComposerThe system in TimingFramework to handle interpolation between values of various
types uses the As in the TimingFramework, most types that you would care about animating are already handled by the system. But if you do need to animate a variable of a type that is unknown to the system, then you need to create your own Composer subclass and register it with the system. It will then be used whenever the system encounters that type and looks for an appropriate Composer. Instead of putting sample code for a here, I'll just defer to the JavaDocs and the source code, which do a good job of showing what any new subclass would need to do in order to work within this system. But assuming you've defined some custom Composer, MytypeComposer, registration is easy: Composer.register(new MytypeComposer());
TimingTrigger is replaced by Clip dependency schedulingOne piece of functionality that is completely gone is the old
addBeginAnimation(Animation anim);
addBeginAnimation(Animation anim, long offset);
addEndAnimation(Animation anim);
addEndAnimation(Animation anim, long offset);
(where Animation is the superclass of both Clip and the as-yet-undiscussed Timeline class). So, for example, you can have clipB start 100 ms after clipA ends with the following call: clipA.addEndAnimation(clipB, 100); Minor ChangesThere are various minor changes to the system that you will notice as you try it
out. It's not worth going through all of these (because it'd take me a long
time to go over the API to catch all of these changes, for one thing), but they
should be fairly self-explanatory when you encounter them. For example, the old
(That's it for this entry - check back next week for the gripping conclusion to this discussion, as we go over some of the new bits in the scene graph animation library that are not now part of the Timing Framework) »
Related Topics >>
Java Desktop Comments
Comments are listed in date ascending order (oldest first)
Submitted by luke_sleeman on Wed, 2008-01-09 19:53.
What is the relationship between the Property and BeanProperty classes in the Scene graph project and the Property and BeanProperty classes in the Beans Binding project? It seems like they are practically identical. Have you guys spoken to Scott Violet and Shannon Hickey about how the binding framework and scene graph timing framework will integrate?
Submitted by joshy on Fri, 2008-01-04 22:30.
Well, what can I say. It's cold and grey and rainy here in Oregon. Blogging is way more fun than sleeping. :)
Submitted by psychostud on Sun, 2008-01-06 02:56.
So Cheat ,
does this mean we put away the timing Framwork at 1.0 and start using the animation engine in the scene graph in future?
Submitted by joshy on Mon, 2008-01-07 11:07.
Yes, Chet is actually The Cheat of HomeStarRunner fame. Long Live Da Cheat!
Submitted by chet on Mon, 2008-01-07 07:43.
psychostud: You've cleverly anticipated part of what I cover in Part 2 - I'll be posting that later today or tomorrow... (no problem about the typo - I've been called worse...)
Chet.
Submitted by psychostud on Mon, 2008-01-07 12:50.
thats great chet,
does the scenegraph also have something similar to the animatedTransitions Library or would they work complementing each other ?
Submitted by dummy on Tue, 2008-01-08 13:04.
Finally or too late?
1. Sun has been pushing 20 years old technology (Swing) for too long. Macromedia has shown the way forward with Flash, Microsoft followed with WPF (aka Silverlight) and now Sun is reimplementing this concept (animated scenegraph) with Java FX. Finally! But this is only the first step in the right direction. 2. Flash is not successful because Flash Player (or Actionscript) is a great technology (they both suck), but because they have a great IDE targeted at designers. Remember, great GUIs are made by designers not developers. Most developers hate designing GUIs and they suck at it. What Java needs is a GUI design tool that bridges the gap between designers and developers (you know what I mean when you yet again start transforming HTML design into XML/XSLT/Velocity/whatever template). A tool that lets us developers easily pick up where designers left off. Microsoft learned that lesson as we can see by their Expression series. Hope Sun has learned that lesson too. Or is it too late? 3. And finally: Sun, I hope you don't think that you can make a breakthrough GUI technology (Web or RIA) without supporting at least an industry-standard video playback, preferably also recording. Codec that is going to rule the next decade is H.264. If we can't create a YouTube rip-off in Java, don't bother developing this technology, because it's not going to make us competitive versus Flash or Silverlight.
Submitted by chet on Mon, 2008-01-07 16:46.
psychostud: AnimTrans is complementary to the scene graph animation engine for now, just like it's complementary with the Timing Framework. The "animation engine" is all about providing the fundamental support for timing behavior plus the ability to interpolate values of different types. AnimTrans, however, is about providing a layer on top of that to make animated seques, in particular, much easier. Maybe something like this makes sense to include in the scene graph engine eventually, but for now it's a separate piece of functionality.
Chet.
|
||
|
|