/** The transform group containing the geometry, we'll use this to rotate our shape */
private TransformGroup tg = new TransformGroup();
The first thing to add is a "TransformGroup". A transform group is another scene graph element. Elements put inside a transform group will be effected by the transform applied to it. In our case we want to rotate our square so we'll add it to the transform group and update the transform.
/**
* This inner class will rotate our square around the x-axis
* each frame
*/
private class Rotator extends Behavior {
/** The current rotation round the x-axis */
private double rotation = 0;
/** The transform used for updates */
private Transform3D transform = new Transform3D();
/**
* The intialiser is called at the start of the universe
* and needs to set up the original coniditon that this
* object will wake up on
*/
public void initialize() {
setSchedulingBounds(new BoundingSphere(new Point3d(0,0,0),100));
wakeupOn(new WakeupOnElapsedFrames(0));
}
/**
* Each time the wake up condition is met, this method is called
* with a list of the reasons it was woken (e.g. the met conditions)
*
* @param enumeration The list of condition met
*/
public void processStimulus(Enumeration enumeration) {
// reschedule the wake up
wakeupOn(new WakeupOnElapsedFrames(0));
// add a little to the rotation
rotation += 0.1;
// update the transform affecting this shape
transform.setIdentity();
transform.rotX(Math.toRadians(rotation));
tg.setTransform(transform);
}
}
The next thing to add is another important scene graph element, the behaviors. Behaviors are elements put into the scene graph to perform some task. In this case, rotating our shape. Behaviors are scheduled based on conditions to wakeup and peform their tasks. In this example we use a WakeupOnElapsedFrames object to cause our behaviour to wake up every frame. However, there are many different types of condition or criterion which can be used to wake behaviors.
When our behavior wakes up we modify the transform manipulating our geometry to rotate it round the X axis. This should cause our square to rotate.
Our final step is to integrate the behavior into our Square object.
// this appearance is added to make sure that both
// sides of the square can be scene (e.g. no back face culling)
Appearance app = new Appearance();
PolygonAttributes poly = new PolygonAttributes();
poly.setCullFace(PolygonAttributes.CULL_NONE);
app.setPolygonAttributes(poly);
// note: the shape is now put inside a transform group
tg.addChild(new Shape3D(array,app));
tg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
addChild(tg);
// now we add our rotator behavior
addChild(new Rotator());
The lines above are added to our constructor. Instead of the adding the shape to the overall branch group we add it to the transform group. This means our transform will be applied to the shape. The transform group is added to the overall branch group instead. We also add a new instance of our behaviour. This allows the behavior to be woken as the scene is being rendered.
We have a couple of extra bits in there too. The setCapability allows us to update the transform group's transform from the behavior. This setting of capabilities is part of the way Java 3D attempts to optimise rendering by knowing exactly what you do and don't want to do to an element.
The final addition is the Appearance and PolygonAttributes lines. These lines are a little ahead of time but are required to make our example look nice. The appearance defines attribute about how a shape 3d will be rendered. In this case we're rotating our shape. By default Java 3D doesn't draw surfaces facing away from the viewer. This would result in us not being able to see the back side of the square as it rotates. The polygon attributes defined here prevent this effect. It not terribly important that you understand this right now as we'll cover more in later tutorials.