Now we have loaded our shape in, we want to do a bit of animating. The way that I am doing this ( I don’t believe it is necessarily the most efficient but it is very easy ) is by using a morphing behaviour. Morphs allow a single node to shift between different geometry arrays with a single appearance shared between them, allowing what is effectively keyframed animation. An important consequence of the fact that they share an appearance is that each geometry array must consist of the same points in the same order- you can move them wherever you want, but you can’t add new points to your geometry at any point in a morphed animation.
We are going to create a behaviour to perform the morphing for us. Behaviours are Java3D’s way of interacting with the rest of the world- we can set them up to be triggered by events in the world –user input, objects interacting together, other behaviours or just every frame. If you want to add any degree of animation or interactivity to your world then behaviours are the way Java3D is expecting you to do it.
We will start by writing a morphBehaviour not entirely dissimilar from the one used in the morphing demo applet that you get with Java3D (the one with the opening and closing hand) this will move our little purple dude through the three frames of animation that we have for him –the one we have already imported, one with his left leg forward and one with his right arm forward. I say “his”but we are technically dealing with five cuboids and a sphere so feel free to adjust the gender if that terminology offends you.
Without further ado, lets look at what we want the behaviour to do. The most basic version of this behaviour will simply take an array of geometries and constantly animate between them but if you want to learn to do that you might as well look at the sun morphing example source code and work it out from there. We are going to take it one step further and have a key that we press to start the walking and release to stop it. This means that the behaviour needs to be activated by different triggers depending on whether the key is down (when we need it to run every frame) and when the key is up (when we don’t want it to run at all until the key is pressed again).
Behaviour itself is an abstract class and there are two methods we need to override, initialize and processStimulus. The first of these is the method that establishes when the Behaviour will wake up, the second explains what it will do when it is running. We will start however at the very beginning:
public class WalkMorph extends javax.media.j3d.Behavior {The creation clause takes a Morph and an Alpha. An Alpha basically creates a value that modulates between 0 and 1 and back again over time. It is a fairly complex class and there is plenty about it in the Javadocs so I will not go into too much detail here. The weights array expresses how much weight the Morph gives to each of its geometry arrays, which means for us that a higher weight will spend more of the animation in that position.
The WakeupCriterion is an abstract base class for any of the triggers that may start our behaviour running- in the creation we initialize the WakeupCriterions (WakeupCriteria?) starter and stopper to be triggered by an awt key event, Notice that we can create Arrays of WakeupCriterion object–this is because it we can then use a WakeupOr to wake our behaviour under multiple circumstances. Starter will be the original starting condition, keepUpCondition is kept in reserve for when the behaviour is running.
The initialize method is pretty much self-explanatory so we’ll go straight on to processStimulus. processStimulus is called as soon as our WakeupCriterion has been triggered. Once we have woken up the criterion has fired and if you want the behaviour to run again you need to reset wakeupOn at the end of processStimulus. What our method does is to check if the criterion that woke us up was an AWT event and if so run a method called processAWTEvent. Next up it checks a Boolean value called walking that is true if the animation should be running. If it is then we change the weights on the three frames of our animation according to the value of the alpha. Finally we reset the behaviour to be woken by keepUpCondition, which was the alternative WakeupCriterion that is triggered either once per frame or on an AWT key release event.
private void processAWTEvent(AWTEvent[] events)Here we have the method that processes the AWTEvent. All it does is check what type of event it was and if it was a KeyEvent it checks the type of Event. If the key was pressed and it was the “w”key then it sets the starting point for the alpha to the current time and sets walking to true, starting the animation loop in processStimulus. If the event was the “w”key being released then walking is false, so the animation will stop and we reset the WakeupCriterion to be the key press event that initially triggered the behaviour.
We will add this behaviour to a scenegraph broadly similar to the one we used previously- as the general changes are minimal I will only include the createSceneGraph() method and I probably won’t use all of that:
private BranchGroup createSceneGraph() {So far, so normal- all we have done differently is to create an array of GeometryArray objects and initialised them all to null. Next we create an array of URLs containing our three files, msFigureStep1.ms3d, msFigureStep2.ms3d and the inevitable msFigureStanding.ms3d. We then try to load them into scene, generate a Shape3D from them and then take the GeometryArray from that Shape3D and add it to our array of Geometries.
try {We follow this by creating a new Morph with our three GeometryArrays. The capabilities we set on ourMorph are the ones that allow our behaviour to operate on it. We use the same appearance as before to make it purple and add it to the SceneGraph.
Morph ourMorph = new Morph(geoms);Next we create the Alpha for our animation and I have to confess that a) I don’t understand alphas that well myself and b) this is the same one that powers the Sun morphing demo. It works fine in this context so I have pretty much left it as it is.
We have now added our WalkBehaviour to the scenegraph- it knows what elements it will act upon because we have handed it the alpha and the morph that we want it to use. Typically we would add the behaviour at the same level in the graph to the object the behaviour is acting on, although in this case it is not so important.
I have left out the rest of createSceneGraph because it is exactly the same as ShowDude –I know because I cut and pasted it from there. We can now run BasicWalkDude and get our little purple dude to move his little arms and legs for all the world as though he was ambling happily along through the void.
This section won’t end with a picture because it would look just the same as the previous one, unless I used an animated gif and I don’t want to breach the Geneva Convention so I think I’ll leave it at that.
Previous: Importing a Model | Back to the Index | Next: Now We're Getting Somewhere