|
Animation and Dynamic Updates Example
In this example, we show how to make dynamic changes to the scene graph. Though
it only presents animation of an object, the same process applies to changing
scene graph structure or other interactions. If you would like to
see the complete version of this code, it can be found in the
examples/basic directory and is named Setting up the applicationAdding animation or any form of dynamic updates starts with the same basic application structure as you saw in the initial Hello World demo. On top of that we now add some more code that will demonstrate the movement of an object over time. Though simple in design, it illustrates the concepts that you will be using time and again. The new code makes very few changes to that skeleton you had - only 3 lines of code difference. Understanding the Aviatrix3D Runtime modelThe design of Aviatrix3D scene graph restricts you from making random changes to the scene graph, by only allowing updates a certain very specific times. The primary motivator for this is dealing the the need to buffer and syncrhonise the updates in a multi-threaded situation. Allowing the user to make changes to the data at arbitrary times can cause a lot of headaches to the internal implementation, so the design has taken the safety-first approach to reduce synchronisation costs as much as possible. Making updates to the scene graph is a two step process - you start by telling a node that you would like to make changes to it by registering a listener instance. At some time later, your listener will be called to say it is safe to update the nominated node (but no other) at that point, this is when you can make changes. Aviatrix3D makes some distinctions in the types of updates based on the effect they have on the scene graph. The two options you have are for bounds or data. You register for bound changes whenever your effects will change the bounds of a node. For example, adding or removing children of a group, changing a transform or setting the vertices of the geometry. Data updates are used for when the node's data will not change any bounding information, such as material colours, light direction parameters, etc. Although you can register the callbacks for these at any time, you may decide that you want to synchronise the changes within a given frame. To do this, another observer class is provided. This class is registered with the render manager instance and is called at the start of every frame before any other updates are done. During this call, it is safe to assume that the scene graph structure is consistent and up to date (it is also a point where picking is enabled too, but we'll cover that in a later tutorial). For the most part, we expect that applications will always use both APIs so this tutorial will cover them as one. Registering and updating the scene graph
In order to update the scene graph, you need to first register with the node
that you want to modify an instance of
To register for these callbacks, you need to call one of two methods.
If you want to change the data associated with a node, for example the colour
or direction of a light, then For our example, we need to modify a transform to move the object about, so our class definition starts with the following code: public class RotationAnimation implements NodeUpdateListener { private Vector3f translation; private Matrix4f matrix; private TransformGroup transform; private float angle; public RotationAnimation(TransformGroup tx) { translation = new Vector3f(); matrix = new Matrix4f(); matrix.setIdentity(); transform = tx; }
Fairly simple code - we need a
There are two methods that you have the choice of in the
public void updateNodeBoundsChanges(Object src) { angle += Math.PI / 1000; float x = 0.5f * (float)Math.sin(angle); float y = 0.5f * (float)Math.cos(angle); translation.x = x; translation.y = y; matrix.setTranslation(translation); transform.setTransform(matrix); } public void updateNodeDataChanges(Object src) { } The second method, in this example, remains empty as we have nothing to do there. Processing per-frame notifications
For smooth animation, you will need to modify the transforms of the geometry on
a regular basis. Typically this will be every frame, so your animation code
starts with creating an instance of the interface that handles this -
When the update method is called by Aviatrix3D, you are now at the beginning of the frame and may perform a number of actions. In this example, we are using this method to simply register with the TransformGroup that we would like to change something that would effect its bounds - naming the transformation matrix. In more complex applications, it can become a sync point for your application code with outside influences such as network updates of database calls. Our basic class definition now looks like this: public class RotationAnimation implements ApplicationUpdateObserver, NodeUpdateListener { ...
Inside the method required by public void updateSceneGraph() { transform.boundsChanged(this); }
The second method, That completes the listener side of the code. The last step that needs to be taken is to register the application observer with the appropriate handler and pass in the right values to the scene graph. Completing the code
As the last step, we need to create an instance of our
... scene.setActiveView(vp); sceneManager.setScene(scene); RotationAnimation anim = new RotationAnimation(shape_transform); sceneManager.setApplicationObserver(anim); } The last line of code here is where the observer is registered with the render manager. Once the renderer is started, it will now receive calls every frame, resulting in the animated triangle that you should now be seeing. That's pretty much all there is to how Aviatrix3D works with dynamic updates. There are a few more rules to play with, but most of them are variations on the themes presented in this tutorial. |
[ Home ]
[ License ]
[ javadoc ]
[ Online Examples ]
[ Download ]
[ j3d.org ] [ Aviatrix3D ] [ Code Repository ] [ Java3D ] [ OpenGL ] [ Books ] [ Contact Us ] Last Updated: $Date: 2010-05-01 04:20:35 -0700 (Sat, 01 May 2010) $ |