You are on page 1of 22

import java.applet.Applet; import java.awt.Button; import java.awt.Choice; import java.awt.FlowLayout; import java.awt.Frame; import java.awt.GraphicsConfiguration; import java.awt.

GridBagConstraints; import java.awt.GridBagLayout; import java.awt.ItemSelectable; import java.awt.Label; import java.awt.Panel; import java.awt.Scrollbar; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.AdjustmentEvent; import java.awt.event.AdjustmentListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener;

import javax.media.j3d.Alpha; import javax.media.j3d.AmbientLight; import javax.media.j3d.Appearance; import javax.media.j3d.Background; import javax.media.j3d.BoundingSphere; import javax.media.j3d.BranchGroup; import javax.media.j3d.Canvas3D; import javax.media.j3d.ColoringAttributes; import javax.media.j3d.DirectionalLight; import javax.media.j3d.Light;

import javax.media.j3d.Material; import javax.media.j3d.Transform3D; import javax.media.j3d.TransformGroup; import javax.vecmath.Color3f; import javax.vecmath.Point3d; import javax.vecmath.Point3f; import javax.vecmath.Vector3d; import javax.vecmath.Vector3f;

import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.behaviors.interpolators.KBKeyFrame; import com.sun.j3d.utils.behaviors.interpolators.KBRotPosScaleSplinePathInterpolator; import com.sun.j3d.utils.behaviors.vp.OrbitBehavior; import com.sun.j3d.utils.geometry.Cone; import com.sun.j3d.utils.geometry.Sphere; import com.sun.j3d.utils.universe.SimpleUniverse; import com.sun.j3d.utils.universe.ViewingPlatform;

/* * This program demonstrates the use of KBRotPosScaleSplinePathInterpolator in * order to to do spline animation paths using Kochanek-Bartels (also known as * TCB or Tension-Continuity-Bias ) splines. A cone red cone is animated along a * spline path specified by 5 knot points, which are showns as cyan spheres. * * Use the left mouse button to changes orientation of scene. Use the middle * mouse button to zoom in/out Use the right mouse button to pan the scene */ public class Main extends Applet implements ActionListener,

AdjustmentListener, ItemListener {

// 3D Canvas Canvas3D canvas;

// UI Components Panel controlPanel;

Panel canvasPanel;

Button animateButton;

Choice interpChoice;

Scrollbar speedSlider;

Label speedLabel;

Label interpLabel;

// Scene Graph BoundingSphere bounds;

BranchGroup root;

BranchGroup behaviorBranch;

Transform3D sceneTransform;

TransformGroup sceneTransformGroup;

Transform3D objTransform;

TransformGroup objTransformGroup;

Transform3D lightTransform1;

Transform3D lightTransform2;

TransformGroup light1TransformGroup;

TransformGroup light2TransformGroup;

// Key Frames & Interpolator int duration = 5000;

Alpha animAlpha;

Transform3D yAxis;

KBKeyFrame[] linearKeyFrames = new KBKeyFrame[6];

KBKeyFrame[] splineKeyFrames = new KBKeyFrame[6];

KBRotPosScaleSplinePathInterpolator splineInterpolator;

KBRotPosScaleSplinePathInterpolator linearInterpolator;

// Data: Knot positions & transform groups Vector3f pos0 = new Vector3f(-5.0f, -5.0f, 0.0f);

Vector3f pos1 = new Vector3f(-5.0f, 5.0f, 0.0f);

Vector3f pos2 = new Vector3f(0.0f, 5.0f, 0.0f);

Vector3f pos3 = new Vector3f(0.0f, -5.0f, 0.0f);

Vector3f pos4 = new Vector3f(5.0f, -5.0f, 0.0f);

Vector3f pos5 = new Vector3f(5.0f, 5.0f, 0.0f);

TransformGroup k0TransformGroup;

TransformGroup k1TransformGroup;

TransformGroup k2TransformGroup;

TransformGroup k3TransformGroup;

TransformGroup k4TransformGroup;

TransformGroup k5TransformGroup;

// Flags boolean animationOn = true;

boolean linear = false;

private SimpleUniverse u = null;

public Main() { }

public void init() { this.setLayout(new FlowLayout());

// Create the canvas and the UI canvasPanel = new Panel(); controlPanel = new Panel(); createCanvasPanel(canvasPanel); this.add(canvasPanel); createControlPanel(controlPanel); this.add(controlPanel);

// Create the scene. BranchGroup scene = createSceneGraph();

// Setup keyframe data for our animation setupSplineKeyFrames(); setupLinearKeyFrames();

// Setup alpha, create the interpolators and start them. We // create both a linear and a spline interpolator and turn on // one depending on user selection. The default is spline. setupAnimationData(); createInterpolators();

startInterpolator();

// Add viewing platform u = new SimpleUniverse(canvas);

// add mouse behaviors to ViewingPlatform ViewingPlatform viewingPlatform = u.getViewingPlatform();

viewingPlatform.setNominalViewingTransform();

// add orbit behavior to the ViewingPlatform OrbitBehavior orbit = new OrbitBehavior(canvas, OrbitBehavior.REVERSE_ALL); BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0); orbit.setSchedulingBounds(bounds); viewingPlatform.setViewPlatformBehavior(orbit);

u.addBranchGraph(scene); }

public void destroy() { u.cleanup(); }

/* * This creates the control panel which contains a choice menu to toggle * between spline and linear interpolation, a slider to adjust the speed of * the animation and a animation start/stop button.

*/ private void createControlPanel(Panel p) {

GridBagLayout gl = new GridBagLayout(); GridBagConstraints gbc = new GridBagConstraints();

p.setLayout(gl); gbc.weightx = 100; gbc.weighty = 100; gbc.fill = GridBagConstraints.BOTH;

gbc.gridx = 0; gbc.gridy = 0; gbc.gridwidth = 1; gbc.gridheight = 1; interpLabel = new Label("Interpolation Type", Label.LEFT); p.add(interpLabel, gbc);

gbc.gridx = 1; gbc.gridy = 0; gbc.gridwidth = 1; gbc.gridheight = 1; interpChoice = new Choice(); interpChoice.add("Spline"); interpChoice.add("Linear"); p.add(interpChoice, gbc); interpChoice.addItemListener(this);

gbc.gridx = 0;

gbc.gridy = 2; gbc.gridwidth = 2; gbc.gridheight = 1; speedSlider = new Scrollbar(Scrollbar.HORIZONTAL, 2, 1, 0, 11); speedSlider.setUnitIncrement(1); p.add(speedSlider, gbc); speedSlider.addAdjustmentListener(this);

gbc.gridx = 0; gbc.gridy = 3; gbc.gridwidth = 2; gbc.gridheight = 1; speedLabel = new Label(" - Animation Speed +", Label.CENTER); p.add(speedLabel, gbc);

gbc.gridx = 0; gbc.gridy = 5; gbc.gridwidth = 2; gbc.gridheight = 1; animateButton = new Button("Stop Animation"); p.add(animateButton, gbc); animateButton.addActionListener(this);

/* * This creates the Java3D canvas */ private void createCanvasPanel(Panel p) {

GridBagLayout gl = new GridBagLayout(); GridBagConstraints gbc = new GridBagConstraints();

p.setLayout(gl); gbc.gridx = 0; gbc.gridy = 0; gbc.gridwidth = 5; gbc.gridheight = 5; GraphicsConfiguration config = SimpleUniverse .getPreferredConfiguration();

canvas = new Canvas3D(config); canvas.setSize(490, 490); p.add(canvas, gbc);

/* * This creates the scene with 5 knot points represented by cyan spheres, a * cone obejct that will be transformed, and two directional lights + and * ambient light. */ public BranchGroup createSceneGraph() {

// Colors for lights and objects Color3f aColor = new Color3f(0.2f, 0.2f, 0.2f); Color3f eColor = new Color3f(0.0f, 0.0f, 0.0f); Color3f sColor = new Color3f(1.0f, 1.0f, 1.0f);

Color3f coneColor = new Color3f(0.9f, 0.1f, 0.1f); Color3f sphereColor = new Color3f(0.1f, 0.7f, 0.9f); Color3f bgColor = new Color3f(1.0f, 0.7f, 0.4f); Color3f lightColor = new Color3f(1.0f, 1.0f, 1.0f);

// Root of the branch grsph BranchGroup root = new BranchGroup();

// Create transforms such that all objects appears in the scene sceneTransform = new Transform3D(); sceneTransform.setScale(0.14f); Transform3D yrot = new Transform3D(); yrot.rotY(-Math.PI / 5.0d); sceneTransform.mul(yrot); sceneTransformGroup = new TransformGroup(sceneTransform); sceneTransformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WR ITE); sceneTransformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_RE AD); root.addChild(sceneTransformGroup);

// Create bounds for the background and lights bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0f);

// Set up the background Background bg = new Background(bgColor); bg.setApplicationBounds(bounds); sceneTransformGroup.addChild(bg);

// Create the transform group node for the lights lightTransform1 = new Transform3D(); lightTransform2 = new Transform3D(); Vector3d lightPos1 = new Vector3d(0.0, 0.0, 2.0); Vector3d lightPos2 = new Vector3d(1.0, 0.0, -2.0); lightTransform1.set(lightPos1); lightTransform2.set(lightPos2); light1TransformGroup = new TransformGroup(lightTransform1); light2TransformGroup = new TransformGroup(lightTransform2); sceneTransformGroup.addChild(light1TransformGroup); sceneTransformGroup.addChild(light2TransformGroup);

// Create lights AmbientLight ambLight = new AmbientLight(aColor); Light dirLight1; Light dirLight2;

Vector3f lightDir1 = new Vector3f(lightPos1); Vector3f lightDir2 = new Vector3f(lightPos2); lightDir1.negate(); lightDir2.negate(); dirLight1 = new DirectionalLight(lightColor, lightDir1); dirLight2 = new DirectionalLight(lightColor, lightDir2);

// Set the influencing bounds ambLight.setInfluencingBounds(bounds); dirLight1.setInfluencingBounds(bounds); dirLight2.setInfluencingBounds(bounds);

// Add the lights into the scene graph sceneTransformGroup.addChild(ambLight); sceneTransformGroup.addChild(dirLight1); sceneTransformGroup.addChild(dirLight2);

// Create a cone and add it to the scene graph. objTransform = new Transform3D(); objTransformGroup = new TransformGroup(objTransform); objTransformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRIT E); sceneTransformGroup.addChild(objTransformGroup);

Material m = new Material(coneColor, eColor, coneColor, sColor, 100.0f); Appearance a = new Appearance(); m.setLightingEnable(true); a.setMaterial(m); Cone cone = new Cone(0.4f, 1.0f); cone.setAppearance(a); objTransformGroup.addChild(cone);

// Create transform groups for each knot point // knot point 0 Transform3D t3dKnot = new Transform3D(); t3dKnot.set(pos0); TransformGroup k0TransformGroup = new TransformGroup(t3dKnot); sceneTransformGroup.addChild(k0TransformGroup);

// knot point 1 t3dKnot = new Transform3D();

t3dKnot.set(pos1); TransformGroup k1TransformGroup = new TransformGroup(t3dKnot); sceneTransformGroup.addChild(k1TransformGroup);

// knot point 2 t3dKnot = new Transform3D(); t3dKnot.set(pos2); TransformGroup k2TransformGroup = new TransformGroup(t3dKnot); sceneTransformGroup.addChild(k2TransformGroup);

// knot point 3 t3dKnot = new Transform3D(); t3dKnot.set(pos3); TransformGroup k3TransformGroup = new TransformGroup(t3dKnot); sceneTransformGroup.addChild(k3TransformGroup);

// knot point 4 t3dKnot = new Transform3D(); t3dKnot.set(pos4); TransformGroup k4TransformGroup = new TransformGroup(t3dKnot); sceneTransformGroup.addChild(k4TransformGroup);

// knot point 5 t3dKnot = new Transform3D(); t3dKnot.set(pos5); TransformGroup k5TransformGroup = new TransformGroup(t3dKnot); sceneTransformGroup.addChild(k5TransformGroup);

// Create spheres for each knot point's transform group

ColoringAttributes sphereColorAttr = new ColoringAttributes(); sphereColorAttr.setColor(sphereColor); Appearance sphereAppearance = new Appearance(); sphereAppearance.setColoringAttributes(sphereColorAttr); k0TransformGroup.addChild(new Sphere(0.10f, sphereAppearance)); k1TransformGroup.addChild(new Sphere(0.10f, sphereAppearance)); k2TransformGroup.addChild(new Sphere(0.10f, sphereAppearance)); k3TransformGroup.addChild(new Sphere(0.10f, sphereAppearance)); k4TransformGroup.addChild(new Sphere(0.10f, sphereAppearance)); k5TransformGroup.addChild(new Sphere(0.10f, sphereAppearance));

return root; }

/* * This sets up the key frame data for the spline interpolator. Each knot * point has a scale and rotation component specified. The second argument * to KBKeyFrame (in this case 0) tells the interpolator that this is to be * interpolated using splines. The last three arguments to KBKeyFrame are * Tension, Continuity, and Bias components for each key frame. */ private void setupSplineKeyFrames() { // Prepare spline keyframe data Point3f p = new Point3f(pos0); // position float head = (float) Math.PI / 2.0f; // heading float pitch = 0.0f; // pitch float bank = 0.0f; // bank Point3f s = new Point3f(1.0f, 1.0f, 1.0f); // uniform scale splineKeyFrames[0] = new KBKeyFrame(0.0f, 0, p, head, pitch, bank, s,

0.0f, 0.0f, 0.0f);

p = new Point3f(pos1); head = 0.0f; // heading pitch = 0.0f; // pitch bank = (float) -Math.PI / 2.0f; // bank s = new Point3f(1.0f, 1.0f, 1.0f); // uniform scale splineKeyFrames[1] = new KBKeyFrame(0.2f, 0, p, head, pitch, bank, s, 0.0f, 0.0f, 0.0f);

p = new Point3f(pos2); head = 0.0f; // heading pitch = 0.0f; // pitch bank = 0.0f; // bank s = new Point3f(0.7f, 0.7f, 0.7f); // uniform scale splineKeyFrames[2] = new KBKeyFrame(0.4f, 0, p, head, pitch, bank, s, 0.0f, 0.0f, 0.0f);

p = new Point3f(pos3); head = (float) Math.PI / 2.0f; // heading pitch = 0.0f; // pitch bank = (float) Math.PI / 2.0f; // bank s = new Point3f(0.5f, 0.5f, 0.5f); // uniform scale splineKeyFrames[3] = new KBKeyFrame(0.6f, 0, p, head, pitch, bank, s, 0.0f, 0.0f, 0.0f);

p = new Point3f(pos4); head = (float) -Math.PI / 2.0f; // heading pitch = (float) -Math.PI / 2.0f; // pitch

bank = (float) Math.PI / 2.0f; // bank s = new Point3f(0.4f, 0.4f, 0.4f); // uniform scale splineKeyFrames[4] = new KBKeyFrame(0.8f, 0, p, head, pitch, bank, s, 0.0f, 0.0f, 0.0f);

p = new Point3f(pos5); head = 0.0f; // heading pitch = 0.0f; // pitch bank = 0.0f; // bank s = new Point3f(1.0f, 1.0f, 1.0f); // uniform scale splineKeyFrames[5] = new KBKeyFrame(1.0f, 0, p, head, pitch, bank, s, 0.0f, 0.0f, 0.0f); }

/* * This sets up the key frame data for the linear interpolator. Each knot * point has a scale and rotation component specified. The second argument * to KBKeyFrame (in this case 1) tells the interpolator that this is to be * interpolated linearly. The last three arguments to TCBKeyFrame are * Tension, Continuity, and Bias components for each key frame. */ private void setupLinearKeyFrames() { // Prepare linear keyframe data Point3f p = new Point3f(pos0); float head = 0.0f; // heading float pitch = 0.0f; // pitch float bank = 0.0f; // bank Point3f s = new Point3f(1.0f, 1.0f, 1.0f); // uniform scale linearKeyFrames[0] = new KBKeyFrame(0.0f, 1, p, head, pitch, bank, s,

0.0f, 0.0f, 0.0f);

p = new Point3f(pos1); linearKeyFrames[1] = new KBKeyFrame(0.2f, 1, p, head, pitch, bank, s, 0.0f, 0.0f, 0.0f);

p = new Point3f(pos2); linearKeyFrames[2] = new KBKeyFrame(0.4f, 1, p, head, pitch, bank, s, 0.0f, 0.0f, 0.0f);

p = new Point3f(pos3); linearKeyFrames[3] = new KBKeyFrame(0.6f, 1, p, head, pitch, bank, s, 0.0f, 0.0f, 0.0f);

p = new Point3f(pos4); linearKeyFrames[4] = new KBKeyFrame(0.8f, 1, p, head, pitch, bank, s, 0.0f, 0.0f, 0.0f);

p = new Point3f(pos5); linearKeyFrames[5] = new KBKeyFrame(1.0f, 1, p, head, pitch, bank, s, 0.0f, 0.0f, 0.0f); }

/* * This sets up alpha for the interpolator */ private void setupAnimationData() { yAxis = new Transform3D(); animAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0, duration, 0,

0, 0, 0, 0); }

/* * create a spline and a linear interpolator, but we will activate only one * in startInterpolator() */ private void createInterpolators() {

behaviorBranch = new BranchGroup();

// create spline interpolator splineInterpolator = new KBRotPosScaleSplinePathInterpolator(animAlpha, objTransformGroup, yAxis, splineKeyFrames); splineInterpolator.setSchedulingBounds(bounds); behaviorBranch.addChild(splineInterpolator);

// create linear interpolator linearInterpolator = new KBRotPosScaleSplinePathInterpolator(animAlpha, objTransformGroup, yAxis, linearKeyFrames); linearInterpolator.setSchedulingBounds(bounds); behaviorBranch.addChild(linearInterpolator); objTransformGroup.addChild(behaviorBranch);

/* * This activates one of the interpolators depending on the state of the * linear boolean flag which may be toggled by the user using the choice

* menu. */ public void startInterpolator() { if (animationOn) { if (linear) { splineInterpolator.setEnable(false); linearInterpolator.setEnable(true); } else { linearInterpolator.setEnable(false); splineInterpolator.setEnable(true); } } }

/* * Toggle animation */ public void actionPerformed(ActionEvent event) { Object source = event.getSource(); if (source == animateButton) { try { // toggle animation if (animationOn) { animationOn = false; splineInterpolator.setEnable(false); linearInterpolator.setEnable(false); animateButton.setLabel("Start Animation"); } else { animationOn = true;

startInterpolator(); animateButton.setLabel("Stop Animation"); } } catch (Exception e) { System.err.println("Exception " + e); } } }

/* * Toggle the interpolators */ public void itemStateChanged(ItemEvent event) { Object source = event.getSource(); ItemSelectable ie = event.getItemSelectable(); if (source == interpChoice) { try { if (ie.getSelectedObjects()[0] == "Spline") { linear = false; } if (ie.getSelectedObjects()[0] == "Linear") { linear = true; } startInterpolator(); } catch (Exception e) { System.err.println("Exception " + e); } } }

/* * Adjust the speed of the animations */ public void adjustmentValueChanged(AdjustmentEvent e) { int value = e.getValue(); duration = 6000 - (500 * value); animAlpha.setIncreasingAlphaDuration(duration); }

public static void main(String[] args) { Frame frame = new MainFrame(new Main(), 500, 600); } }

You might also like