Tell Friends about VRMLSite
Read VRML
News Yet?

The Marriage of Java and VRML

by Adrian Scott

Pioneering efforts to combine Java and VRML have lead the VRML community to embrace the Java/VRML connection in the 2.0 Specification of VRML.

There are four significant ways for VRML and Java to interact.

  • In VRML 2.0, Script nodes allow you to fashion nodes that are described by Java classes using the VRML 2.0 Java API. (Nodes are the building blocks of VRML worlds.)

  • Alternatively, you can use the VRML 2.0 Java API to link into a VRML world from outside the VRML file.

  • If you are using Netscape's Live3D VRML browser, you can use Netscape's LiveConnect architecture to link into a VRML world from a Java applet.

  • Or you could just write your whole browser in Java, as Dimension X has done with their Liquid Reality VRML toolkit. With LR, you can extend the browser in Java using its special API.

This article takes a brief look at these interactions between Java and VRML, with an in-depth look at the VRML 2.0 Java API through an example from Sony's Community Place VRML 2.0 browser. (For more information on applications of Liquid Reality, see our article on Liquid Reality: Physics and Locales by Christopher Blohm.)

Current VRML browsers which support Java are Dimension X's Liquid Reality, Netscape's Live3D, and Sony's Community Place (formerly known as CyberPassage). Dimension X and Netscape have their own special Java APIs. Sony's Community Place uses the VRML 2.0 Java API. The Sony team led the development of the VRML 2.0 Java API specification. Both Community Place and Liquid Reality are VRML 2.0 browsers.

Liquid Reality's Core package recently was licensed by Microsoft to form the underlying technology of Microsoft's VRML 2.0 support. Since Liquid Reality uses native methods, this means Microsoft essentially licensed the native methods only for Windows operating systems.



Why would you want to use Java with your VRML?

One excellent capability of Java is its simple networking classes. You can use this to write Java that will create VRML based on other data on the network. So you could create multi-user VRML worlds, visualizations of the Internet or visualizations of data warehouses.

You can also write corporate applications with virtual reality interfaces. You could even create CAD or VRML authoring software using VRML 2.0 and Java. I expect we soon will see a move to put authoring tools inside the VRML browser, rather than as external applications.



Why would you want to use VRML with your Java?

Anyone who's ever written or viewed a Java animation applet knows the pain of waiting for all of the animation frames and segments to download. And if you want to do 3-D animations with Java, you're really facing a challenge, both from a programming and graphic design standpoint.

VRML provides a specification of the entire 3D object and its basic properties. And savvy authoring combined with compression can give you delightfully small file sizes. Thus, you can achieve huge bandwidth savings plus cost savings by using a VRML world animated by a Java applet, rather than 2D GIF or JPEG images animated by a Java world.

As an example, on a project for Goldberg Moser O'Neill Advertising for Symantec Cafe's online Web advertising, Aereal did both image versions and VRML versions of a frog in a blender! The Java applet only took up 6K, but the 2D images took up almost 100K. However, the VRML version only took 5K compressed! With VRML 2.0 we can use the VRML version and a similarly sized Java applet and really let loose!



VRML 2.0 Script nodes

Using Script nodes in VRML 2.0, you can use Java classes to affect the VRML world. With Script nodes, you are essentially creating a new node, with associated fields and events. For instance, if you are creating a multi-user Script node, you might have the following properties.

  • eventIn for movements by the user,
  • eventOuts for movements of the current avatars,
  • eventOuts to transition for new avatars entering the world,
  • eventOuts for garbage collection of avatars who have left the world, and a
  • field for the number of avatars currently in the world

The Java class referenced by this Script node could do the "plumbing" in between, transmitting position changes to and from other users or a multi-user server over the network.

When it comes to programming the actual Java class for this Script node, fields and eventOuts correspond to properties of the class, while eventIns correspond to class methods. eventOuts can be referenced using their setValue() method. In addition there is a constructor method for the class. Plus there is also an eventsProcessed method, which will be called after a set of events has been received by the Script node.

Java classes for use with the Script node must import the vrml package. They also are extensions of the Script class in the vrml package, as shown below.

import vrml;
class MultiUser extends Script { 
     ...
}



VRML 2.0 Java API Example

As an example of how the VRML 2.0 Java API works, we'll look at "drive", which comes with Sony's Community Place VRML 2.0 browser. (Look in c:\Program Files\Sony\CyberPassage\contents\drive to find the files we'll be examining.) The world contains a car ("buggy") which can be started or stopped by touching it (i.e. clicking on it with the mouse). Once you start it, it moves around a course in a fixed route.


VRML Source

The overall VRML file, main.wrl, just inlines two worlds, buggy.wrl and world.wrl, which are inside the models directory. The file buggy.wrl contains the VRML description of the car, including the Script node which references the Java class, buggy.class, which is in the classes directory. The important lines are the following.

1  DEF SCRIPT Script{
2    url "classes/buggy.class"
3    scriptType "javabc"
4
5    eventOut SFRotation buggyRt
6    eventOut SFVec3f    buggyTr
7
8    eventIn SFTime moveBuggy
9    eventIn SFBool getOnOff
10 }


Let's look at this Script node line by line. In the first line, we define the Script node to be called by the name SCRIPT. This name is used at the bottom of the VRML file for the ROUTE statements which link the Script node outputs to the actual buggy geometry. The ROUTE statements will also link the TouchSensor on the buggy and a TimeSensor to the Script's input events.

The second and third lines are the url and scriptType fields of the Script Node. The url field gives the URL which contains the script code. The scriptType field indicates that the script is given in Java bytecodes at that URL.

The following lines, 5-9, define the interface of this script with the rest of the VRML world. First come the eventOuts. Line 5 defines an eventOut called buggyRt -- which can stand for buggy rotation -- of the type SFRotation. SFRotation is the VRML field type for rotations, which consists of four floats, the first three giving a vector, and the fourth giving a rotation angle in radians. The rotation works by rotating the default orientation ( 0 0 -1 or into the negative z axis, which is the direction you are facing in a VRML world by default when you load it up, assuming no alternate viewpoints have been set up) around the vector by the rotation angle.

The second eventOut is buggyTr -- which can stand for buggy translation -- of field type SFVec3f. Translation means movement, so this event is related to moving the buggy, as if we could pick it up and move it to a new position. The field type SFVec3f is a vector of three float numbers (like decimal numbers). The eventOuts will be generated by the Java class, buggy.class, giving the location of the buggy and the direction to point it in.

The eventIns are moveBuggy of field type time SFTime, and getOnOff of field type SFBool. These are messages that will be sent to the script from other parts of the VRML world. The eventIns correspond to methods in the Java class.


Java Source

We look next at the Java source code, buggy.java, which is included in the classes directory. Here is an outline of the source file.

// import vs (Sony) and vrml (VRML 2.0 Java API) packages
import vs.*;
import vrml.*;

public class buggy extends Script{
  // define variables

  // constructor method
  public buggy() {}

  // invoked every 350ms -- moves the buggy
  public void moveBuggy(ConstSFTime time, ConstSFTime ts) {}

  // get on/off the car. (opens link to HTML page)
  public void getOnOff(ConstSFBool arg, ConstSFTime ts) {}
}
First, the packages for the VRML 2.0 Java API and Sony's browser are imported. Then the class is defined. Note that it is a public class and that it extends Script. This is just analogous to applets extending the java.applet.Applet class. The three methods include the constructor method, buggy(), which is called when the class is first loaded, and the methods corresponding to the eventIns, moveBuggy() and getOnOff().


Java Variable Definitions

Here are the variable definitions from buggy.

 float aRad = (float) (Math.PI/180.0) ;

 // get the reference to the buggy.
 SFRotation buggyRt = (SFRotation)getEventOut("buggyRt");
 SFVec3f buggyTr = (SFVec3f)getEventOut("buggyTr");

 int count;
 boolean ride = false;
 float[] positionX;
 float[] positionY;
 float[] positionZ;
 float[] angle;
 float[] translation;
 float[] rotation;

 float   rotkeep = 0.0f ;
The properties buggyRt and buggyTr correspond to the eventOuts in the VRML file. The property ride is a true or false (boolean) variable which keeps track of whether or not the buggy is currently moving.

The arrays of floats (positionX[], positionY[], etc.) will be used in the constructor method to store the sequence of positions and orientations the buggy will move through.


Constructor Method

In the constructor method, buggy(), the method initializes creates instances of the arrays. Then it fills the positionX, positionY, positionZ and angle arrays with preset values of the course the buggy will drive through.

 // initialize
 public buggy()
 {

   positionX = new float[156];
   positionY = new float[156];
   positionZ = new float[156];
   angle = new float[156];
   translation = new float[3];
   rotation = new float[4];

   positionX[0] = 0f;
   positionY[0] = 0f;
   positionZ[0] = 0f;
   angle[0] = 8f;

   // 155 more sets of values are 
   // initialized in the above arrays

   // ...

   // initialize count.
   count = 0;
        
   // initial rotation.
   rotation[0] = 0.0f;
   rotation[1] = 1.0f;
   rotation[2] = 0.0f;
   rotkeep = 43.0f ;
   rotation[3] = rotkeep * aRad ;

   buggyRt.setValue(rotation);
 }
At the end of method (we omit the 155 repetitions of the array value settings), a few more variables are initialized. The variable count keeps track of what iteration the buggy is at in its run around the course. Then the initial orientation of the buggy is set, by passing the value of rotation to the setValue() method of object buggyRt.

Since buggyRt is associated with the eventOut of the Script node, this means that an eventOut message is generated and passed to the VRML world, and then routed (because of the ROUTE statement in the VRML file) to set the orientation of the buggy.

In this particular case, the buggy is only moving around a flat surface, which makes calculating the value of rotation rather easy. Remember, the first three values of an SFRotation are a vector. In this instance -- at the end of the constructor -- the vector is (0,1,0). The second number is y the vertical direction. Thus, the vector is just pointing straight up. The fourth value is the rotation angle of the car around this vector, which corresponds directly to the car turning left or right while moving on a flat surface.


The moveBuggy() method

The moveBuggy() method moves the buggy, by updating both the translation and the rotation of it. Remember that moveBuggy() corresponds to an eventIn property of the Script node, and the output translation and rotation correspond to eventOuts.

The method is called every time it receives an eventIn message. The eventIn message will contain two pieces of information:

  • a value called time of type SFTime.
  • the time stamp ts -- the time the message was sent at (A time stamp is a part of every eventIn).

A quick look back at the VRML file, buggy.wrl, reminds us where the second piece of information comes from.

ROUTE TOUCH_SENSOR.isActive TO SCRIPT.getOnOff
ROUTE TIME_SENSOR.cycleTime TO SCRIPT.moveBuggy

ROUTE SCRIPT.buggyTr TO BUGGY_TRANSFORM.set_translation
ROUTE SCRIPT.buggyRt TO BUGGY_TRANSFORM.set_rotation
It comes from a TimeSensor node in the VRML 2.0 world. You can think of the TimeSensor node as a clock or stopwatch that is keeping everything in the world organized and in sync, no matter what the real time is.

This stopwatch is what controls when to run the moveBuggy method -- in this case, every 350 milliseconds.

 // invoked every 350ms.
 public void moveBuggy(ConstSFTime time, ConstSFTime ts)
 {

   // move.
   if (ride) {
     translation[0] = positionX[count];
     translation[1] = positionY[count];
     translation[2] = positionZ[count];
     buggyTr.setValue(translation);

     // rotate.
     rotkeep += angle[count] ;
     rotation[3] = rotkeep * aRad;
     buggyRt.setValue(rotation);

     // count up.
     count++;
     if(count >= 156){
       count = 0;
     }
   }
 }
First, the method checks to see if the buggy is currently moving. If so, it creates an SFVec3f object containing the new position the buggy will move to. Then it passes this object to the setValue method of the buggyTr object, in effect creating an eventOut message.

Then it updates the rotation of the buggy, just as it did at the end of the constructor method. Finally it increments or resets the count counter to ready the class for the next movement using the preset array previously initialized.


The getOnOff() method

If you have Netscape started up when you start up Sony Community Place, the getOnOff() method can communicate with the browser using Sony's vs package that was imported at the beginning of the Java source file. This is the loadworld() method of the Browser object you see in the method source listing below.

  // get on/off the car.
  public void getOnOff(ConstSFBool arg, ConstSFTime ts)
  {
    if(true == arg.getValue()){
      // when the button is pressed, return immediately.
      return;
    }

    String s[] = {"html/drive.htm"};
    Browser.loadWorld(s);
    // the button is released.
    if(true == ride){
      ride = false;
    }else{
      ride = true;
    }
  }
Now, the beginning may seem confusing. What's happening is that the eventIn is coming from a TouchSensor node that has been routed to the Script node. TouchSensor nodes will transmit a "true" signal when a user touches an object in the world, and a "false" signal when the user stops touching the object.

So if the user is starting to touch the buggy (true == arg.getValue()), the method returns and doesn't do anything else. (However, if you were creating a car door that could be opened, you might want the method to do something while they were touching the car door.) When the user releases their touch (i.e. click and release the mouse), that's when we want the buggy to be affected.

In that case, the buggy will stop moving or start moving. The method adjusts this by changing the ride flag. Remember that the moveBuggy() method checks to make sure ride is true before it moves the buggy.

And that's all there is to buggy.class. Well -- now you're an expert on VRML 2.0's Java API. Congratulations!



Netscape's LiveConnect

Netscape's Live3D team has developed a plug-in API for Live3D that uses Netscape's LiveConnect architecture. This lets developers access VRML worlds through Java or JavaScript. Netscape has developed this as an intermediary step to their VRML 2.0 Java API. They will support both the required VRML 2.0 Java API, plus their own API. The current API will only work on Windows 95/NT.

To use LiveConnect, you create an HTML page with a VRML world embedded in it with the <EMBED> tag. Then you can also have a Java applet in the HTML page with an <APPLET> tag which communicates with the Live3D plug-in. Alternatively, you can use JavaScript to access the plug-in. For instance, you could create a form with <INPUT> tags set to "TYPE=BUTTON" and have the JavaScript calls in the ONCLICK field of the <INPUT> tag. When using LiveConnect, you will want to name the instance of the Live3D embedded world. You can do this using the NAME field of the <EMBED> tag, as follows.

<EMBED NAME="vrmlworld" SRC="http://www.aereal.com/home.wrl.gz" HEIGHT=100 WIDTH=100>

The API is heavily documented at Netscape's site. You may have trouble compiling LiveConnect Java source code if you are using Symantec Café. I ended up having to go back the Sun Java compiler. Either way, you need to make sure you have the Netscape Navigator and Live3D LiveConnect files set up in your CLASSPATH (for Windows 95/NT users).

C:\Program Files\Netscape\Navigator\Program\java\classes\java_30
C:\Program Files\Netscape\Navigator\Program\plugins\npl3d32.zip

Since this API is still bleeding edge (though much more stable than before!), you will probably also want to monitor the Live3D Newsgroup on Netscape's server. See the Live3D Web site for a link to the newsgroup.



Liquid Reality

Dimension X wrote the first combinations of Java and VRML with its Liquid Reality VRML Toolkit. Liquid Reality is now available in a VRML 2.0 version. You could try writing your own VRML browser in Java, or you could start with Liquid Reality and write your own VRML/Java with Liquid Reality. You can easily create your own nodes that are described by Java classes.


No matter which API you choose to start with, combining Java and VRML is lots of fun, and hey -- it sure beats double-buffering!




Resources:


Adrian Scott, Ph.D., adrian@aereal.com, is founder and CEO of Aereal Inc., and Publisher of VRMLSite magazine. He has previously been an Internet Specialist in Hewlett-Packard's Direct Marketing Organization, and a Visiting Scholar in the Department of Management at Hong Kong Polytechnic University. He is a co-author or contributing author to six Internet books, including Sams.net's Unleashed series. He is also Editor of SIGS Publishing's Java Professional Book Series and is a regular contributor to Java Report Magazine.


#VRML V2.0 utf8 | WorldInfo | ViewPoint | Shape
NavigationInfo | Java Chat | Subscribe | Tell Friends

© 1996 Aereal, Inc. Please send suggestions to suggest@vrmlsite.com.