VRMLSite

Subscribe for FREE

Discussion Area


VRML 2.0 URLs
VRML by the Pound

People Linking to Us
Tell a Friend

We'll Link to You!!

Aereal, Inc.
Instant VRML World
Proteinman's Top Ten VRML Worlds

BackContentsNext
view me!


Java and VRML 2.0 Part 1: Basic theory
by Rodger Lea

So, you've written a PROTO node, played around with touchsensors, and maybe even written a spinning cube. What next? 'Cos frankly, VRML is starting to look a little boring. The problem is that it's easy to get locked into a mindset that views VRML as a self contained system. Instead, if you start to think of VRML as a display engine for applications then you're starting to break out of the closed mindset. VRML applications should allow you to query databases and display results, interact with users via pop up menus, display your disk contents, access the web, work with others. To do all of this you need to combine VRML with a fully fledged programming language, such as Java, and these articles will show you how.

In our first article we'll give you a techie's overview of the VRML 2.0 execution model and how Java can interact with VRML. The second article will build on this to show you how to start writing serious applications that use VRML to display results.

Both these articles are based on our book, Java for 3D and VRML worlds, Lea, Matsuda, Miyashita, New Riders (ISBN 1-56205-689-1) and are taken from early chapters. Later chapters discuss the use of Java in more detail with full examples of Java windowing, a VRML directory browser and a multiuser VRML server using Java networking code.

Community Place

NOTE: You'll need a VRML browser that supports Java. We recommend Community Place.

the VRML execution model isn't sophisticated

The execution model
Unlike VRML 1.0, VRML 2.0 supports behaviors, doing so through an internal execution model; an execution model is a way to manipulate the basic data structures that VRML offers: its internal nodes or new nodes that you define with PROTOs. The VRML execution model isn't sophisticated; it's simply an event mechanism that allows you to propagate data values, as events, between fields of nodes. The source and target for these events are specified using the ROUTE construct. Although this model is simple, it is quite powerful when used in conjunction with existing nodes and allows you to build simple animation and behaviors completely within VRML. However, one of the reasons that VRML 2.0 architects kept the execution model simple was because they wanted it to work in conjunction with full-fledged programming languages, which would provide it with the more sophisticated facilities such as comparison, looping and I/O.

A quick recap
We assume that people reading this article have a basic knowledge of the way that VRML 2.0 can be used to create dynamic scenes, but for those of you who may be sketchy on the details, here is a quick recap.

Nodes, fields and routes
VRML 2.0's built-in nodes consist of a name and a set of fields. Each field has a both category and a type. The type of the field defines the data that it can hold, e.g. integers or strings. The category of the field defines whether you can set, read or write the field.

Fields of category Field are set at definition time by the scene author and only change again when written; they can be read but don't generate events.

written to. When this happens, the field is set to a new value, and an event that contains the new value is generated.

eventIn fields receive events. The value of the event is used to set the value of the eventIn field. A special type of field, an exposedField, is actually a shorthand method of saying that a field is both an eventIn and an eventOut; i.e, it can be both source and target for events. Once we have a mechanism to allow fields to change, then we need a way to send the events between these fields. The ROUTE mechanism is designed to do that. It specifies a source field and a target field for an event. By using a ROUTE, a scene author can specify an eventOut field as the source of an event and "route" that event to an eventIn field. By chaining eventIns to eventOuts, the author can build chains of events, or event cascades, that propagate data from node to node throughout the scene. Since these fields are also used by the browser to display the scene; any changes in their values are shown by the browser next time it renders the scene.

Obviously, you must have a source event to start an event cascade

Sourcing events, sensors and interpolators
Obviously, you must have a source event to start an event cascade. VRML 2.0 provides two ways to create source events: Sensor nodes and Interpolator nodes. Sensors track some external entity, e.g. the mouse or time, and generate events as that external entity changes value. Interpolators (which are usually used in conjunction with sensors) generate values between defined starting and ending points, which can then be used as events. These initial events can then be routed through to the rest of the scene in the normal way.

Here is a simple example that allows you to turn on a light when the mouse button is held down and turn it off when the button is released. Line 9 defines a PointLight and line 14, a light shade. Line 26 defines a TouchSensor which is attached to the light because it is defined within the same Transform node. Line 38 sets up the ROUTE between the TouchSensor named LIGHT_ON_SWITCH and the PointLight named LIGHT. When the mouse clicks on it, the TouchSensor generates an isActive event with a value of TRUE, which is then routed to the PointLight setting its "on" file to TRUE also. When the mouse button is released, the TouchSensor generates a FALSE event which causes the light to be switched off.

1   #VRML V2.0 utf8
2
3   #
4   # turn on/off the light by pressing/releasing the mouse button.
5   #
6   
7   Transform{
8           children[
9           DEF LIGHT PointLight{
10                   on FALSE           # initially the light is turned off.
11           },
12           Transform{
13                   translation 0 1 0
14                   children[
15                           # lamp shade
16                           DEF LAMP_SHADE Shape{
17                                   geometry Cone{
18                                           height 2
19                                           bottomRadius 4
20                                           bottom FALSE
21                                   }
22                           }
23                   ]
24           },
25           # sensor to turn the light on / off
26           DEF LIGHT_ON_SWITCH TouchSensor{}
27           ]
28   }
29
30   # dummy object to reflect the light.
31   Transform{
32           translation 0 -5 0
33           children[
34                   Shape{geometry Box{size 10 0.3 10}}
35           ]
36   }
37
38   ROUTE LIGHT_ON_SWITCH.isActive TO LIGHT.on

To be able to perform these more complicated logic operations, you must use a programming language

Using Java
The basic method to building dynamic scenes is to route events between fields in an arbitrary fashion and combineg that facility with sensor and interpolator nodes, as just described. However, because you are restricted to only being able to route a data item from one node to another, you won't be able to handle a whole class of behaviors. For example, you can't use this method to determine if the value of position interpolator is greater than a certain value, and if so, negate the value. To be able to perform these more complicated logic operations, you must use a programming language.

Bridging from VRML to programs - the Script node
The Script node allows you bridge from VRML to access a programming language while allowing your world to be independent of the language you are trying to access. The Script node is similar to any other VRML node in that it has a name and a set of pre-defined fields. However, it is different in that it can also have a set of user defined fields. These fields are special because events sent to them will be automatically passed, by the VRML browser from the Script node, to an associated piece of programming code.

Here is the specification of the Script node:

 
Script { 
  exposedField MFString url           [] 
  field        SFBool   directOutput  FALSE
  field        SFBool   mustEvaluate  FALSE
  # And any number of:
  eventIn      eventTypeName eventName
  field        fieldTypeName fieldName initialValue
  eventOut     eventTypeName eventName
}

The key field is the url field. This defines the name and location of the program that 'manages' this Script node. Since this article is about Java, we'll assume for the rest of the examples that the program specified is a Java program. However, VRML 2.0 is open; the Script node can be managed by any language that the VRML browser supports.

The user defined fields of a Script node are no different from the fields of any other nodes; they can be of category field, eventIn or eventOut and can be routed to and from in the usual way. They can't be of category exposedField because of the complications that would impose on the execution model.

The event handler class - Java code to handle Script Nodes
The Java side of the picture is a piece of Java code that we refer to as the 'event handler class' - this is a Java class that is designed to handle events sent to the Script node. You should note that there are two ways to access Java from VRML; One, referred to as internal scripting, communicates directly with Java and the other , referred to as external scripting, accesses Java running as a seperate application using the External Application Interface (EAI). The following discussion concentrates on internal scripting.

To make the following discussion more concrete, here is an example of a simple VRML Script node and the associated event handler class. The goal of this example is to use a TouchSensor to switch the color of a Sphere from red to blue. If it's blue, change it to red, and if red, change to blue. This is an example that requires the use of a comparison, and so access to a programming language. First the VRML file:

The VRML example for changing a Sphere color:

1   #VRML V2.0 utf8
2   Transform {
3      children [
4        DEF TS TouchSensor {} # TouchSensor
5        Shape {
6          appearance Appearance {
7            material DEF SphereColor Material { diffuseColor 1 0 0 } # red
8          }
9          geometry Sphere {}
10        }
11      ]
12   }
13   
14   DEF ColorScript Script {
15      url "ChangeColor.class"
16      eventIn SFBool clicked
17      eventOut SFColor newColor
18      field SFBool on FALSE
19   }
20   # Routing
21   ROUTE TS.isActive TO ColorScript.clicked
22   ROUTE ColorScript.newColor TO SphereColor.set_diffuseColor

Note the TouchSensor, "TS" (line 4), which is routed to the Script node field clicked using the ROUTE at line 21. This ensures that whenever the the mouse is clicked over the light shade, the TouchSensor is triggered, and an isActive event is routed to the Script field "clicked". The route from the Script node "newColor" to the Shape node's diffuseColor field ensures that whenever the "newColor" field is written to, an event is generated and passed along the route to the diffuseColor field of the Shape node. Essentialy, the field "clicked" checks for click events from the mouse, the field "on" holds the current status of the Sphere color (TRUE equals blue, FALSE equals red) and the field "newColor" holds the value that the Sphere should now be set to.

The Java code which actually reads the current color from the field "on" and sets the new color via the eventOut field "newColor" is shown below:

1   import vrml.*;
2   import vrml.field.*;
3   import vrml.node.*;
4
5   public class ChangeColor extends Script {
6   
7     private SFBool on;      // status of on-off
8     float red[] =  { 1, 0, 0 };      // RGB(Red)
9     float blue[] = { 0, 0, 1 };      // RGB(Blue)
10     private SFColor newColor ;
11
12     public void initialize() {   
13
14       newColor = (SFColor) getEventOut("newColor");
15       on = (SFBool) getField("on");
16     }
17
18     public void processEvent(Event e) {
19       ConstSFBool v = (ConstSFBool)e.getValue();
20
21       if(v.getValue()){
22         if (on.getValue()) {
23           newColor.setValue(red);     // set red to 'newColor'
24         } else {
25           newColor.setValue(blue);    // set blue to 'newColor'
26         }
27         on.setValue(!on.getValue());  // = !on.getValue();
28       }
29     }
30   }

This example may seem a little confusing at first because it contains quite a lot of information. We will use it to show you three things: how to pass information from the Script node to the event handler class using events, how to read a field in the Script node from Java, and how to write back a result from the event handler class to the Script node.

You should note that the Java file includes three packages, vrml.*, vrml.field.* and vrml.node.* which contain the java classes that support the Java API. You must import these packages into each event handler class. You must also define you event handler class as an extension of the Script class.

Receiving events and reading their values
The Script node contains three user defined fields, "clicked" of type SFBool and category eventIn; "newColor" of type SFColor and category eventOut; and "on" of type SFBool --initially set to FALSE-- and of category field. The Script node also defines an event handler class, ChangeColor.class, which is responsible for dealing with events sent to the Script node. The name of the file which implements the event handler class (in our case, ChangeColor.Class) as specified in the url field of the Script node is important. The name of the event handler class must equal the stem of the file name. In our example, the file is ChangeColor.class, and the event handler class (shown in ChangeColor.java) must be ChangeColor. This is necessary to allow the browser to make the link between the Script node and the event handler class.

Within the event handler class (ChangeColor) there is a special method, processEvent(), which must always be present and is called by the browser when an event is sent to the Script node. The actual mechanism that ensures that an event sent to a field of a Script node is forwarded to the Java event handler is automatic, as it is the responsibility of the browser manufacturer to make sure this happens. What is important is that whenever an event arrives at an eventIn field of a Script node, that event will always be delivered to the Java event handler class and will cause execution of the special method, processEvent().

Looking back at our example, you can see that that the method processEvent takes a parameter "e" of type Event. Event is a pre-defined Java class in the vrml.* package which holds the actual event sent to the Script node.

In our example, we know that the only type of event that can arrive at the Script node is of type SFBool since this is the only eventIn field in the Script node. Therefore, the first thing we do in the method processEvent() is convert the event into a ConstSFBool value "v". All VRML data types have a corresponding Java class, such as ConstSFBool. This new class "v" is initialised by calling getValue on the "e" event. You should note here that we are not using getValue on "e" to actually get the value, but to initialize an instance of a ConstSFBool class. We call this instance the handle. To actually find out the value of the event, we need to call getValue() on the handle, "v" - this returns the actual value of "v" the event. Hence, getting a value of an event is a two step process: first, create an instance of whatever type the event is (e.g. a boolean, ConstSFBool) and then, read the value of that instance using the getValue() method. we can also access other fields of the node that haven't received events

we can also access other fields of the node that haven't received events

Accessing another field of the Script node
We are not restricted to only receiving events from a Script node; we can also access other fields of the node that haven't received events. The next line in our example (line 22) checks the value of the field "on" in the Script node.

 
if (on.getValue()) {

However, we have just stated that accessing a value is a two stage process; first, get a handle to the value's class and then, get the value itself. In the above, we only get the value. The first stage is actually performed in another special method, initialize(). initialize() is used to set up internal variables and is guaranteed to be called by the browser after the event handler class is instanciated but before it recives any events. Within initialize() we create handles to the variable "newColor" and the variable "on" by calling getEventOut() and getField() respectively.

Writing data back to the VRML scene
So far, we have checked the incoming event sent to the eventIn field "clicked" to see if it equals TRUE. If so, we have accessed the field "on" to see the current status of the Script node. Now, depending on the status of the Script node field "on", we will decide to set the Script node field "newColor" to red or blue.

Lines 23 or 25 write a new color back to the scene graph by setting the "newColor" field of the Script node. To do that, they use the method setValue(). When this method is called, it actually writes the new value to the field of the Script node. Since the field newColor is of category eventOut, writing a new value to it from the Java event handler causes it to generate an event within the VRML scene. This event is routed to the diffuseColor of the Sphere node (line 23 of the VRML file) causing the new color to be sent to the Sphere node and so changing the color of the Sphere in the VRML scene.

The net result: the TouchSensor monitors the mouse over the Sphere. When clicked, the "click" event causes the event handler class to read the current color of the Sphere from the Script node, and if red set it to blue, or if blue, to red.

Conclusion
This basic model of sending events to Script nodes, handling the events in the event handler class, and returning results to the VRML forms the basis of the link between VRML and Java. Once you've understood this, you can write arbitrarily complicated scripts. In the next article, we will build on this explanation and show you a couple of examples that use this mechanism to enhance built-in VRML nodes.

If your browser is already set up to handle Java, then you can copy these examples, edit them, compile the java and test them out. Note, your browser must support Java internally - accessing Java via the EAI is not sufficient. If this is not the case, then you should download Community Place. See the URL at the beginning of this article.

Community Place tutorials

In addition, there is a set of online tutorials for Community Place which includes a page on setup for the Java environment.

The examples in this article are taken from the our book: "Java for 3D and VRML worlds" Lea, Matsuda and Miyashita. New Riders Publishing, ISBN 1-56205-689-1 and are provided courtesy of New Riders Publishing.

Rodger Lea is a senior research scientist at Sony's Computer Science lab in Tokyo . He holds a PhD in computer science, usually works on distributed operating systems but has, over the last year, moved up in the world and developed the distributed architecture for Sony's multiuser VRML system. He can be reached at rodger@csl.sony.co.jp
Back Contents Next
Have you tried out our new Discussion Area yet?

LinkExchange
LinkExchange Member

Need sponsorship or advertiser information? E-mail adrian@aereal.com.

Have an idea for an article? Thought of a way we can improve VRMLSite? E-mail suggest@vrmlsite.com.

Please Tell a Friend about VRMLSite!

© 1997 Aereal, Inc. All rights reserved. VRMLSite is a trademark of Aereal Inc.