Areas
  • J3D FAQ
  • Tutorials
  • Utilities
  • Books
  • News
  • Other Sites
  •  Chapters
  • TOC
  • Getting Started
  • Lighting
  • Textures
  • Behaviours
  • User Feedback
  • Navigation
  • Audio
  • Input Devices
  • No Monitors
  •  Sections
  • Chapter TOC
  • Behaviour Fundamentals
  • Built-in Behaviours
  • Summary
  •   

    Interpolators

    © Justin Couch 1999

    Previously we mentioned the use of interpolators as behaviours. Despite their apparently simple nature, they are quite sophisticated in what they can provide the user. As mentioned earlier, an interpolator takes an input, usually time based, and produces an output appropriate to the type of interpolator. When producing time based interpolated routines, you can wire up several of these in parallel to produce a very interesting and complex output.

      

    Interpolator Basics

    Say we have a path as indicated in Figure 5. This path is the real path that we need to travel in a car to get from point A to point B. Most of the time we need to travel in straight lines, only when we get to a corner will the direction change. We need to build an application that will show that output to a user.

    A path through objects
    Figure 5: A path that we want to travel

    One option in our application is to set up a behaviour that wakes on every frame. For that frame it looks up the next position based on what frame number we are at and moves the view to that position. While this runs really nicely on your machine, the users complain that it is really jerky or runs in contravention to the laws of physics. Apart from that, your server gets overloaded from the amount of calculation it needs to do to present every single point. Obviously this is not really ideal.

    The users are experiencing this behaviour because you based everything on a per-frame basis. Every machine has different frame rates simply because of different CPU speeds, amount of memory or video card.

    An easier solution to the problem is to just provide the corner values and let "the system" work out all the positions in between - that is what an interpolator does.

    The basic interpolator is just a set of key/value pairs. So if we strip all the map part from the image we are left with Figure 11-6 a series of known positions and the time it should take us to travel between each position.

    Just the path information
    Figure 6: The path from figure 5 stripped to the important waypoints

    That leaves us with a series of values:

    T1 T2 ... T7
    X1, Y1 X2, Y2 ... X7, Y7

    When the interpolator is given a key that is between T1 and T2 it will produce the corresponding value proportionally distant between X1,Y1 and X2, Y2.How it determines what that output value is, is dependent on the type of interpolator. For positional information it is just a simple linear interpolation of the values. However, for color interpolation there are a number of different color spaces that may be used to interpolate between any two color values. For example, two RGB color values may use either RGB space or HSV space - each of which result in totally different output color values for the same key.

    Time and Alpha

    In Java3D parlance, the key is called an Alpha and is encapsulated in its own class. Alpha values are used as the glue between the system time and the key values for interpolators. With the Alpha class, you can control exactly how to interpret time and control the output anywhere from a one-shot animation to continually looping value.

    The Alpha class treats time as a value between 0 and 1. At zero, the time is just beginning. A value of 1 indicates that the period that the animation cycle is complete. All time is represented by a value in between. If we wanted to perform the same animation for a number of cycles, the alpha value would run between 0 and 1 for the number of cycles.

    On first contact the Alpha class can look quite daunting. With the help of figure 7, hopefully we will clear up much of the confusion. Note that as always, time is represented in milliseconds.

    Complex picture of the Alpha class timing
    Figure 7: Diagrammatic representation of the field values of the Alpha class.

    • loopCount: The number of loops to execute. If the value is -1 then it will loop indefinitely.
    • triggerTime: Java3D works on the elapsed time since the application started. Note that this is a bit different to most other APIs that work on current system time. The default start time is the time that the Java3D execution engine starts running, although it is possible to explicitly set it yourself.
    • phaseDelayDuration: The amount of delay after the start time that the Alpha should begin running. This time only occurs once when the behaviour is first executed. Every cycle after the first cycle is not effected by this delay.
    • increasingAlphaDuration: The total amount of time that the interpolator spends increasing the value from 0 to 1. If the decreasingAlphaDuration value is non-zero then the total output of the of the interpolator will look like a triangular wave. If it is zero then you get a saw tooth style output where upon reaching the value 1, the output immediately drops to zero again. During this second portion, the output of the interpolator will appear to be running backwards. For example, if you have a path defined, the object will run along the path in the opposite direction.
    • increasingAlphaRampDuration: It is possible to provide accelerative parts of the time increase and decrease. During this time, the value of output begins to accelerate to the desired value of interpolation. This value is, by necessity, limited to half of the total time for the increasing alpha duration because you also need the symmetrical deceleration. The corresponding time value for the return is decreasingAlphaRampDuration.
    • alphaAtOneDuration: The time that the output of the alpha output value stays at 1. Following the end of this interval, the alpha output will either immediately start at 0 and start increasing again, or it will start the decreasingAlphaDuration section.

    Using Interpolators

    For most applications, there will be little need to specify all of these values. Typically you will only want to define the trigger time, whether or not to loop and the increasing alpha duration. To illustrate in code what you need to do to get an interpolator going, we’ll make our geometry example from the previous chapter spin.

    The first step in using any interpolator is making sure that there is an instance of the object that you need to manipulate already created. When you look at the RotationInterpolator you will notice that the constructor requires a TransformGroup instance. In order to make the object rotate, we need to change the parent transform of that object. As our example code illustrates, we only have the Shape3D object to use. That means making some minor modifications to the test frame code to give the geometry a TransformGroup parent.

    // add some geometry
    GeometryTest geom = new GeometryTest();
    TransformGroup tg = new TransformGroup();
    tg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
    tg.addChild(geom);
    
    // Create the behaviour
    
    universe.addWorldObject(tg);
    
    Notice that we’ve also had to enable the capability to write the transform. This should seem fairly obvious because we need to be constantly changing the transform to make the object rotate.

    Next we need to build the behaviour and all the supporting classes. The default implementation of the rotation interpolator is to circle between 0 and 2pi meaning that we don’t need to do anything special. Since this is the case, the Alpha class only needs increasing values and should loop indefinitely. Also, because we want simple rotation we don’t need any ramp values either. If we call our class BehaviourTest, we start with the following constructor code:

    public BehaviourTest(TransformGroup tg)
    {
      Alpha alpha = new Alpha(-1, 5000);
    
      RotationInterpolator rotator = new RotationInterpolator(alpha, tg);
    
      tg.addChild(rotator);
    }
    
    The constructor used in the Alpha class creates the basic saw-tooth shaped output that we discussed in the previous section. The value of -1 for the first argument says to loop forever, while 5000 indicates that a period of 5 seconds should be used (remember the values are in milliseconds). If you just compiled and ran this code you would notice that nothing happens. Remember earlier in the chapter the discussions about scheduling bounds? Well, the default implementation provides no bounds, so we need to explicitly create them. For the purposes of this exercise, a spherical bound of radius 100 should do us quite well. The following code is then inserted just before the last line of the previous example:
    Point3d origin = new Point3d(0, 0, 0);
    Transform3D axis = new Transform3D();
    
    BoundingSphere bounds = new BoundingSphere(origin, 100.0);
    rotator.setSchedulingBounds(bounds);
    

    Standard Interpolators

    Moving positions is not the only sort of interpolator that you can define:
    • RotationInterpolator: Used to control orientation changes in an object. By setting three points of zero, pi and 2 pi (using the default constructor creates this example) we can make an object spin automatically with minimal extra code.
    • ScaleInterpolator: Used on a scalar value to control the size of an object. It provides a uniform scaling factor to the nominated TransformGroup.
    • PathInterpolator: The combination of the previous two interpolators. There are various subclasses that allow you to construct a path and control how the user moves along it, rotates around and maybe even scale objects as needed. Using this one behaviour, you have a ready built restricted Amusement Park style tour navigation paradigm. By applying appropriate offsets of the camera you could also build second and third person navigation systems too.
    • SwitchValueInterpolator: interpolates between integer indexes of a switch node to control the swapping of values. Typically used to implement the LOD style behaviour
    • TransparencyInterpolator: Used to interpolate between completely opaque objects and transparent. Useful for building window/mirrored glass type systems.
    • ColorInterpolator: Used to transition between two colors. Usually great for slider type UI controls in furniture viewing type applications to view the different options.

      

    [ TOC ] [ Home ] [ FAQ ] [ Books ] [ Tutorials ] [ Utilities ] [ Contact Us ]