Given by Hasan Ozdemir (Geoffrey C. Fox) at CPS616 -- Information Track of CPS on Spring Semester 98. Foils prepared March 18 1998
Outside Index
Summary of Material
Script Nodes essentially give logic and state management to a VRML world. |
We describe Java and JavaScript Scripting of nodes internal to a VRML world |
Then we discuss the External Authoring Interface EAI allowing outside programs to interact with a VRML application on client side |
Examples including Multi-User Worlds are given |
Outside Index Summary of Material
Hasan Ozdemir ( Presented Geoffrey Fox) |
NPAC |
Syracuse University |
111 College Place |
Syracuse NY 13244-4100 |
Script Nodes essentially give logic and state management to a VRML world. |
We describe Java and JavaScript Scripting of nodes internal to a VRML world |
Then we discuss the External Authoring Interface EAI allowing outside programs to interact with a VRML application on client side |
Examples including Multi-User Worlds are given |
VRML defines a simple 3D content definition language but this structure does not allow to define a complicated dynamic behaviors. |
Script node intends to overcome this issue by allowing the execution of ECMAScript (essentially JavaScript) or Java code so that developer can program the behavior as much complex as possible. |
Why do we need scripts? Without Scripts ...
|
VRML execution model is based on Events. Each node has fields which describes the state of an object and events change the value of the (exposed)fields and hence the state of the object. |
Based on Event Model, each field can be one of those categories:
|
A ROUTE defines the path between event producer and consumer so that events can flow from one node to another. |
Cascading with ROUTE: |
ROUTE A.xxxx_changed TO B.set_yyyy |
ROUTE B.yyyy_changed TO C.set_zzzz |
Fan-Out with ROUTE: |
ROUTE A.xxxx_changed TO B.set_yyyy |
ROUTE A.xxxx_changed TO C.set_zzzz |
VRML97 standard recommends ECMAScript and Java code execution and both model is based on the Event Model. |
External Authoring Interface (EAI) is added by browser writers to support API based programming from other client programs to VRML. EAI is not within the standard but it is supported by almost all VRML Browsers. |
The javascript: protocol allows the script to be placed inline as follows: |
Script { url "javascript: function foo( ) { ... }" } |
The url field may contain multiple URL's and thus reference a remote file or inline code: |
Script { |
url [ "http://foo.com/myScript.js", |
"javascript: function foo( ) { ... }" ] |
} |
The file extension and MIME type for ECMAScript source code is .js and application/x-javascript. |
initialize() is invoked before the browser presents the world to the user and before any events are processed by any nodes in the same VRML file as the Script node containing this script. |
shutdown() is invoked when the corresponding Script node is deleted or when the world containing the Script node is unloaded or replaced by another world. |
eventsProcessed() is called after some(one or more depends on implementation) set of events has been received. |
function's name is the same as the eventIn field's name and is passed two arguments, event value and its timestamp(SFTime). |
Script {
|
} |
Whenever set_position event occurs, set_position() method is being called. |
Whenever the value of the corresponding variable changes, an output event will be produced. |
Script {
|
} |
Browser object is predefined object which lets script to get or set browser information. |
This interface allows script to do the followings:
|
The url field of the Script node may contain URL references to Java bytecode as illustrated below: |
Script { |
url "http://foo.co.jp/Example.class" |
eventIn SFBool start |
} |
The file extension for Java bytecode is .class. |
The MIME type for Java bytecode is defined as application/x-java. |
The class should be extended from vrml.node.Script. |
initialize() and shutdown() methods of vrml.node.Script class is exactly the same we saw in ECMAScript version. |
processEvents(int count, vrml.Event evts[]) is called when the script receives some set of events. |
count indicates the number of events delivered. evts is the array of events delivered. |
vrml.Event object is defined as follows: |
public class Event implements Cloneable { |
public String getName(); // name of the event |
public ConstField getValue(); // value of the event |
public double getTimeStamp();// timestamp of the event |
// other methods ... |
} |
developer can overload processEvents( ) or processEvent(vrml.Event evt) since default behavior in processEvents() is to call processEvent() for each received event. |
Field getField(String fieldName) |
Field getEventIn(String fieldName) |
Field getEventOut(String fieldname) |
Field getExposedField(String fieldName) |
let the Java code get the handle of the corresponding fields in the Script node. |
Calling one of the setValue(), set1Value(), addValue(), insertValue(), clear() or delete() methods on an eventOut/eventIn sends that event at that time. |
DEF SomeNode Transform {} # A transform node (flush out!) |
Script { # A Script node |
field SFNode node USE SomeNode # SomeNode is a Transform node |
eventIn SFVec3f pos # new value to be inserted in |
# SomeNode's translation field |
url "Example3.class" |
} |
# while Example3.class is: |
public class ExampleGetAnotherNode extends Script { |
private SFNode node; // field |
public void initialize() |
{ node = (SFNode) getField("node"); } |
} |
It is possible to access any field of the node object. |
vrml.Browser object provides all the features we saw in Browser object in ECMAScript. |
public class ExampleGetBrowser extends Script { |
private MFString target_url; // field (see VRML for reason for this) |
private Browser browser; |
public void initialize(){ |
target_url = (MFString)getField("target_url"); |
browser = this.getBrowser(); |
} |
} |
Critical Link |
The External Authoring Interface (EAI) allows Java to control a VRML world externally. |
This allows VRML to be part of a larger multimedia web presentation. |
The EAI allows much of the same functionality as the JSAI (JavaScript Authoring Interface). You can send events to VRML nodes, create new nodes, and query the VRML world about its state and characteristics. |
import vrml.external.field.*; |
import vrml.external.exception.*; |
import vrml.external.Node; |
import vrml.external.Browser; |
public class ExampleGetBrowser extends Applet { |
Browser browser; |
public void start() |
{ browser = (Browser) vrml.external.Browser.getBrowser(this); } |
} |
vrml.external.Browser is object supports the same feature we saw before in JSAI. |
By using the name you gave in the DEF, you can get the handle of particular node with the help of Browser object. |
// Get handle to the ROOT Node where there is a DEF ROOT in VRML file |
try |
{ root = browser.getNode("ROOT"); |
System.out.println("Got the ROOT node: " + root); |
} catch (InvalidNodeException e) |
{ System.out.println("PROBLEMS!: " + e);} |
First you get the handle of the eventIn field and then whenever you update its value, you will produce event for this sink. |
EventInSFVec3f set_translation; |
transform = browser.getNode("aNode"); |
set_translation = (EventInSFVec3f) transform.getEventIn("translation"); |
float [] val = new float[3]; |
val[0] = val[1]= val[2]=10.0; |
set_translation.setValue(val); |
DEF aNode in VRML File |
Field in transform node |
By creating an implementation of EventOutObserver( callback()) interface and passing the reference (advise()) of the appropriate object to the eventOut object, you can collect the incoming events. |
public class ExampleEventCollector implements EventOutObserver { |
public void start() { |
translation_changed = (EventOutSFVec3f)transform.getEventOut("translation"); |
translation_changed.advise(this,null); |
} |
public void callback(EventOut event, double time, Object userData) { } |
} |
http://www.npac.syr.edu/users/timucin/Vrml/JavaScriptNode/AddExam/JSEx1.wrl |
http://www.npac.syr.edu/users/timucin/Vrml/JavaScriptNode/AddExam/JSEx1.wrl |
DEF TIME1 TimeSensor { cycleInterval 3 } |
DEF INTERP1 PositionInterpolator { |
key [ 0.0 0.25 0.5 0.75 1.0] |
keyValue [ 3.0 0.0 0.0 3.0 -.95 0.0 3.0 0.0 0.0 3.0 +.95 0.0 3.0 0.0 0.0 ] } |
DEF T1 Transform { |
children Shape { geometry Sphere{} } |
translation 3.0 0.0 0.0 } |
DEF T2 Transform { |
children [ DEF GO TouchSensor {} |
Shape { geometry Box{} }] |
translation -3.0 0.0 0.0 } |
T2 is a box and starts the action. Whenever user clicks on it, it starts the script Action1-> TimeSensor-> PositionInterpolator -> T1 |
DEF Action1 Script { |
eventIn SFTime clicked |
eventOut SFTime start |
url "vrmlscript: // Note: Cosmo Player 2.0 still wants to see vrmlscript |
function clicked(time) |
{ start = time; } " |
} |
ROUTE GO.touchTime TO Action1.clicked |
ROUTE Action1.start TO TIME1.startTime |
ROUTE TIME1.fraction_changed TO INTERP1.set_fraction |
ROUTE INTERP1.value_changed TO T1.set_translation |
Even though its JavaScript |
Previous example, we used PositionInterpolator to produce the position of the object. We can do this calculation in Script node and do not need to put all those points into the file. |
The following example replaces PositionInterpolator with the sin() function and moves the ball according to this function. |
Please click on the left hand side box. |
http://www.npac.syr.edu/users/timucin/Vrml/JavaScriptNode/AddExam/JSEx2.wrl |
http://www.npac.syr.edu/users/timucin/Vrml/JavaScriptNode/AddExam/JSEx2.wrl |
DEF Action1 Script { |
eventIn SFFloat clicked |
eventOut SFVec3f set_position |
url "vrmlscript: // Note: Cosmo Player 2.0 still wants to see vrmlscript |
function clicked(time) |
{ set_position[0] = 1.0+time*1; |
set_position[1] = Math.sin(time*6.28); |
set_position[2] = 0.0; |
}" |
} |
ROUTE GO.touchTime TO TIME1.startTime |
ROUTE TIME1.fraction_changed TO Action1.clicked |
ROUTE Action1.set_position TO T1.set_translation |
http://www.npac.syr.edu/users/timucin/Vrml/JavaScriptNode/AddExam/earth/earth_fighter.wrl |
http://www.npac.syr.edu/users/timucin/Vrml/JavaScriptNode/AddExam/earth/earth_fighter.wrl |
When you click on the Earth, it starts rotation and this also triggers Script node to provide an ecliptic path to Tie fighter object. |
In the next example we use Radio buttons to switch the Background node of the scene from one representation to another. In the example, we put the Script node definition into a PROTO definition so that we do not need to repeat the same code for three implementation. |
http://www.npac.syr.edu/users/timucin/Vrml/JavaScriptNode/AddExam/JSEx3.wrl |
http://www.npac.syr.edu/users/timucin/Vrml/JavaScriptNode/AddExam/JSEx3.wrl |
PROTO scriptControl [ eventIn SFBool set_boolean |
eventOut SFBool true_changed |
eventOut SFBool false_changed ] { |
Script { |
eventIn SFBool set_boolean IS set_boolean |
eventOut SFBool true_changed IS true_changed |
eventOut SFBool false_changed IS false_changed |
url "vrmlscript: |
function set_boolean( bool, eventTime ) { |
if ( bool == true ) { true_changed = true; } |
else { false_changed = true; } |
}" |
} |
}# end of PROTO scriptControl |
How to define different scripts where scriptControl defined as a prototype |
DEF Filter1 scriptControl {}, |
DEF Filter2 scriptControl {}, |
DEF Filter3 scriptControl {} |
How to define ROUTE |
ROUTE BackButton1.cc_isActive TO Filter1.set_boolean |
ROUTE Filter1.true_changed TO Back1.set_bind |
EAI is used to link several VRML instances together |
Vnet is one example for the Multi User environment definition. It has a central server and everybody talks to the same server. It is downloadable from |
ftp://cslub.uwaterloo.ca/pub/u/sfwhite/ |
We developed the similar prototype at NPAC, based on JSDA (A Java collaboration proposed standard) as a collaboration technology. It is downloadable from |
http://osprey7.npac.syr.edu:1998/iwt98/projects/tvr/intropage/tvr.html |
It is possible to add a new object to the scene by using createVrmlfromString() method of the Browser object. |
http://www.npac.syr.edu/users/timucin/Vrml/JavaScriptNode/AddExam/JSEx5.wrl |
http://www.npac.syr.edu/users/timucin/Vrml/JavaScriptNode/AddExam/JSEx5.wrl |
DEF Box1 Transform { ... DEF Start TouchSensor {} ...} |
DEF DATA Transform { } |
DEF BxAction Script { |
eventIn SFBool isActive |
field SFNode node USE DATA // A node to add these objects |
field SFInt32 cone_count 0 |
url "vrmlscript: |
function isActive(value,time) |
{ if(value==true) |
{ node.addChildren = Browser.createVrmlFromString(' DEF Bx_'+ |
cone_count+' Transform { children Shape { geometry Box {} }}'); |
cone_count++;} |
}" } |
ROUTE Start.isActive TO BxAction.isActive |
http://www.npac.syr.edu/users/timucin/Vrml/JavaScriptNode/AddExam/lamp/lamp2.wrl |
http://www.npac.syr.edu/users/timucin/Vrml/JavaScriptNode/AddExam/lamp/lamp2.wrl |
When you click on the stand of the lamp, light will be turn off. With the next click on the stand, it will turn on again. |