CSc 474 Labs


Lab 4: Distance Control




/*
 *  Lab exercise 4.0
 *  CSc 474, Computer Graphics
 *  Copyright 2002 Chris Buckalew
 *
 * This lab gives you the code to do the simple 1-D Bezier that we
 * used as an example in class, using 10 steps to go from one end to
 * the other.   
 *
 * 1) Create an array and evaluate and store many points along the curve,
 *    along with the t values and the total distance traveled.  Start out
 *    with 20 steps so you can compare the results with what we did in class.
 *    Make sure that D(1.0) = 25 for this curve.
 *
 * 2) Create another array to store the t values for 10 equal steps along
 *    the curve.  Compute these steps by just searching out the bracketing
 *    values for the desired distance and picking the nearest.  To display
 *    the motion, use the frame number as an index into this array, pull
 *    out the t value stored there, and plug that value into the curve.
 *    Before you go on, make sure the motion looks like equal steps.
 *
 * 3) Increase the quality of the motion by increasing the size of the
 *    distance table.  See what size seems to give good results without
 *    being too big.
 *
 * 4) Finally, increase the number of steps in the animation from 10 to 100
 *    in the same length of time.  You'll likely also have to increase the
 *    distance table size as well to give smooth results.
 *    
 *
 *------------------------------------------------------------*/

import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.GraphicsConfiguration;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import java.io.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.*;
import java.awt.Font;
import com.sun.j3d.utils.behaviors.mouse.*;

public class DistanceControlLab extends Applet
                   implements ActionListener {
                          
   private Timer animControl;
   private int frame, startFrame, endFrame, increment;
   static Transform3D tempTrans;
   private TransformGroup cubeTrans;

   public DistanceControlLab() {
      setLayout(new BorderLayout());
      GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();

      Canvas3D c = new Canvas3D(config);
      add("Center", c);

      // Create a simple scene and attach it to the virtual universe
        BranchGroup scene = createSceneGraph();
        SimpleUniverse u = new SimpleUniverse(c);

        tempTrans = new Transform3D();
      frame = 0;
        startFrame = 0;
        endFrame = 10;
        increment = 1;

      animControl = new Timer(150, this);  
      animControl.start();
   
      // This will move the ViewPlatform back a bit so the
      //      objects in the scene can be viewed.
      u.getViewingPlatform().setNominalViewingTransform();

      u.addBranchGraph(scene);
    
   }

   private BranchGroup createSceneGraph() {
    
      // Create the root of the branch graph
      BranchGroup objRoot = new BranchGroup();

      // Create light source
      // first bound its influence
      BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0),100.0);
    
      // now make the light itself
      DirectionalLight light = new DirectionalLight(new Color3f(1.0f, 1.0f, 1.0f),
                                                 new Vector3f( 0f,0f,-1f));
      light.setInfluencingBounds(bounds);
      objRoot.addChild(light);
    
      // make the transform that moves the whole model
      TransformGroup modelTrans = new TransformGroup();
    
      Transform3D trans = new Transform3D();
      // initially move it away from camera
      trans.setTranslation(new Vector3d(0d, 0d, -10.0d));
      // and shrink everything so it fits in field of view
      trans.setScale(new Vector3d(0.3d, 0.3d, 0.3d));
      modelTrans.setTransform(trans);

      // necessary so mouse movements can read and change transform
      modelTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
      modelTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
    
      // Create the rotate behavior node
      MouseRotate modelRot = new MouseRotate();
      modelRot.setTransformGroup(modelTrans);
      modelTrans.addChild(modelRot);
      modelRot.setSchedulingBounds(bounds);

      // Create the zoom behavior node
      MouseZoom modelZoom = new MouseZoom();
      modelZoom.setTransformGroup(modelTrans);
      modelTrans.addChild(modelZoom);
      modelZoom.setSchedulingBounds(bounds);

      // Create the translate behavior node
      MouseTranslate modelTranslate = new MouseTranslate();
      modelTranslate.setTransformGroup(modelTrans);
      modelTrans.addChild(modelTranslate);
      modelTranslate.setSchedulingBounds(bounds);

      modelTrans.addChild(generateLinearCube());

      objRoot.addChild(modelTrans);
        return objRoot;
   }

   public void actionPerformed(ActionEvent e)
   {
      // This function is called for each frame of animation
      if ((Timer)e.getSource() == animControl) {
    
         double t = (double) (frame - startFrame) / (endFrame - startFrame);
   
         //this implements linear interpolation on the translation
         double x, y, z;
    
         x = (1-t)*(1-t)*-10.0 + 2.0*t*(1.0-t)*20 + t*t*10.0;
         y = 0.0;
         z = 0.0;

         tempTrans.setTranslation(new Vector3d(x, y, z));

         cubeTrans.setTransform(tempTrans);

         if (frame == endFrame) increment = -1;
         else if (frame == startFrame) increment = 1;
    
         frame = frame + increment;
      }
   }
 
   private TransformGroup generateLinearCube()
   {
      // Generate the cube that moves linearly
    
      cubeTrans = new TransformGroup();
      cubeTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

      Transform3D trans = new Transform3D();
      trans.setTranslation(new Vector3d(0.0d, 0.0d, 0.0d));
      cubeTrans.setTransform(trans);
      
      // Make the cube's color
      Color3f black = new Color3f(0.0f, 0.0f, 0.0f);
      Appearance cubeApp = new Appearance();
      cubeApp.setMaterial(new Material(black, black, new Color3f(1.0f,1.0f,1.0f), black, 0f));

      com.sun.j3d.utils.geometry.Box cube =
         new com.sun.j3d.utils.geometry.Box(0.5f, 0.5f, 0.5f, cubeApp);
      cubeTrans.addChild(cube);
    
      return cubeTrans;
   }
 
   // The following allows DistanceControlLab to be run as an application
   //     as well as an applet
   public static void main(String[] args) {
      new MainFrame(new DistanceControlLab(), 500,500);
   }
}