Chapter 41 -- Adding Behaviors with VRMLScript and Java
Chapter 41
Adding Behaviors with VRMLScript
and Java
by John J. Kottler
CONTENTS
As the World Turns
Viewing the New World
Sensors
The Script
Node
The Best Route
Introduction to VRMLScript
Functions in VRMLScript
Assigning Values in VRMLScript
Conditional Logic
Looping
VRML Browser Commands
Seeing the Light
Touch-Sensitive Cone
Reading the Script
Wiring the Light
Using Java for More Kick
It's About Time
Time to Read the Script
Route It Out
Imported Java
Initializing the Applet
The Main Task
Summary
Like the world itself, the World Wide Web is not flat. However,
most of the content on the Web today consists of simple, two-dimensional
pages that contain two-dimensional graphics. Only recently, a
change has begun to sweep over the Internet and the computer industry.
More emphasis is being placed on the three-dimensional world.
This is obvious by the immense popularity of three-dimensional
games that have saturated the market.
The idea of using three-dimensional objects that can be manually
manipulated is becoming more a commonality than a futuristic idea.
Businesses and scientists can clearly benefit from the use of
three-dimensional drawings to analyze mechanical equipment, chemical
compounds, or DNA strands. Simulators are developed using three-dimensional
technologies to emulate the real world, and the possibility of
three-dimensional operating systems for computers is not far away.
But what about the Internet? Anyone who has browsed the Web can
easily be inundated with information. In order to organize some
of that information, three dimensions may be clearer than two.
In the future, you may find more three-dimensional worlds being
created to more easily handle large volumes of data. And as Web
technologies continue to evolve, three-dimensional games will
become a reality, as will chat rooms where you interact with other
three-dimensional people.
The technology that has advanced the prospect of 3D on the Web
is VRML, the Virtual Reality Modeling Language. As you have learned
from other chapters in this book, this simple language instructs
a three-dimensional browser how to paint three-dimensional worlds.
The language is fairly straightforward, and numerous development
tools available today assist in creating three-dimensional objects
for VRML. Unfortunately many VRML sites today suffer from the
same afflictions as Web sites in the recent past: the lack of
interaction. Users can see a VRML world, walk through it, or rotate
it, but they can't actually do anything in it.
As the World Turns
Users who are viewing worlds created with VRML 1.0 are very limited
in what they can do. Fortunately, just as everything else evolves
quickly on the Internet, so has the world of VRML. The newest
iteration of VRML 2.0, also referred to as Moving Worlds, is a
dynamic virtual reality language. Current information regarding
Moving Worlds can be found at the Silicon Graphics Web site: http://vrml.sgi.com/moving-worlds.
In addition to new effects and three-dimensional capabilities,
with VRML 2.0 it is possible to create worlds where objects spin
or move in space. But more importantly, these objects can be smart
as they move about. Moving Worlds allows three-dimensional objects
to interact with computer scripting languages to define the unique
characteristics or behaviors for those objects. These objects
can also interact with each other or with the user to truly make
an interactive experience.
In this chapter, you have the opportunity to learn how to make
three-dimensional worlds that are dynamic and respond to the actions
of the user. You learn about Moving Worlds' newest additions to
VRML such as sensors, the script node, and wiring a world with
VRMLScript or a Java applet.
Viewing the New World
Moving Worlds still requires the use of a three-dimensional browser.
A 3D browser is capable of translating VRML, constructing a three-dimensional
scene, and allowing the user to control how the scene is viewed.
Most VRML browsers today can be launched by a Web browser such
as Netscape's Navigator or Microsoft's Internet Explorer to view
a scene related to a Web page. These VRML browsers may either
create separate windows for displaying the scene or occupy the
same space as the Web page.
In any case, it is important to remember that to see a three-dimensional
world created using VRML 2.0, you must use a browser that is compliant
with VRML 2.0. A few capable browsers are the following:
CosmoPlayer by Silicon Graphics
(http://vrml.sgi.com/)
CyberPassage by Sony Corporate
(http://vs.sony.co.jp/VS-E/vstop.html)
Liquid Reality by DimensionX (http://www.dimensionx.com/products/lr/)
These browsers allow you to view VRML 2.0-animated worlds and
interact with objects within those worlds. Each of these browsers
include sample files that demonstrate the capabilities of VRML
2.0, particularly when used in conjunction with the browser. You
will see differences in the way each handles VRML worlds, but
they all can display a Moving Worlds three-dimensional world.
Figure 41.1 demonstrates a sample of the Sony CyberPassage VRML
browser. This browser makes particularly good use of Java applets
with the VRML worlds. Several sample files are included with this
browser including Drive, a race-track world with an animated car
that winds through the curves of the track. In addition, the user
can control whether the car moves or is stopped by clicking directly
on the car.
Figure 41.1 : Sony's CyberPassage displays Moving Worlds,
VRML 2.0 files that feature animation and interaction.
Sensors
In order to accomplish the results shown in Figure 41.1, numerous
new interactive capabilities were added to VRML 2.0. For instance,
new capabilities that handled the user clicking on the object
or touching it were required before the user could click on the
car to start it racing around the track. Most of these new interactive
capabilities were added to the VRML 2.0 standard in the form of
sensors.
You can think of these sensors as everyday sensors in the real
world. For instance, a common touch sensor is found in the touch-sensitive
computer screens in mall kiosks or on some automated teller machines.
When you touch the screen, something happens. Likewise, motion
sensors may be attached to the outside of a house or business
building. When someone or something comes within a predefined
distance of the sensor, exterior lights may be lit.
These same sensors are available in VRML 2.0. You find the touch
and proximity sensors as well as many others listed in Table 41.1.
These sensors all do different tasks but work on the same principle.
They monitor activity within the VRML world and send notifications
appropriately to programming scripts or other objects when particular
events occur.
Table 41.1. Sensors can be set in a VRML 2.0 world
to monitor activity.
Sensor NameSensor Action
CylinderSensor
This sensor allows the developer to specify objects of 3D space that are to be rotated around their Y axis, independent of the rest of the scene. This sensor monitors when a user drags the mouse in this region with the button down.
PlaneSensor
A developer can specify which objects may be moved along their X and Y axis' independent of the scene. This sensor outputs events when the user drags the mouse with the button down within this region.
ProximitySensor
As a user moves closer to a region in 3D space using the VRML browser, specific events are triggered. The developer can use this sensor to make objects run away from the user when the user gets too close.
SphereSensor
Similar to CylinderSensor and PlaneSensor, SphereSensor allows the developer to choose which objects in 3D space may be rotated around any axis, independently of the rest of the scene.
TimeSensor
Some events occur regularly at a scheduled interval or once at a specific time. The TimeSensor monitors an internal clock and triggers events either regularly on a given interval or once when a specific time has occurred. To
create objects that update every second, a developer sets the interval for a TimeSensor.
TouchSensor
Truly interactive worlds allow the user to control them. One method of implementing this control is to note when a user clicks on or "touches" an object. A developer can use the TouchSensor to create a switch for
turning animation on or off, for example.
VisibilitySensor
This sensor determines whether a particular region of the three-dimensional world can be seen by the viewer. If a user can see a particular region monitored by the sensor, an event is triggered. Developers can use this sensor to
determine when users can see parts of their world.
Most of the sensors listed in Table 41.1 are associated with particular
objects in a VRML scene. For instance, the TouchSensor
affects all objects within its parent group. Therefore, if a TouchSensor
is created within a cone transform, as shown in Listing 41.1,
you are able to click on the cone and not any other object in
the scene. Of course, each object in the scene may have its own
sensors with unique functionality.
Listing 41.1. Sensors can be applied to individual objects
in VRML 2.0.
Transform {
children [
DEF TOUch_SENSOR TouchSensor {}
Shape {
appearance Appearance {
material Material {
diffuseColor 0 0 1
}
}
geometry Cone{}
}
]
}
These sensors open the possibility to create interactive worlds
by noting when particular events occur. However sensors alone
do not make the world interactive, they need to be connected to
other objects or programming logic. In the next section, you learn
how to add intelligent behaviors to objects using the Script
node.
The Script
Node
As mentioned numerous times already, objects themselves are static
but can behave differently when coupled with programming scripts.
These scripts can add simple or complex natures to objects in
a scene. Anything from simply moving or rotating objects to creating
interactive games is possible with scripts.
The Script node allows you
to add these complex routines and behaviors to your VRML scene.
Currently, the Script node
supports numerous scripting languages such as VRMLScript, JavaScript,
and more robust languages such as Java. Each of these languages,
as we will see shortly, allows you to give more control over the
flow of a world.
Tip
Each scripting language that can be used in Moving Worlds can perform the same basic functions. The difference between these languages becomes more apparent when constructing complex worlds. More complex scenes require faster and more robust languages
like Java.
The following outlines the basic scripting node for VRML 2.0:
DEF toggle Script {
field fieldType fieldName defaultValue
eventIn eventType eventName
eventOut eventType eventName
url "Script/Applet URL or embedded Script"
scriptType "ScriptLanguage"
}
field-There may be
any number of fields within a Script
node. These fields are similar to variables in other computer
programming languages. Like variables in most languages, the type
of data each field holds must be specified in VRML by way of an
appropriate field type. Valid VRML field types can be found on
the Web at http://vrml.sgi.com/moving-worlds/spec/part1/fieldsRef.html.
A sample type is SFBool to
indicate Boolean values.
eventIn-VRML works
with objects in three-dimensional space. Therefore, it is not
surprising that it is also somewhat object-oriented in nature.
eventIn specifies the names
of functions within the Script
node that may be invoked by objects outside of the Script
node. For instance, if there is an object named MY_CONE
and a function named MoveCone
within a Script node of a
VRML scene, that MoveCone
function needs to be made available to other objects like the
cone using eventIn. eventIn
is comparable to methods in object-oriented technology, and there
can be as many eventIn's
as needed within a Script
node.
eventOut-Just as a
script can expect information to be sent into its functions, a
Script node may export data
to other objects. The data to be made available to other objects
is specified using the eventOut
parameters. eventOut's are
equivalent to variables that are defined within a Script
node that are made available to other objects as well. eventOut
is similar to properties in object-oriented technology, and there
may be numerous eventOut's
in a Script node.
url-After the functions
for receiving input and the variables for sending output are defined
in the Script node, the actual
functions and programming logic must be specified. The url
parameter of the Script node
identifies the functions to be associated with that node. The
information within the url
parameter may indicate another location to retrieve scripting
commands from or may be used to embed the language directly into
the node. It may also be used with an optional scriptType
parameter to indicate executable languages such as Java.
scriptType-When choosing
other languages, such as Java, to handle the script's events,
the scriptType parameter
is essential for specifying what that language is. It is also
useful when the url parameter
points to a file that contains the script, not the actual script
itself. In the case of using Java applets, the scriptType
parameter must be set to javabc,
for Java byte-codes, when the url
contains the name of the Java class to use.
Tip
The position for Script nodes within a VRML file is irrelevant. Scripts are only invoked as instructed by ROUTE statements and therefore can exist at any location in a VRML file. It is recommended that you keep all of the scripts near
each other to improve readability of the source VRML file. Typically, scripts are placed near the end, after the scene is described.
The Best Route
Script nodes, like most other
nodes in VRML, can be placed at any location in a VRML source
file. This is because the VRML browser typically reads the entire
VRML source file before attempting to display the scene. However,
if this is the case, how can a script be instructed to execute
when particular events occur? The answer to controlling the flow
of events in a VRML world is the ROUTE
command.
ROUTE is a command in VRML
that specifies the actions that objects in a world should follow.
It specifies what actions in one object can occur to affect other
objects. It is not a node, and it can be written on a single line
of code. Its sole purpose is to map eventOut's
from objects to eventIn's
of other objects. This mapping creates a link between objects
so that they can communicate with each other and update each other
accordingly.
The ROUTE command is a fairly
straightforward command to understand:
ROUTE eventOut_of_Object TO eventIn_of_Object
Note
A ROUTE command must exist for every mapping between two objects. If you wish to map three eventOut's of one object to three eventIn's of a second object, you must include three distinct
ROUTE statements in your VRML source code for each connection.
For example, it's possible to route the output of a sensor to
a function in a custom script. The TouchSensor,
for instance, contains an isActive
property (eventOut). This
property can then be routed into a function (eventIn)
in your own custom script. That way, whenever a user clicks on
an object and triggers the TouchSensor,
a custom function defined in a Script
node can be executed. With this route, it is possible to monitor
when a user clicks on objects in the VRML scene and act appropriately.
Each node in VRML contains its own set of eventIn's
and eventOut's. Covering
each node with its respective events would require much more than
a single chapter. To find out more about specific events for each
node, visit the VRML specification site: http://vrml.sgi.com/moving-worlds/spec/part1/nodesRef.html.
Tip
Like the Script node, ROUTE statements may be placed anywhere within the VRML file. However, it is recommended that you either group all routing commands at the end of the file or at least have related commands near their respective
Script or object nodes.
Introduction to VRMLScript
Now that you have learned about the Script
node and the ROUTE statement
in VRML 2.0, you need to begin creating scripts that determine
the behavior of objects in a three-dimensional world. VRMLScript
is a language that is supported by VRML 2.0 and therefore browsers
that are compliant with Moving Worlds. This language, which is
a derivative of JavaScript, is exceedingly similar to Java or
C programming languages. If you have experience with these languages
already, then VRMLScript appears very easy.
VRMLScript is actually a subset of JavaScript. Therefore, it supports
much of the same language semantics of JavaScript. The primary
difference between VRMLScript and JavaScript is that VRMLScript
disregards many of the document and browser class methods and
properties necessary for Web pages. VRMLScript does contain a
math library and common functions found in JavaScript.
This chapter presents a quick overview of VRMLScript. For more
information on the JavaScript scripting language, which is again
identical to VRMLScript in many ways, consult Chapters 34-38 of
this book or Teach Yourself JavaScript in 21 Days or Netscape
3 Unleashed by Sams Publishing.
Functions in VRMLScript
As mentioned earlier, functions are essential in scripts. A function
is simply a collection of VRMLScript commands that are executed.
The important thing to note about functions is that the same group
of VRMLScript commands can be executed repeatedly simply by calling
that function's name.
The Script node maps particular
eventIn parameters to functions
within a Script node. In
addition, values from other objects can be passed into a function.
The function can use those values to determine what other events
are happening in the three-dimensional scene you create.
Functions typically take the following format:
function functionName(eventIn_Value) {
VRMLScript Code
}
Note
More than one function may be inserted within a Script node. However, each function must be declared by the eventIn parameters of a Script node in order for those functions to be publicly available to other objects in the scene.
Assigning Values in VRMLScript
The code between curly braces ({}) in a script's function may
be any combination of VRMLScript commands or functions. Often
calculations are performed and stored in variables within VRMLScript
code. These variables can be assigned using a single = character.
Likewise, property values for particular objects may be assigned
using the = character. For example, assigning the on
property of a DirectionalLight
node named MY_LIGHT may be
performed with the following statement:
MY_LIGHT.on = 1
Traditional mathematical functions are accepted within VRMLScript
as well, such as multiplication (*), division (/), addition (+),
and subtraction (-). Many other mathematical functions are defined
within VRML/JavaScript's math
object. For instance, using Math.PI
in a line of VRMLScript code returns the value for pi.
Tip
There are numerous shortcuts in C, Java, JavaScript, and VRMLScript for updating variables. By using a variable name followed by two mathematical symbols, it is possible to update the value of that variable. For instance, to update the value of the
variable var, the following statements can be used:
var++; // Updates the variable by adding "1" to it, same as "var=var+1"
var-=5; // Updates the variable by subtracting "5" from it, same as "var=var-5"
Conditional Logic
Another common action to perform in programming languages is conditional
logic. Conditional logic is an elegant name for simply testing
for certain values. Conditional logic typically consists of an
if/then/else set. The VRMLScript
application checks to see if some variable is equivalent
to a particular value. If it is, then the VRMLScript can
perform a particular task. If it is not equivalent, then the VRMLScript
may have an option to do something else.
Conditional statements typically appear as follows:
if (variable == value) {
do some VRMLScript if result is true
}
else {
do some VRMLScript if result is false
}
Conditional statements may be as complex as necessary and can
even be nested within each other. In some cases, you may need
to test multiple criteria in order to establish a result. VRMLScript
uses typical C/Java/JavaScript notation for testing equivalence
(==), non-equivalence (!=),
greater than (>), less
than (<), greater than
or equal to (>=), less
than or equal to (<=),
logically "ANDing" values together (&&),
logically "ORing" values (||),
or inverting TRUE/FALSE Boolean
values (!).
For example, to test whether an object is a sphere and
is either red or blue, the following condition can be used:
if (shape == "sphere" && (color == "Red" || color == "Blue")) {
the object is a red or blue sphere.
}
Note
Curly braces ({}) are used to surround a group of lines in VRMLScript source code. These braces indicate which lines of code are to be executed together as a group. For example, if an if statement is used, it is essential to indicate in the
VRMLScript source code exactly which lines are to be executed when the result is true versus those lines that are executed when the result is false.
Looping
Some regions of a VRMLScript application may need to be executed
more than once. To make a portion of code repeat numerous times,
loops may be used in VRMLScript. There are typically two types
of loops available in VRMLScript: the for
loop and the while loop.
For Loop
The for loop indicates that
a section of source code should execute for a particular
number of iterations. This loop requires the following syntax:
for (loopIndex = startingValue; loopIndex_Condition; loopIndex_Update) {
VRMLScript code
}
The loopIndex is a variable
that keeps track of how many times the loop has executed. It may
be set to a starting value. The loopIndex_Condition
is similar to an if statement
that instructs what a loop should look for in order to terminate.
If the loopIndex_Condition
is true, then the code within the loop is executed. When it is
false, the loop terminates. Typically, it tests the loopIndex's
value to determine whether it has reached the end of the loop's
range. Commonly, the loopIndex
is incremented by one step at a time. However, it is possible
to specify that this index update its value differently using
the loopIndex_Update parameter.
The following are two examples of for
loops that execute VRMLScript code for a total of 10 iterations:
for (n=1; n<=10; n++) {
some VRMLScript code
}
or
for (n=20; n>0;n-=2){
some VRMLScript code
}
while Loop
In some cases, you may want to execute a section of code several
times without necessarily knowing in advance the exact number
of times that loop should occur. The while
loop allows you to execute a section of VRMLScript as long as
the condition within the while
loop is true. while loops
use the following syntax:
while (condition) {
do some VRMLScript
}
In this case, the condition
parameter of the while loop
acts like an if statement.
When the result of the conditional test is true, the VRMLScript
code is executed. Once the result is false, the loop is terminated.
VRML Browser Commands
You will remember that VRMLScript is very similar to JavaScript
with the exception of the typical properties and methods found
in JavaScript for documents and Web page control. However, VRMLScript
also adds several specific commands that can be used with VRML
browsers. Table 41.2 lists these specific commands and their functionality
within the VRML browser.
Table 41.2. VRMLScript can access numerous methods
for the Browser
object.
Browser MethodAction Performed
getName()
Returns the name of the VRML browser being used to view a scene as a string.
GetVersion()
Returns the version number of the VRML browser being used as a string.
getCurrentSpeed()
Returns the current speed at which a user is traveling through the VRML world. The value returned is a floating-point number.
getCurrentFrameRate()
Returns the speed at which scenes can be generated, in frames per second, as a floating-point number returns a VRML scene can be updated as quickly as a browser on a particular computer platform allows. Constraints may include the speed
of the hardware, software, or graphics controller.
getWorldURL()
Returns a string value containing the current URL used to access the VRML scene displayed in the browser window.
loadWorld(url)
Instructs the browser to load another VRML world into the browser window. The url parameter specifies the file and location of the VRML file to load.
replaceWorld(nodes)
At times it may become necessary to update or replace particular nodes in a world currently viewed in the browser without actually loading a brand new world. The nodes parameter allows you to specify a list of nodes to use when
replacing the currently viewed scene.
createVRMLFromURL
It is possible to create a 3D scene using another
(url, node, event)
URL for the VRML source. However, retrieving other URLs from the Internet may be a time consuming process. Therefore this method allows you to specify an eventIn that is notified when the new node list is successfully read.
createVRMLFormString(string)
Three-dimensional scenes may be created on the fly by passing strings that contain VRML commands to the browser. This method sends a string to the browser to be rendered and returns a list of root nodes when completed.
addRoute(fromNode, fromEventOut, toNode, toEventIn)
Because objects can be created by way of browser methods at any time, there must be a provision to add routing between new nodes. The addRoute method instructs the VRML browser to connect the eventOut from one node to
the eventIn of another node, provided that the events and nodes are named.
deleteRoute(fromNode, fromEventOut, toNode, toEventIn)
Just as it is possible to add routes spontaneously to newly created nodes, it is possible to remove them. This method disconnects an eventOut from one node and the eventIn of a second node.
Seeing the Light
Now that you have had a quick overview of VRMLScript and a familiarity
with it, we can examine how it is used in a VRML scene to create
an interactive world. A simple example in VRMLScript is to create
a world where there is a single white cone in the middle of the
world.
Ordinarily this cone appears very dark, therefore a default directional
light can be added to give the cone an additional glow of light.
Figure 41.2 demonstrates this simple three-dimensional object
with the light source applied. In this figure, the Silicon Graphics
CosmoPlayer was used to display the VRML world.
Figure 41.2 : A directional light adds a glow to the
right half of this 3D cone. The light can be turned on or off
by clicking on the cone.
When the light is on and you click on the cone, the light is turned
off, and the cone is scarcely visible against the black background.
Likewise, if you click on the cone while the light is off, it
is turned back on again to reveal the cone.
This simple task of turning a directional light on or off is accomplished
using a simple VRML script embedded within a Script
node and a TouchSensor. There
are also additional ROUTE
statements used to direct eventOut's
of some nodes into eventIn's
of others. To understand how this simple world is constructed,
examine its source code in Listing 41.2.
Listing 41.2. The light is controlled using a TouchSensor
and a simple VRMLScript with routing statements.
#VRML V2.0 utf8
DEF MY_LIGHT DirectionalLight {
on TRUE
}
Transform {
children [
DEF TOUch_SENSOR TouchSensor {}
Shape {
appearance Appearance {
material Material {
diffuseColor 1 1 1
}
}
geometry Cone{}
}
]
}
DEF toggle Script {
field SFBool lightOn FALSE
eventIn SFBool isConeClicked
eventOut SFBool toggle_changed
url "vrmlscript:
function isConeClicked(button_state) {
if (button_state == 0) {
if (lightOn == 0)
lightOn = 1;
else
lightOn = 0;
toggle_changed = lightOn;
}
}
"
}
ROUTE TOUch_SENSOR.isActive TO toggle.isConeClicked
ROUTE toggle.toggle_changed TO MY_LIGHT.on
As you look at the code in Listing 41.2, you will not find much
out of the ordinary for creating a simple cone shape in a VRML
world. The following sections review what code elements make this
simple world interactive.
Touch-Sensitive Cone
The first thing you may notice as you scan down from the top of
the source code in Listing 41.2 is the presence of a TouchSensor.
This TouchSensor is named
TOUch_SENSOR for reference
later on in the source code.
You'll recall that a TouchSensor
gives an object in VRML 2.0 the ability to have a user click on
it in order to perform some action. The TouchSensor
node can contain numerous events and fields, but the only thing
we are concerned with is setting up the TouchSensor
and triggering a VRMLScript when someone clicks on the cone.
TouchSensors are applied
to all geometry that falls within the parent node containing the
TouchSensor node. In our example, the TouchSensor
is related to its parent node Transform,
which was not given a proper name. Therefore, any geometry that
appears within this Transform
is treated as "hot-spots" for the TouchSensor.
That is, if you can click on any objects within that transform
and a TouchSensor is connected
to that transform, an action
occurs. In our example in Listing 41.2, the only geometric object
within the transform is a
cone, therefore you are only able to click on that cone to initiate
an action.
The sensor simply monitors mouse input while the world is viewed.
Whenever the mouse passes over objects that contain the TouchSensor
and the mouse button is clicked, an eventOut
is triggered from the TouchSensor.
In this case, the isActive
eventOut is sent, indicating
that a user is actively clicking on the object.
So now that the sensor has been created and an appropriate event
is being triggered, what's next? The action of clicking on the
cone must be recognized by a script and handled appropriately.
This requires the use of a routing statement that connects the
isActive eventOut from the
TouchSensor to an appropriate
function within a Script
node. We will review all of the routes that are defined in this
scene shortly.
Reading the Script
The next obvious difference in the source code is the addition
of a Script node. This node
allows the VRML browser to control other objects and actions within
the three-dimensional world using instructions presented in the
node.
The first three lines of the Script
node declare a variable to be used within the script (lightOn),
the function isConeClicked
(which is the node's eventIn
), and a property named toggle_changed,
which is an eventOut. As
you will recall, a Script
node's eventIn declarations
match the functions that are available to other objects as methods.
Similarly the script node's eventOut
declarations match variables used in the script that can be read
by other objects afterward.
This simple script reads the output of the TOUch_SENSOR
output event as input to its own isConeClicked
function. The isActive event
from the touch sensor is TRUE
or 1 when the mouse button is held down and FALSE
or 0 otherwise. This event is passed to the isConeClicked
function as the variable button_state.
When the button is pressed, the isActive
event of the TouchSensor
changes from a 0 to a 1, and that result is assigned to the variable
button_state in the isConeClicked
function.
Within that function, the script determines whether the light
is currently on or off using a variable that toggles its state
simultaneously with the directional light MY_LIGHT.
After the script establishes that the light is either on or off,
it changes the state of the light to be the opposite. This is
accomplished by first setting the variable within the Script
node that represents the light to the appropriate value (1
= on, 0 = off). Another routing
statement later takes this variable's result and routes it to
the actual light source to complete the action.
Note
When writing scripts that respond to TouchSensors, it is important to notice that the TouchSensor triggers the events and actions continuously. For example, when you hold the mouse button down for a long period of time over the object
with the sensor, the sensor sends the isActive event to a respective object as long as the mouse button is held down. Therefore, you may consider checking the status of the mouse button (which is indicated by the isActive event from the
TouchSensor). You may wish to only execute the script commands when the mouse button has been released, indicating a complete button click. Listing 41.2 does just this using the condition:
if (button_state == 0).
Tip
Although it does not matter to the VRML browser that the events and fields appear before the URL, it is a good practice to place them before the actual embedded script code. This makes the code more legible since common programming practices have
developers declare variables before the script. Also when reading the script from top to bottom, you will read the variables first and remember them when they are referenced in the code.
Wiring the Light
Now that the script has been designed to check the status of the
light and set the new state appropriately, it is time to see how
the TouchSensor, script,
and light are all connected together.
You learned earlier about the ROUTE
statement in VRML 2.0. This command allows you to control the
flow of control for a three-dimensional environment created with
Moving Worlds. Routing commands basically inform the browser of
the sequence of actions that are to be taken when particular events
arise.
In the example shown in Listing 41.2, the TouchSensor
triggers a script, which in turn triggers a light source in the
scene. Therefore, two routing statements are required: one to
connect the TOUch_SENSOR
sensor to the toggle script,
and a second to connect the toggle
script to the light MY_LIGHT.
More specifically, the output event's value of the sensor is passed
to the input event and ultimately a function of the script. The
resulting property value of the script is then sent onto the input
event for the light that determines whether the light is on or
off. The two lines that accomplish this are:
ROUTE TOUch_SENSOR.isActive TO toggle.isConeClicked
ROUTE toggle.toggle_changed TO MY_LIGHT.on
Using Java for More Kick
You can create some fairly complex VRML worlds using the VRMLScript
capabilities that have been introduced so far. However, for very
complex worlds that require a more robust, object-oriented language,
you may consider using something like Java. With Java, truly interactive
applications that deal with user's input, network information,
and a host of other capabilities are possible.
Fortunately, it is quite simple to tap the capabilities of Java
and integrate them with your VRML 2.0 worlds. In the previous
section, you learned many of the fundamentals of integrating programmable
scripts with Moving Worlds objects. These same techniques will
be applied to integrating Java applets with your three-dimensional
worlds.
To illustrate connectivity between Java and VRML, consider another
example. In this example, we will make a simple cone (we love
cones) rotate towards the viewer and appear closer. It will then
take several steps to rotate that cone away from the viewer at
a further distance away. The animation will continue to swing
back and forth as long as the scene is viewed in the VRML browser.
In this case, Sony's CyberPassage makes viewing Java-controlled
VRML files easy. Sony CyberPassage also includes Java classes
that can be incorporated into your Java applets to create these
complex VRML worlds. These classes follow standards documented
at the Moving Worlds site at Silicon Graphics (http://vrml.sgi.com/moving-worlds).
This is a fairly simple animation applet that does not require
complicated coding algorithms. However, it is ample for demonstrating
the connectivity between VRML and Java. Figures 41.3 through 41.5
show three of the stages of the cone's rotation in order for you
to gain a feel for how it will look animated.
Figure 41.3 : In the Java-controlled VRML animation,
the cone begins by pointing directly at the user.
Figure 41.4 : In the middle of the same Java-controlled
VRML animation, the cone points straight up.
Figure 41.5 : The Java-controlled VRML animation ends
by pointing the cone away from the user.
Now that you can picture how this animation appears, consider
the source code for this animation. Listing 41.3 demonstrates
the VRML file that renders the cone. Listing 41.4 displays the
Java source code that controls the animation of the VRML cone.
The VRML file also connects a TimeSensor
to a Script node that invokes
the Java applet described in Listing 41.4.
Listing 41.3. The VRML file for the animated cone consists
of the cone, a TimeSensor,
and a simple script to connect the Java applet.
#VRML V2.0 utf8
DEF MY_LIGHT DirectionalLight {
on TRUE
}
DEF MYCONE_TRANSFORM Transform {
children [
Shape {
appearance Appearance {
material Material {
diffuseColor 0 0 1
}
}
geometry Cone{}
}
]
}
DEF TIME_SENSOR TimeSensor{
loop TRUE
cycleInterval .250
}
DEF SCRIPT Script{
url "MyCone.class"
scriptType "javabc"
eventOut SFRotation MyConeRt
eventOut SFVec3f MyConeTr
eventIn SFTime moveMyCone
}
ROUTE TIME_SENSOR.cycleTime TO SCRIPT.moveMyCone
ROUTE SCRIPT.MyConeTr TO MYCONE_TRANSFORM.set_translation
ROUTE SCRIPT.MyConeRt TO MYCONE_TRANSFORM.set_rotation
Listing 41.4. This Java applet controls the animation of the
cone displayed in Figures 41.3-41.5.
import vs.*;
import vrml.*;
public class MyCone extends Script{
// aRad is defined to make degrees to radian conversion easier
float aRad = (float) (Math.PI/180.0) ;
// Get the eventOuts from the VRML file
// These are the properties that get sent to the cone
// to update its rotation and position
SFRotation MyConeRt = (SFRotation)getEventOut("MyConeRt");
SFVec3f MyConeTr = (SFVec3f)getEventOut("MyConeTr");
// We're going to setup an array of coordinates, so we'll
// need an index for the array
int count;
// Since the animation will bounce back and forth, we'll
// need to increment or decrement "count" accordingly
int countDirection = 1;
float[] positionX;
float[] positionY;
float[] positionZ;
float[] angle;
float[] translation;
float[] rotation;
// Constructor my "MyCone" class. Initialization happens here.
public MyCone()
{
positionX = new float[9];
positionY = new float[9];
positionZ = new float[9];
angle = new float[9];
// Translations of objects requires a 3D vector
// "translation" will hold the X, Y, and Z
translation = new float[3];
// Rotations require four parameters:
// Which axis to rotate around: X, Y, or Z, and the
// amount of radians to rotate
rotation = new float[4];
// Setup all of the animation points
positionX[0] = 0f;
positionY[0] = 0f;
positionZ[0] = 4f;
angle[0] = 60f;
positionX[1] = 0f;
positionY[1] = 0f;
positionZ[1] = 3f;
angle[1] = 45f;
positionX[2] = 0f;
positionY[2] = 0f;
positionZ[2] = 2f;
angle[2] = 30f;
positionX[3] = 0f;
positionY[3] = 0f;
positionZ[3] = 1f;
angle[3] = 15f;
positionX[4] = 0f;
positionY[4] = 0f;
positionZ[4] = 0f;
angle[4] = 0f;
positionX[5] = 0f;
positionY[5] = 0f;
positionZ[5] = -1f;
angle[5] = -15f;
positionX[6] = 0f;
positionY[6] = 0f;
positionZ[6] = -2f;
angle[6] = -30f;
positionX[7] = 0f;
positionY[7] = 0f;
positionZ[7] = -3f;
angle[7] = -40f;
positionX[8] = 0f;
positionY[8] = 0f;
positionZ[8] = -4f;
angle[8] = -60f;
// Initialize the count index
count = 0;
}
// moveMyCone is invoked every 250ms as defined in
// the host VRML file. This method is invoked each
// time the TimeSensor cycleTime event occurs.
public void moveMyCone(ConstSFTime time, ConstSFTime ts)
{
// Move cone to new X, Y, Z position
translation[0] = positionX[count];
translation[1] = positionY[count];
translation[2] = positionZ[count];
MyConeTr.setValue(translation);
// Rotate the cone around its X access
rotation[0] = 1.0f;
rotation[1] = 0.0f;
rotation[2] = 0.0f;
rotation[3] = angle[count] * aRad;
MyConeRt.setValue(rotation);
// Increment/Decrement array index through animation
count = count + (1*countDirection);
// When we hit one end of animation, change direction
if(count >= 9){
countDirection = -1;
count = 7;
}
if(count < 0){
countDirection = 1;
count = 1;
}
}
}
It's About Time
To make sense of all of this code, first look at the VRML file
shown in Listing 41.3. It should be fairly straightforward by
now what this VRML file is doing. It renders a scene with a cone,
lit by a directional light source.
It also defines a TimeSensor.
A TimeSensor in Moving Worlds
is similar to other sensors, including the TouchSensor
we have reviewed already. It contains eventOut's
that can be used to trigger actions to occur in other objects
and eventIn's for specifying
the sensor's own characteristics. The TimeSensor
node allows a VRML browser to create an object that checks an
internal clock and sends notifications when a particular time
has transpired. This TimeSensor
can be used as an alarm for events that should occur only after
a specific amount of time has past. It may also be used as a metronome,
sending events on a regular basis. In our example, the TimeSensor
triggers actions in the script object on a regular interval (every
250ms).
Time to Read the Script
Every 250ms, the TimeSensor
sends a cycleTime eventOut
to a Script node as specified
by a ROUTE command near the
end of the VRML code listing. This Script
node is similar to the one we examined earlier with our lighted
cone example. The sole purpose of the Script
node is to determine which methods within the program Script
are to be used by other objects and what values the program script
can post for other objects to use.
In our previous example in this chapter, the Script
node also embedded the actual scripting commands within the node.
In this case, the Java applet that controls the animation cannot
be embedded since it is compiled into Java bytecodes. Therefore,
the URL parameter of this
node points to the actual Java class file. Since the URL
parameter does not contain the actual script language, the VRML
browser must know what type of program code it can expect at the
location specified. The scriptType
parameter in Listing 41.3 indicates that the program pointed to
by the URL is a byte code-compiled
Java applet (javabc implies
Java Bytecode).
Route It Out
The final routing statements should come as little surprise. Once
the Java applet has determined what the next rotational and translation
points should be for the cone during its course of animation,
it must update the cone accordingly. The last ROUTE
commands map the respective properties of the Java applet that
contain this information to the appropriate eventIn
methods for the Transform
node that contains the cone.
Imported Java
Once you have an understanding of the VRML file for this simple
animation, you can begin to examine its accompanying Java applet's
source code. As mentioned earlier, Sony CyberPassage provides
VRML classes that can be imported into your Java applet. These
classes provide numerous functions, but most importantly in this
example, they provide the linkage between the Script
node in the VRML file and the respective methods and properties
in the Java applet.
Tip
To make compilation of Java/VRML applets easier, copy the VRML and VS subdirectories into the Java Developer's Kit (JDK) directory. The best place to move them to make your life easier is within the classes subdirectory within
your JDK directory. Your JDK directory should then contain a classes folder that contains at least four directories: java, sun, vrml, and vs.
The first two lines found in Listing 41.4 import the necessary
classes for creating Moving Worlds Java applets. One of these
classes defines the Script
class that the applet inherits from, as shown by the first line
of code past the import statements.
The Script class contains
all of the Application Programming Interface (API) commands necessary
to connect your Java applet to the Script
node in your VRML file. These classes also contain the different
field types found in VRML and map them as appropriate variable
declarations in Java.
A few lines further into the Java application, you will find the
following two lines:
SFRotation MyConeRt = (SFRotation)getEventOut("MyConeRt");
SFVec3f MyConeTr = (SFVec3f)getEventOut("MyConeTr");
These two lines fetch the eventOut
information from the Script
node in the VRML file and map the information to Java variables
respectively. The getEventOut
function finds a particular eventOut
in a VRML Script node to
which the Java applet is related. As you can see from these two
lines, the rotational values and translation positions are declared
using appropriate vectors for VRML.
Initializing the Applet
When the applet is constructed for the first time, its constructor
method is invoked. The MyCone
method is the constructor for this applet, which initializes default
values and fills the rotational/translation arrays used for the
animation with numbers. The number of four basic arrays that are
used: positionX, positionY,
positionZ, and angle.
These arrays are as large as the number of steps in the animation.
This particular animation uses nine steps, where each step stores
a different rotational and translation value in each of the arrays.
Therefore the first step of the animation, denoted by an index
of 0 for the arrays, contains
the following settings for the cone's location in 3D space as
well as how far it should be rotated:
positionX[0] = 0f;
positionY[0] = 0f;
positionZ[0] = 4f;
angle[0] = 60f;
The Main Task
The Script node found in
Listing 41.3 specifically states that the primary method (eventIn)
for the Java applet is the moveMyCone
method. Therefore, whenever the script is invoked in the Script
node, this method is invoked in the Java applet. In this example,
this happens when the actual animation is performed.
The method simply finds the position and rotation information
for the current step in the animation and assigns the appropriate
position vector and rotational properties for export out of the
Java applet. The ROUTE statements
in the VRML file found in Listing 41.3 take the data exported
from the Java applet and update the correct object nodes appropriately.
Note
Notice that the exported properties (myConeTr and myConeRt) for the Java applet in Listing 41.4 are set using the setValue method. This is essential since the rotational and translation values are treated as arrays of
floating-point numbers in the Java applet, but must be converted to appropriate vectors for VRML.
The moveMyCone method also
updates the pointer to the current frame in the animation and
verifies that it has not gone past the beginning or the end of
the animation. If it has crossed the bounds at either end, the
direction of the animation is reversed by changing the steps in
the sequence to increment or decrement. The end result is an animation
that appears to swing back and forth.
Note
Because a number of steps are played for a consecutive number of times to create the animation, it is tempting to think that a loop would be appropriate to use in the moveMyCone method. Although loops can be used, this particular animation is
supposed to constantly run in the background. The TimeSensor found in the VRML source for this example indicates that an action should be taken every 250 milliseconds. Therefore, every 250 ms the cone's position and rotation can be updated. The
TimeSensor keeps the VRML world in sync, particularly if other VRML objects are animated with the cone.
In addition, some machines may execute Java code faster than others. If the animation were accomplished completely with a loop, the speed of the animation would vary depending on the machine. Not to mention that a continuous loop may occupy all of the
applet's running time and not allow other actions to occur.
Summary
This chapter introduced you to the fundamentals of VRMLScript
and the techniques required to attach VRML objects to programmable
scripts. You learned the basics of controlling a VRML world with
a Java applet and can hopefully expand upon that knowledge to
create some truly unique, entertaining, and interactive worlds
of your own.
Wyszukiwarka
Podobne podstrony:
ch41CH41 (2)ch41ch41ch41ch41ch41ch41 (3)ch41ch41ch41ch41ch41ch41CH41ch41ch41ch41więcej podobnych podstron