Mega Code Archive

 
Categories / Java / 3D Graphics
 

Spline Animation

/*  * @(#)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);   } }