Java3D adding movement to a model, where to start/fix?

Well as of this morning I went digging around in some Java3D websites/tutorials/downloads, and I found out that Java3D really isn’t that complicated if you KNOW what to program/apply/setup.

I’m use to java2D, example: drawing out a shape,texturing it, and letting the KeyListener/cycle update everything, the movement, the graphics.

But it’s not that easy in Java3D J found out…
So far what I have is a basic .obj file being loaded via J3D (No knowledge on J3D so i can’t add movement), basic lighting, and a light color bieng applied to the model.

Picture of status:

Here’s the code: (Only one class at the moment)


	/**
	 * This class creates a very simple window in which a 3D canvas occupies the
	 * entire window and displays a 3D model loaded from disk. 
	 **/

public class Display extends JFrame implements Runnable, ActionListener,
		KeyListener {

	public static float absX = 1.9F;
	public static float absY = 1.2F;
	public static float absZ = 6F;
	public static Timer time;
	public int sleep = 10;

	/** The canvas where the object is rendered. */
	private Canvas3D canvas;

	/** Simplifies the configuration of the scene. */
	private SimpleUniverse universe;

	/** The root node of the scene. */
	private BranchGroup root;

	public static void main(String[] args) {
		try {
			new Display().setVisible(true);
		} catch (IOException ex) {
			ex.printStackTrace();
		}
	}

	/**
	 * Creates a window with a 3D canvas on its center.
	 * 
	 * @throws IOException  if some error occurs while loading the model.
	 */
	public Display() throws IOException {
		configureWindow();
		configureCanvas();
		conigureUniverse();
		addModelToUniverse();
		addLightsToUniverse();
		root.compile();
		universe.addBranchGraph(root);
		time = new Timer(sleep, this);
		time.start();
	}

	/**
	 * Defines basic properties of this window.
	 */
	private void configureWindow() {
		setTitle("Basic Java3D Program");
		setSize(640, 480);
		Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
		int absX1 = (screenSize.width - getWidth()) / 2;
		int absY1 = (screenSize.height - getHeight()) / 2;
		setLocation(/* absX1,absY1 */200, 200);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	}

	/**
	 * Defines basic properties of the canvas.
	 */
	private void configureCanvas() {
		canvas = new Canvas3D(SimpleUniverse.getPreferredConfiguration());
		canvas.setDoubleBufferEnable(true);
		getContentPane().add(canvas, BorderLayout.CENTER);
		canvas.addKeyListener(this);
	}

	/**
	 * Defines basic properties of the universe.
	 */
	private void conigureUniverse() {
		universe = new SimpleUniverse(canvas);
		universe.getViewingPlatform().setNominalViewingTransform();
	}

	/**
	 * Loads a model from disk and assign the root node of the scene
	 * 
	 * @throws IOException if it's impossible to find the 3D model
	 */
	private void addModelToUniverse() throws IOException {
		vpTranslation = new Transform3D();
		Scene scene = getSceneFromFile("bin/res/objects/male02.obj");
		root = scene.getSceneGroup();
		ViewingPlatform vp = universe.getViewingPlatform();
		TransformGroup vpGroup = vp.getMultiTransformGroup().getTransformGroup(
				0);
		/* You can transform the view platform as you do with other objects */
		Vector3f translationVector = new Vector3f(absX, absY, absZ);
		vpTranslation.setTranslation(translationVector);
		vpGroup.setTransform(vpTranslation);
	}

	public Transform3D vpTranslation;

	/**
	 * Adds a dramatic blue light...
	 */
	private void addLightsToUniverse() {
		Bounds influenceRegion = new BoundingSphere();
		Color3f lightColor = new Color3f(Color.BLUE);
		Vector3f lightDirection = new Vector3f(-1F, -1F, -1F);
		DirectionalLight light = new DirectionalLight(lightColor,
				lightDirection);
		light.setInfluencingBounds(influenceRegion);
		root.addChild(light);
		Background background = new Background(new Color3f(Color.LIGHT_GRAY));
		background.setApplicationBounds(influenceRegion);
		root.addChild(background);
	}

	public static Scene getSceneFromFile(String location) throws IOException {
		ObjectFile file = new ObjectFile(ObjectFile.RESIZE);
		return file.load(new FileReader(location));
	}

	public void keyPressed(KeyEvent k) {
		int key = k.getKeyCode();
		int right = 39;
		if (key == right) {
			absY += 2000; // Hoping this would move the model.
			Vector3f translationVector = new Vector3f(absX, absY, absZ);
			vpTranslation.setTranslation(translationVector);
		}
		System.out.println(key);
	}

	public void keyReleased(KeyEvent k) {
	}

	public void keyTyped(KeyEvent k) {
	}

	public void actionPerformed(ActionEvent e) {
		run();
	}

	public void run() {
		try {
			absX += 0.1f; // Tried moving the variables..
			repaint(); // Repaint the JFrame or Canvas3D?
			Thread.sleep(sleep);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

My Questions:
1: Did I setup everything right?
2: Would I repaint the JFrame, or the Canvas3D?
3: How can I interact with the model? (Via rotation/translation/camera angles).
4: Is there any methods that ‘Override’ a loop method for constant updating/initialization?
5: As seen in the picture above, is there any way with Graphics2D or even Graphics to render above that layer? (Example: render fps count?)

  1. looks ok

  2. Neither. Java3D will repaint automatically when there is a change to the scenegraph.

  3. if you want to change the camera you have to update the view transform group as you do with vpGroup in addModelToUniverse. If you want to move the model you have to put in under a TransformGroup that you update.

  4. Yes, thay are called behaviors. Google the Java3D tutorials and read more about it there. You should use a WakeUpOnElapsedFrames with 0 as parameter to update every frame. You should NOT use a Timer.

Still having troubles since I don’t even know what Variable to declare/class to use for that ‘WakeUpOnElapsedFrames(int i)’ method, or even where to declare any of this stuff at…
All helpful feedback welcome.

google java3d javadoc. Look up Behavior and WakeupOnElapsedFrames.

You have to override Behavior and call wakupOn with a WakeupOnElapsedFrames in the initialise and processStimilus methods. Remember to set sheduling bounds to an infinite sphere.

http://escience.anu.edu.au/lecture/cg/BehaviorInterpolator/behaviorExampleCode.en.html

The behavior have to be added to the scenegraph. You might have to wrap it in a BranchGroup.