JME2 Starter 10 - Hello Animation (1)


« Previous: Starter Tutorial 9 - Hello Terrain
Next: Starter Tutorial 11 - Hello Animation (2) »


(Tip: Up-to-date source files for the tutorials are always in the repository)


This program introduces moving a LightNode using Controllers. The moving controller we will use is called SpatialTransformer.

Code Sample

import com.jme.animation.SpatialTransformer;
import com.jme.app.SimpleGame;
import com.jme.bounding.BoundingBox;
import com.jme.bounding.BoundingSphere;
import com.jme.light.PointLight;
import com.jme.light.SimpleLightNode;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.Node;
import com.jme.scene.shape.Box;
import com.jme.scene.shape.Sphere;
 
/**
 * Started Date: Jul 21, 2004<br>
 * <br>
 * 
 * This class demonstrates animation via a controller, as well as LightNode.
 * 
 * @author Jack Lindamood
 */
public class HelloAnimation extends SimpleGame {
	public static void main(String[] args) {
		HelloAnimation app = new HelloAnimation();
		app.setConfigShowMode(ConfigShowMode.AlwaysShow);
		app.start();
	}
 
	protected void simpleInitGame() {
		// Make my sphere and give it some bounds
		Sphere s = new Sphere("My sphere", 30, 30, 5);
		s.setModelBound(new BoundingSphere());
		s.updateModelBound();
		// I will rotate this pivot to move my light
		Node pivot = new Node("Pivot node");
 
		// This light will rotate around my sphere. Notice I don't give it a
		// position
		PointLight pl = new PointLight();
		// Color the light red
		pl.setDiffuse(ColorRGBA.red.clone());
		// Enable the light
		pl.setEnabled(true);
		// Remove the default light and attach this one
		lightState.detachAll();
		lightState.attach(pl);
 
		// This node will hold my light
		SimpleLightNode ln = new SimpleLightNode("A node for my pointLight", pl);
		// I set the light's position thru the node
		ln.setLocalTranslation(new Vector3f(0, 10, 0));
		// I attach the light's node to my pivot
		pivot.attachChild(ln);
 
		// I create a box and attach it to my lightnode. This lets me see where
		// my light is
		Box b = new Box("Blarg", new Vector3f(-.3f, -.3f, -.3f), new Vector3f(
				.3f, .3f, .3f));
		// Give the box bounds
		b.setModelBound(new BoundingBox());
		b.updateModelBound();
		ln.attachChild(b);
 
		// I create a controller to rotate my pivot
		SpatialTransformer st = new SpatialTransformer(1);
		// I tell my spatial controller to change pivot
		st.setObject(pivot, 0, -1);
 
		// Assign a rotation for object 0 at time 0 to rotate 0 degrees around
		// the z axis
		Quaternion x0 = new Quaternion();
		x0.fromAngleAxis(0, new Vector3f(0, 0, 1));
		st.setRotation(0, 0, x0);
 
		// Assign a rotation for object 0 at time 2 to rotate 180 degrees around
		// the z axis
		Quaternion x180 = new Quaternion();
		x180.fromAngleAxis(FastMath.DEG_TO_RAD * 180, new Vector3f(0, 0, 1));
		st.setRotation(0, 2, x180);
 
		// Assign a rotation for object 0 at time 4 to rotate 360 degrees around
		// the z axis
		Quaternion x360 = new Quaternion();
		x360.fromAngleAxis(FastMath.DEG_TO_RAD * 360, new Vector3f(0, 0, 1));
		st.setRotation(0, 4, x360);
 
		// Prepare my controller to start moving around
		st.interpolateMissing();
		// Tell my pivot it is controlled by st
		pivot.addController(st);
 
		// Attach pivot and sphere to graph
		rootNode.attachChild(pivot);
		rootNode.attachChild(s);
	}
}

Introducing the LightNode

The first new thing in this program is LightNode:

// This node will hold my light
SimpleLightNode ln = new SimpleLightNode("A node for my pointLight", pl);
// I set the light's position thru the node
ln.setLocalTranslation(new Vector3f(0, 10, 0));
// I attach the light's node to my pivot
pivot.attachChild(ln);

Only objects that extend Spatial can be attached to a scene graph. Node extends Spatial. Box extends TriMesh, which extends Geometry, which extends Spatial. PointLight extends Light, but is not a spatial. LightNode is a bridge between Light and Spatial.

When I set the LightNode’s local translation, I am actually setting my lights position. The difference is that this light’s position is relative to the LightNode. For example, if light node’s parent is translated up 10 and the lightnode is translated up 10, then the light is at 20 y. But, if I light.setLocation() to 10, then the light’s exact position is 10 no matter what parent it’s attached to. Usually, you’ll use LightNode to position your lights just like I did.

Introducing the Controller

The next new thing is when I create my controller to rotate my pivot:

// I create a controller to rotate my pivot
SpatialTransformer st = new SpatialTransformer(1);
// I tell my spatial controller to change pivot
st.setObject(pivot, 0, -1);

SpatialTransformer (jME API) extends Controller. Controllers ‘control’ things. They are the Java3D equivalent of Behaviors. Every frame, any Spatial in the graph has its Controllers updated first. SpatialTransformer changes a set of Spatial’s rotations, translations, and scales over time. The first part creates a SpatialTransformer that will change one object but note that you can create a SpatialTransformer which can change several objects with passing the number of the objects in the constructor.

I set the pivot Node to index 0 on the second part. For Controller may change several objects at the same time, setting index to Node would make it easier find the node to be changed. The -1 at the end of setObject is a parent index. Don’t confuse this with an object’s parent in the scene graph. It’s a little different. For now, always use -1.

Animation Using Quaternions

Now that SpatialTransformer knows what to update, lets tell it how to update it:

// Assign a rotation for object 0 at time 0 to rotate 0
// degrees around the z axis
Quaternion x0 = new Quaternion();
x0.fromAngleAxis(0, new Vector3f(0, 0, 1));
st.setRotation(0, 0, x0);

The fromAngleAxis command means that Quaternion (jME API) x0 is equivalent to rotating 0 degrees about a vector drawn to x=0, y=0, z=1. After calculating the correct rotation, I say that index 0 (which is pivot) should at time=0 rotate by x0. Next I assign a rotation of 180 degrees at time=2. Because the fromAngleAxis function takes rotations in radians, and not in degrees, I have to convert 180 to radians. We use FastMath (jME API) to do that. FastMath is an equivalent of the Math library, but uses all floats instead of doubles. This is because everything in jME uses floats, not doubles:

// Assign a rotation for object 0 at time 2 to rotate 180 degrees around
// the z axis
Quaternion x180 = new Quaternion();
x180.fromAngleAxis(FastMath.DEG_TO_RAD * 180, new Vector3f(0, 0, 1));
st.setRotation(0, 2, x180);
 
// Assign a rotation for object 0 at time 4 to rotate 360 degrees around
// the z axis
Quaternion x360 = new Quaternion();
x360.fromAngleAxis(FastMath.DEG_TO_RAD * 360, new Vector3f(0, 0, 1));
st.setRotation(0, 4, x360);

After setting a rotation for time=4 to rotate the object back, I wrap up using my Controller:

// Prepare my controller to start moving around
st.interpolateMissing();
// Tell my pivot it is controlled by st
pivot.addController(st);

In order to correctly interpolate rotations/scales/translations for times I didn’t specify to SpatialTransformer, I call interpolateMissing(). This is just a requirement for SpatialTransformer to work correctly. After interpolating, I add it as a controller (not as a child) to pivot. This means the controller will be updated and the object rotated every frame.

Multiple Animated Objects

If we had multiple animated objects, that all used the same SpatialTransformer, we would have to make sure that we register the SpatialTransformer only ONCE as a controller via the addController(…) method. For example, register it at the rootnode or at the first spatial which is animated. Otherwise the animation timings would be wrong (we won't go into detail here why).

Creating several SpatialTransformer instances and assigning them to the animated objects on a 1:1 basis would be another workable solution.

Scene Graph

My scene graph looks like the following:


rootNode
“pivot node” pivot “My sphere” s
“node for pointlight” ln
Box “blarg”
 
Except where otherwise noted, content on this wiki is licensed under the following license:CC Attribution 3.0 Unported