Animation Through Interpolators and Alpha Objects

The Interpolator class extends Behavior that is used in conjunction with an Alpha object to provide animation to the scene graph. We use the term animation to refer to basically non-interactive changes to the scene graph.

The name Interpolator reflects the use of these classes in interpolating between sets of values. We all remember having to interpolate tables and such in math class. This idea is the same. Often, the programmer will specify two values, and the Interpolator will provide a smooth set of values between the pair. Other Interpolators can have a variable number of points called knots to interpolate between.

Note that Interpolators are almost always considered with respect to an Alpha value. In rare cases, an Alpha object is used alone; however, the two are intended to be used together.

The role of the Alpha object is to map time to the referencing Interpolator. In other words, the purpose of the Alpha object is to scale (normalize) time into a series of values between 0 and 1 and to map those values to other objects (especially Interpolators) as input. The scaled time values are called the Alpha values.

Interpolator/Alpha pairings are generally used for ballistic events; that is, events that are triggered and run to completion without further changes. The typical example of a ballistic event is the firing of a missile. Once the missile is launched, little can be done to change the course of events (modern guided missiles notwithstanding). Regardless, the general idea is to turn on the Interpolator and let it go. We note, however, that in Java 3D version 1.3, Interpolators do allow for starting and stopping of their action through the pause() and resume() methods.

Existing Interpolators

Java 3D provides a number of prewritten Interpolators as part of the base API in javax.media.j3d.Behavior.Interpolator as well as extensions of these as part of the utilities in com.sun.j3d.utils.behaviors.interpolators. Note that as of Java 3D v 1.3, there are new methods to pause and restart Interpolators. Interpolators used for rotating or translating objects in the scene graph extend the abstract class TransformInterpolator. The ColorInterpolator and SwitchInterpolator classes still extend Interpolator.

Specifying Alpha Objects

To examine Alpha objects in more detail, consider some arbitrary function of time f(t) = 10*t. Table 12.3 shows this very simple relationship that would have two columns, one containing the value of f(t) and the other containing discrete values of t.

Table 12.3. Sample Table for f(t) and Alpha Evaluated at Different Values of t
f(t) (seconds) t (seconds) Alpha
0 0 0.0
10 1 0.01
20 2 0.02
990  0.99
1000 100 1.0

In this particular example, computation of the Alpha object is simple because the time points are equidistant and therefore could be easily specified in a Behavior with a wakeupOnElapsedTime() wakeup condition. Indeed, all the Interpolators can be specified in this way.

To understand the Alpha object, it is important to understand two mappings (input-output pairings) that are computed for each Alpha object. The first is termed the time-to-Alpha mapping and describes how the Alpha value, restricted to the range of 0-1 floating point, relates to time (which is, of course, continuous). The second mapping, Alpha-to-value, specifies how the Alpha values relate to changes in the Java 3D object (for example, TransformGroup, Color, or Switch).

Indeed, the Alpha class can be used to produce almost any time sequence. For example, the setPhaseDelayDuration() method is used to specify a period of time before the interpolation begins. A fixed (or infinite) number of loops can be specified using the setLoopCount() method. (Note that setting the LoopCount to -1 specifies infinite looping.)

Specifying Knots

Knots are much like key frames. In a complex sequence of movements, knots specify where the object is to be at different times in the sequence. In Listing 12.16, knots are used in conjunction with the Interpolator to specify some interesting movements of a cube through space.

The important thing to remember when using knots is that the first and last knots in the sequence are 0.f and 1.f, respectively. Furthermore, a sequence of knots always progresses upward (for example, knot 2 is higher than knot 1, knot 3 is higher than knot 2, and so on).

The InterpolationPlotter Example

Partly because there are so many options that can be specified in an Alpha object and further because we want to demonstrate the interaction between an Alpha object and its Interpolator, we provide an example program for experimentation. In Listing 12.16, the InterpolationPlotter application allows the user to create Alphas and then instantiate one of several Interpolators to see the results.

Listing 12.16 InterpolationPlotter.java
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.event.*;
import java.awt.GraphicsConfiguration;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.Box;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.geometry.Primitive;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
import javax.media.j3d.*;
import javax.vecmath.*;
import javax.swing.*;
//import javax.swing.JScrollPane.ScrollBar;
import java.util.Random;
import javax.media.j3d.Text3D;

import java.awt.*;
import javax.swing.border.*;

public class InterpolationPlotter extends JFrame {
  VirtualUniverse universe;
  Locale locale;
  TransformGroup vpTrans, geoTG;
  View view;
  Bounds bounds;
  InterpPlot2D ip2d;
  JButton newAlpha, newRandomInterp;
  Alpha a;
  Random r = new Random();

  int n_knots;
  Quat4f[] quats;

  float[] knots;

  Point3f[] points;

  JRadioButton inc_alpha_enabledButton, dec_alpha_enabledButton, 
inc_dec_alpha_enabledButton;
     private String fontName = "TestFont";
  BranchGroup scene;

  WholeNumberField phaseDelayDuration,triggerTime,
                   increasingAlphaDuration, decreasingAlphaDuration,
                   increasingAlphaRampDuration, decreasingAlphaRampDuration,
                   alphaAtOneDuration, alphaAtZeroDuration,
                   n_points, n_loops;

  public BranchGroup createSceneGraph(boolean newPath) {

        // Create the root of the branch graph; this will be returned
        Appearance app = new Appearance();
        BranchGroup objRoot = new BranchGroup();
        objRoot.setCapability(BranchGroup.ALLOW_DETACH);


        geoTG = new TransformGroup();
        geoTG.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        geoTG.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);

        TransformGroup boxTG = new TransformGroup();
        boxTG.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        boxTG.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);

        geoTG.addChild(boxTG);

        BoundingSphere bounds =
             new BoundingSphere(new Point3d(0.0,0.0,0.0), 1000.0);

        MouseRotate mouseBeh = new MouseRotate(geoTG);
        geoTG.addChild(mouseBeh);
        mouseBeh.setSchedulingBounds(bounds);

        PlotBehavior pb = new PlotBehavior(this);
        pb.setSchedulingBounds(bounds);
        objRoot.addChild(pb);

        Transform3D yAxis = new Transform3D();

        knots[n_points.getValue()-1]=1.f;
        for (int ii=1; ii<n_points.getValue()-1; ii++) {
          knots[ii] = (float)ii/(float)(n_points.getValue()-1);
          System.out.println("ii: " + ii + " knots[ii]: " + knots[ii]);
        }

        if (newPath==true) {

           for (int ii=0; ii<n_points.getValue(); ii++) {
              quats[ii] = genRandomQuat();
              points[ii] = genRandomPoint();
           }
        }
         for (int ii=0; ii<n_points.getValue(); ii++) {
            String label = " " + ii;
            geoTG.addChild(MakeLabels(label,points[ii]));
         }

. . .

         PointArray pathLine = new PointArray(n_points.getValue(),GeometryArray.
COORDINATES);
         pathLine.setCoordinates(0, points);
         Shape3D path = new Shape3D(pathLine, app);
         geoTG.addChild(path);

         for (int ii=0; ii<n_knots; ii++) {
           String label = " " + ii;
           geoTG.addChild(MakeLabels(label,points[ii]));
         }

         RotPosPathInterpolator interp =
                 new RotPosPathInterpolator( a,
                       boxTG,
                  yAxis,
                  knots,
                  quats,
                  points);


        PositionPathInterpolator interp =
           new PositionPathInterpolator(a, geoTG, yAxis, knots,points);

 */

        interp.setSchedulingBounds(bounds);

        objRoot.addChild(interp);

        boxTG.addChild(new ColorCube(.8f));
        objRoot.addChild(geoTG);

        Color3f blue = new Color3f(0.f, 0.9f, 0.f);
        Vector3f bluedir  = new Vector3f(0.0f, -8.0f, -8.0f);

       // AmbientLight al = new AmbientLight(true, new Color3f(.1f,.9f, .1f));
        AmbientLight al = new AmbientLight();

        DirectionalLight bluelight = new DirectionalLight(blue, bluedir);

        objRoot.addChild(al);

       objRoot.addChild(bluelight);

    return objRoot;
     }

     public BranchGroup createViewGraph() {

         BranchGroup objRoot = new BranchGroup();

     Transform3D t = new Transform3D();
     t.setTranslation(new Vector3f(0.0f, 0.2f,30.0f));
     ViewPlatform vp = new ViewPlatform();
     TransformGroup vpTrans = new TransformGroup();
         vpTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
     vpTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
     vpTrans.setTransform(t);
     vpTrans.addChild(vp);
     view.attachViewPlatform(vp);

         NavigationBehavior nav = new NavigationBehavior(vpTrans);
         vpTrans.addChild(nav);
         nav.setSchedulingBounds(bounds);

         objRoot.addChild(vpTrans);
         return objRoot;

   }

   public TransformGroup MakeLabels(String s, Point3f p) {

        Font3D f3d = new Font3D(new Font(fontName, Font.PLAIN, 1),
                                new FontExtrusion());

        int sl = s.length();

        Appearance apText = new Appearance();


        Text3D txt = new Text3D(f3d, s, p);
        Shape3D textShape = new Shape3D();
        textShape.setGeometry(txt);
        textShape.setAppearance(apText);

   // Using billboard behavior on text3d

        TransformGroup bbTransPt = new TransformGroup();
        bbTransPt.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        bbTransPt.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
        Billboard bboardPt = new Billboard( bbTransPt );
        geoTG.addChild( bboardPt );
        BoundingSphere bounds =
        new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);

        bboardPt.setSchedulingBounds( bounds );
    bboardPt.setAlignmentMode(Billboard.ROTATE_ABOUT_POINT);

    Point3f rotationPt = new Point3f(0.0f, 5.0f, 0.0f);
    bboardPt.setRotationPoint(p);
        bbTransPt.addChild( textShape );

        return bbTransPt;
    }

   public Point3f genRandomPoint() {
       float x = r.nextFloat()*15;
       float y = r.nextFloat()*15;
       float z = r.nextFloat()*15;
       Point3f p = new Point3f(x,y,z);
      // System.out.println("Point3f is made of x: " + x + " y: " + y + " z: " + z);
       return p;
   }

   public Quat4f genRandomQuat() {

       float x = r.nextFloat()*200;
       float y = r.nextFloat()*200;
       float z = r.nextFloat()*200;
       float w = r.nextFloat()*1;
       Quat4f q = new Quat4f(x,y,z,w);
      // System.out.println("Quat4f is made of x: " + x + " y: " + y + " z: " + z + "w: " 
+ w);
       return q;
   }

   public InterpolationPlotter() {
    super("Interpolation Plotter");

. . .
        universe = new VirtualUniverse();
    locale = new Locale(universe);

        GraphicsConfigTemplate3D g3d = new GraphicsConfigTemplate3D();
        GraphicsConfiguration gc=
        GraphicsEnvironment.getLocalGraphicsEnvironment().
                      getDefaultScreenDevice().getBestConfiguration(g3d);

    Canvas3D c = new Canvas3D(gc);

. . .
        plotpanel.add(c);
        PhysicalBody body = new PhysicalBody();
    PhysicalEnvironment environment = new PhysicalEnvironment();
    view = new View();

    view.addCanvas3D(c);
    view.setPhysicalBody(body);
        view.setPhysicalEnvironment(environment);
    // Create a simple scene and attach it to the virtual universe

        bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);
        scene = createSceneGraph(true);
        BranchGroup vgraph = createViewGraph();

        locale.addBranchGraph(vgraph);
    locale.addBranchGraph(scene);

    }

    public void newAlpha() {
       System.out.println("new Alpha");

       a = new Alpha(-1,
                      Alpha.INCREASING_ENABLE | Alpha.DECREASING_ENABLE,
                      //Alpha.DECREASING_ENABLE,
                      triggerTime.getValue(),
                      phaseDelayDuration.getValue(),
                      increasingAlphaDuration.getValue(),
                      increasingAlphaRampDuration.getValue(),
                      alphaAtOneDuration.getValue(),
                      decreasingAlphaDuration.getValue(),
                      decreasingAlphaRampDuration.getValue(),
                      alphaAtZeroDuration.getValue());
    }

    public void resetScene() {
      scene.detach();
      ip2d.setNewAlpha(a);
      ip2d.refreshPlot();
      scene = createSceneGraph(false);
      locale.addBranchGraph(scene);
    }

    public void newScene() {
        scene.detach();
        quats = new Quat4f[n_points.getValue()];
        knots = new float[n_points.getValue()];
        points= new Point3f[n_points.getValue()];
        scene = createSceneGraph(true);
        locale.addBranchGraph(scene);

    }

. . .

Figure 12.9 shows the screen output for InterpolationPlotter. The InterpolationPlotter program allows for the adjustment of several parameters of the Alpha object to be manipulated. The program also allows for placement of the knots.

Figure 12.9. Screen output for InterpolationPlotter.


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset