/*
* @(#)SplineAnim.java 1.13 02/10/21 13:55:30
*
* Copyright (c) 1996-2002 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
* IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
* NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
* LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
* LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
* INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
* CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
* OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGES.
*
* You acknowledge that Software is not designed,licensed or intended for use in
* the design, construction, operation or maintenance of any nuclear facility.
*/
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 SplineAnim 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 SplineAnim() {
}
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(0.0f, 0.0f, 0.0f);
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_WRITE);
sceneTransformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
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_WRITE);
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 SplineAnim(), 500, 600);
}
}
|