ENHANCING VRML97 SCRIPTING

Andrew Davison
Department of Computer Engineering
Prince of Songkla University
Hat Yai, Songkhla 90112, Thailand
E-mail: dandrew@ratree.psu.ac.th

KEYWORDS

VRML 2.0 Standards; Rule Based Programming.

ABSTRACT

VRML97, the 3D modeling language, has restrictive mechanisms for specifying node behaviour and inter-node communication, which makes it difficult to write applications where visual elements dynamically change.

Three related extensions to the language are proposed: the formulation of node behaviour as condition/action rewrite rules, the introduction of tuple spaces for more powerful node coordination, and augmentations to node naming. The utility of these extensions are illustrated through examples.

INTRODUCTION

VRML97 is a 3D modeling language based around the notion of a hierarchical scene graph made up of nodes of various types (VRML Consortium 1997a). The behaviour of a node can be programmed using a script node, which is triggered by the arrival of an event. The scene author must explicitly direct events to the node by using ROUTE commands, which require all the nodes or fields involved to be named. Output from a script node consists of events sent to other nodes along declared routes, or changes to fields in named nodes (VRML Consortium 1997b, Marrin and Couch 1999).

There are three problem areas related to this kind of scripting:

  1. Script node behaviour. A script node has a limited triggering mechanism based on the arrival of a single event. For example, it is not possible to specify a trigger which waits for a conjunction of events to occur.
  2. Inter-node communication. Events must be explicitly routed to script nodes, which makes it quite cumbersome to encode dynamically changing patterns of communication. In general, all communication must take place between named entities, which hinders the use of techniques such as anonymous communication or multicasting.
  3. Node naming. VRML only permits references to named nodes defined in the original scene file. This makes interaction with dynamically added nodes problematic. Names can only be constants, and lack the scoping inherent in the scene graph structure.

These drawbacks motivate the following proposals:

  1. Encode node behaviour using condition/action rewrite rules. Rule conditions should respond to conjunctions of events and other types of data, and be tested atomically. Such rules will subsume the existing VRML scripting model, simplifying it.
  2. Communication augmented with tuple spaces. Script nodes should be able to utilise tuple spaces (Carriero and Gelernter 1989) via their rewrite rules. This will permit additional forms of communication between nodes, which will be particularly useful when scenes are dynamically changing or when the computation involves parallelism.
    Combining rewrite rules and tuple spaces will also have a beneficial influence on the semantics of the enhanced script nodes, which will be able to view the scene graph as a hierarchical multiset. This will allow the operations used to manipulate nodes, fields, and tuples to be explained in a similar manner.
  3. Node naming extensions. VRML should permit equal access to nodes whether they have been statically or dynamically inserted into the scene. In addition, names should be parameterised so that they can be selected via pattern matching. The naming policy for PROTO nodes should also be modified so that node names inside a PROTO node can be referenced relative to the PROTO node's name.

VRML97 SCRIPTING

A script node may have many typed fields. However, each field must have one of four possible modes. These are: field (the field holds local data, visible only to the node), eventIn (the field can receive incoming events), eventOut (the field can send events), and exposedField (the field holds data that is visible outside the node, which can be read and set).

When an event arrives at a script node in an eventIn field, it is passed to the code linked to the node, computation is carried out, and the code sends output to the scene by assigning an event to an eventOut field in the script node. Communication relies on ROUTE commands which link eventIns and eventOuts between nodes.

A slightly different style of programming is to assign a node name to a field in the script node. This reference is passed to the code, where it is then possible to directly manipulate the node's fields. This approach is utilised in Figures 1 and 2 (taken from (Lea et al. 1996)).


DEF MOVER Transform {
translation 10 0 0
children [
DEF TS TouchSensor {}
Shape {
appearance Appearance {
material DEF SphereColor Material {
diffuseColor 1 0 0 } } # red
geometry Sphere {}
} ]
}

DEF MoveIt Script {
url "MoveIt.class"
eventIn SFBool clicked
field SFNode node USE MOVER
}

ROUTE TS.isActive to MoveIt.clicked

Figure 1: A Sphere and its Script Node.

public class MoveIt extends Script {
private SFNode theNode;
private SFVec3f position;


public void initialize()
{ theNode = (SFNode)getField("node"); }

public void processEvent(Event e) {
ConstSFBool v = (ConstSFBool)e.getValue();
Node node;
if (v.getValue()) {
node = (Node)(theNode.getValue());
position = (SFVec3f)

node.getExposedField("translation");
position.setValue(
(position.getX()+5), 0, 0);
} }
}

Figure 2: Java code for the Script Node in Figure 1.

In Figure 1, the Transform node called MOVER contains a touch sensor called TS and a sphere (whose material component is called SphereColor). The Script node called MoveIt has one eventIn and a node field which references MOVER. The ROUTE connects the touch sensor's IsActive eventOut field to the clicked eventIn field of MoveIt. IsActive is triggered when the user clicks on the sphere.

Figure 2 uses Java to program the script node. The arrival of an event triggers processEvent(). If the boolean cast of the event has the value True (i.e. the sphere was touched) then the translation field of MOVER has its X-coordinate incremented by 5.

Figures 1 and 2 use VRML's Script Authoring Interface (SAI) (VRML Consortium 1997b), where code is conceptually part of a script node. An alternative approach is to use the External Authoring Interface (EAI) (Marrin and Couch 1999) which allows a separate Java applet to communicate with the script node. The features detailed in this paper center on augmenting node behaviour and so are more closely aligned with the SAI. However, they could be applied to the EAI since both use VRML's event model.

SCRIPTING EXTENSIONS

The unifying idea behind our extensions is the semantic rephrasing of VRML. Instead of viewing a VRML scene as a graph consisting of a tree of nodes, it is treated like a hierarchical multiset consisting of multisets and/or fields. Each named node becomes a named multiset which, by virtue of its name, can be assigned extra children or have children removed. A multiset (a node) can consist of VRML fields (i.e. eventIns, eventOuts, exposedFields and fields), and these can be manipulated in restricted ways related to their modes. Multisets representing script nodes may include a new type/mode, tupleSpace, which supports Linda-style operations (i.e. in(), out(), read()).

At the programming level, rewrite rules utilise operations which assume a Logic Programming (LP) representation for the multisets (nodes) and fields. Each VRML name is translated into a functor, but with its first letter in lowercase to make it an atom. A VRML element whose body may contain a variable number of elements is represented by a functor of arity 1 whose single argument is a multiset (denoted using {…}). A VRML element whose body may contain a fixed number of elements (say N) is represented by a functor with N arguments.

Node names are enhanced so they can contain parameters. Such names are treated as LP terms, and can be matched against using unification. Named nodes inside a PROTO node can be accessed using a '.' notation.

Using multisets and LP, MOVER in Figure 1 can be rewritten as in Figure 3.

{ def(tS, touchSensor({})),
def(sphereColor, material({
diffuseColor(1,0,0) })),
def(mOVER, transform({
translation(10,0,0),
children({ use(tS),
shape({
appearance( appearance({
material(use(sphereColor)) })),
geometry(sphere({}))
})
})
})) }

Figure 3: MOVER in LP form.

One thing to note is that any node will implicitly contain all the fields of its node type. For example, the Transform node of MOVER in Figures 1 and 3 has an implicit rotation field with a default value.

The behaviour of a script node is programmed with LP style rewrite rules.

The condition part of a rule is executed atomically, and the conditions of all the rules in a node may be tested in OR-parallel. Several rules may succesfully evaluate their conditions, and then a single rule is chosen non-deterministically to have its action part carried out. This execution style is very similar to rules in committed choice non-deterministic LP languages (Shapiro 1989). Any bindings in the condition part of a rule only become visible when the rule is 'committed to'.

Several script nodes may be evaluating their rules in this manner, and so there is potential for AND-parallelism between nodes.

Operations used by rules can refer to nodes (multisets) based on their names.

A rewrite rule has the form:

cond1, ..., condN --> act1, ..., actM.

where the condition operators (cond) and action operators (act) are:


cond ::= [NodeName:] in(FN/mode, V) |
[NodeName:] read(FN/mode, V) |
PrologGoal

act ::= [NodeName:] read(FN/mode, V) |
[Ground_NodeName:] out(FN/mode, V) |
[Ground_NodeName:] set(FN/mode, V) |
PrologGoal

FN/mode is a field name with its mode attached. Frequently, a mode can be left off the field name since it is obvious by the node context. V is a variable or a (partially) instantiated term. NodeName may be a constant or a partially instantiated term. Ground_NodeName is a ground node name, which is used by output operations to simplify their meaning.

The operations follow the standard Linda style, but have varying behaviours depending on the mode of the field name.

With in(), if the mode is eventIn then no node name must be prepended to the operation. The call blocks until an event arrives at the local eventIn field and then returns its value. If the mode is eventOut then a node name must be given. The operation blocks until an event can be removed from the eventOut field of the named node. This use of in() removes the need to explicitly route eventOuts to eventIns in the script node. When the mode is tupleSpace then the field name refers to the tuple space variable in the named script node. V will be bound to a tuple from that space, and the selection can be guided by supplying a partially instantiated V term. If the field name is children then in() removes a child from the node.

read() can read fields with the modes field, exposedField and tupleSpace, although if the mode is field then only local rules can access the field's value.

When the mode is eventOut, out() places an event in an eventOut field. If the mode is eventIn then an event is placed in the eventIn field of another node. If the mode is tupleSpace then a tuple is added to the specified dataspace. If the field name is children then a child node is added to the named node.

With set(), the mode can be field or exposedField, and updates an existing field.

Prolog goals can appear in the conditions and actions. However, condition goals are restricted to calls to built-in predicates, in a similar style to flat concurrent LP languages (Shapiro 1989). Goals on the action side of a rule can call user-defined predicates which may contain action operations.

If the action part of a rule fails for some reason, perhaps due to an operation being applied to a non-existent node or field, then the rule fails as a whole. No attempt is made to undo operations carried out already.

EXAMPLES

Three examples will be discussed: the first is a recoding of the example in Figure 2, which shows that condition/action rules capture the existing VRML event model and make it easier to understand. The next example shows how rules can handle node interactions impossible with the event model. The third example outlines how a cellular automata can be programmed with tuple-based communication.

Moving a Sphere

The MoveIt script of Figure 2 is recoded as in Figure 4.


Def MoveIt Script {
tS:in(isActive, true) -->
mOVER:read(translation,

translation(X,_,_) ),
X1 is X + 5,
mOVER:set(translation,

translation(X1,0,0) ).
}

Figure 4: Moving a Sphere with a Rule

Almost all Java-based scripts follow a format like the code in Figure 2 due to the constraints of the VRML event model, and so can be recoded in a similar manner to Figure 4.

Turning Spheres Blue

Assume the existence of a VRML scene made up of red spheres moving in random directions. The aim is to trigger a colour change in any two spheres which pass through the same point at the same moment, making both turn blue.

The scene can be implemented by defining a MovingSphere PROTO node to group together a sphere, a position interpolator and a time sensor. Using the extended naming scheme, all the moving spheres can be labelled in a uniform fashion:

Def msphere(1) MovingSphere { ... }
Def msphere(2) MovingSphere { ... }
:

Each sphere inside a PROTO node is defined in a similar way to the Transform node in Figure 1. The '.' notation means that the named nodes inside a PROTO node instance can be referenced as msphere(i).mOVER and msphere(i).sphereColor, where i is a given instance number.

A script node is also added to the scene, whose task is to monitor the spheres. When any two spheres move, their locations are tested and if they are at the same coordinates then their colours are changed to blue. The script node is shown in Figure 5.


Def BlueSpheres Script {
msphere(X).mOVER:in(

translation_changed,Pos1),
msphere(Y).mOVER:in(

translation_changed,Pos2),
X /== Y -->

change_colour(Pos1, Pos2, X, Y).

change_colour(Pos,Pos,X,Y) :- # same posn

msphere(X).sphereColor:set(
diffuseColor, color(0,0,1)),
msphere(Y).sphereColor:set(
diffuseColor, color(0,0,1)).
change_colour(Pos1,Pos2,_,_) :-

Pos1 /== Pos2.
}

Figure 5: Turning Spheres Blue

A translation_changed event is generated whenever a sphere's translation exposedField is changed (by its position interpolator).

This rule illustrates the power of multiple in() conditions, which allow a rule to capture relationships between nodes. Also, the use of partially instantiated names permits a non-deterministic choice of events generated by similar nodes.

Cellular Automata

This example begins by dynamically adding a 100x100 grid of cells to the VRML scene. A cell is a PROTO node which uses a Switch group to display a green box when 'off' and a red sphere when 'on'. Each cell contains a script node which defines its behaviour, while a script node associated with the overall grid ensures that each cell displays its next 'state' only when all the other cells are ready to display theirs.

Figure 6 shows the empty scene and the gridRules script node.


Def grid Group {children [] } # no cells yet

Def gridRules Script {
tupleSpace gridTS {} # empty tuple space

ts.in(isActive,true) --> # create grid
create_grid(99,99),

out(gridTS,choice_stage).

in(gridTS, cellDone(N1)),
in(gridTS, cellDone(N2)) --> # count trans

Num is N1 + N2,
out(gridTS, cellDone(Num)).

in(gridTS, cellDone(10000)),
in(gridTS, choice_stage) --> # trans done
out(gridTS, rewrite_stage).

in(gridTS,rewriteDone(N1)),
in(gridTS,rewriteDone(N2)) --> # count rwts

Num is N1 + N2,
out(gridTS, rewriteDone(Num)).

in(gridTS, rewriteDone(10000)),
in(gridTS, rewrite_stage) --> # rwts done
sleep(3000),

out(gridTS, choice_stage).

# grid creation predicates
create_grid(-1, _).
create_grid(Row, Col) :-
Row >= 0, create_row(Row, Col),
Row1 is Row-1, create_grid(Row1,Col).

create_row(_, -1).
create_row(Row, Col) :-
Col >= 0, R is Row*4, C is Col*4,
Rand is random()%2,
grid:out(children, def(cell(Row,Col),
cell({position(R,C,0),choice(Rand)}) )),
cell(Row,Col).cellRules:
out(cellTS, cell(Row,Col)),
Col1 is Col-1, create_row(Row,Col1).
}

Figure 6: Empty Cellular Automata Grid and its Rules

We assume a touch sensor, called ts, which initially invokes the first gridRules rule. create_grid/2 adds a lattice of cell nodes to the scene; each cell is named cell(Row,Col), where Row and Col range from 0 to 99. The cell location is the first parameter of the cell PROTO node, calculated using the Row and Col values. The second is the switch choice field value which is randomly set to 0 (off) or 1 (on).

As a cell instance is added to the grid, create_row/2 also places a cell(Row,Col) tuple in the tuple space of the cell's script node. This is used by the script node to trigger its own execution.

At the end of the grid initialisation rule, a choice_stage tuple is added to the tuple space associated with the grid.

The other rules in gridRules will be explained after the cell PROTO node has been considered. Its code is given in Figure 7.


PROTO Cell [ field SFVec3f position
exposedField SFInt32 choice ]
{ Def shapeSW Switch {
whichChoice IS choice
choice [
Transform { # green box means off(0)

translation IS position
children [
Shape { appearance Appearance {
material Material {
diffuseColor 0 1 0}}
geometry Box {}
} ] }
Transform { # red sphere means on(1)

translation IS position
children [
Shape { appearance Appearance {
material Material {
diffuseColor 1 0 0}}
geometry Sphere {}
} ] }
] } # end of switch

Def cellRules Script {
tupleSpace cellTS {} # empty space

in(cellTS, cell(X,Y)),
gridRules:read(gridTS,choice_stage) -->
shapeSW:read(whichChoice, C),
XP is (X+1)%100, XM is (X-1)%100,
YP is (Y+1)%100, YM is (Y-1)%100,
cell(X,YM).shapeSW:read(
whichChoice, Cs),
cell(XM,YM).shapeSW:read(
whichChoice, Csw),
: # choices for other 6 neighbours

nextStep([C,Cs,Csw,Cw,Cnw,Cn,
Cne,Ce,Cse], NextChoice),
out(cellTS,newcell(X,Y,NextChoice)),
gridRules:out(gridTs,cellDone(1)).


in(cellTS, newcell(X,Y,NextChoice)),
gridRules:read(gridTS,rewrite_stage)-->
shapeSW:set(whichChoice, NextChoice),
out(cellTS, cell(X,Y)),
gridRules:out(gridTS,rewriteDone(1)).
} # end of script
} # end of PROTO

Figure 7: A Cell PROTO Node and its Rules

The cell consists of a Switch node called shapeSW and a script node called cellRules. The position parameter of the PROTO node is used to initialise the translation fields of the sphere and box Transform nodes. The choice parameter sets the switch choice field of the node.

The first rule of cellRules executes only when there is a cell/2 tuple in its tuple space and when gridRules contains a choice_stage tuple. Both conditions are met at grid initialisation time, and so all cell nodes can start executing in AND-parallel. The action part of the first rule reads the current choice setting for the cell and obtains the choice settings for its eight neighbours. They are accessed by calculating their node names from their row and column positions relative to the cell.

nextStep/2 implements the cellular automata transition, and returns a new choice setting. This is stored in the cell's tuple space as a newcell/3 term and the completion of the transition for that node is signalled to the grid by placing a cellDone(1) term in the tuple space of gridRules.

The description of the gridRules script node can now be completed. The second and third rules implement a parallel summation of the number of cells which have completed their transition. When cellDone/1 contains 10,000 (i.e. all the cells have recorded their next configuration), the choice_stage tuple is removed from the gridRules tuple space, and a rewrite_stage tuple is put in its place.

When a cell observes a rewrite_stage tuple in gridRules, it switches its choice setting to its next value. This can be done by all cells concurrently, and so the user will see a rapid global change of the grid to its new configuration. The cell rule also adds a cell/2 term to its tuple space, and puts a rewriteDone(1) term into the tuple space of gridRules.

The appearance of rewriteDone/1 terms in gridsRule's tuple space triggers its fourth rule: another parallel summation is carried out. When it reaches 10,000 (i.e. all the cells have updated their appearance), the fifth rule fires, goes to sleep for a short time, before a choice_stage tuple is put back into its tuple space.

The main feature highlighted by this example is the use of tuple spaces: one in the gridRules script node, and one in each cell node. The cellDone/1 and rewriteDone/1 tuples allow each cell to proceed in AND-parallel but also to be coordinated periodically -- when the cells start their next transition, and when they change their choice field to alter their appearance. These synchronisation points are handled by the choice_stage and rewrite_stage tuples in gridRules. The third type of tuple use is to store collections of data in a convenient format: the cell/2 and newcell/3 tuples.

This example does not use events at all, illustrating that tuples are sometimes a more natural mechanism for communication and coordination.

RELATED WORK

This paper views the VRML scene graph as a hierachical multiset. No other work has made this connection, although there are many models and languages which utilise multisets and condition/action rewrite rules.

Jinni is a Prolog interpreter written in Java which has support for distributed blackboards and multithreaded agents (Tarau 1999). It can be used as a scripting tool for controlling the interaction between Java objects in network application, and can be easily integrated with Java code. In particular, Jinni has access to a Java class interface to VRML's EAI. Jinni differs from our work in that it makes no changes to VRML's scripting model -- for example, its blackboards remain outside VRML.

Pavane is a visualization environment which is probably closest to our approach (Roman et al. 1992). It utilises multisets and rewrite rules, and can also define mappings from tuple states to 3D geometric objects (e.g. lines, spheres, polygons). Animation is dealt with by registering state change as event activations, and the smooth movement of the graphical entities are carried out by time-dependent functions. Pavane's rules are separate from the graphical scene, so it is not possible to give 3D objects their own behaviour as in our notation. Our rules also benefit from the modes, richer event model, sensors, and interpolators within VRML.

CONCLUSION

Rewrite rules generalise the event trigger mechanism used in VRML's SAI and EAI, allowing a rule to be activated by conjunctions of events and other data. Existing scripting applications can be readily rephrased, and become clearer. The proposed execution model permits the utilisation of AND- and OR- parallelism.

The addition of tuple spaces offers a range of extra communication metaphors not available to VRML's event driven approach. These are especially useful for programming dynamically changing applications. The tuple mechanism is integrated with the rewrite rules so that their semantics can be based on treating VRML's scene graph as a hierarchical multiset which is manipulated by tuple operations.

These modifications of VRML's scripting behaviour rely heavily on the augmentation of its restrictive naming mechanism for nodes. Statically and dynamically added nodes are handled in the same way, names can be parameterised, and a '.' notation is introduced for PROTO nodes.

REFERENCES

Carriero, N. and D. Gelernter. 1989. "Linda in Context", Communications. of the ACM, 32, No. 4, 444-458.

Lea, R., K. Matsuda and K. Miyashita. 1996. Java for 3D and VRML Worlds, New Riders Publishing.

Marrin, C. and J. Couch. 1999. External Authoring Interface (EAI) Working Group, Available at http://www.web3d.org/WorkingGroups/
vrml-eai/, Feb. 2001.

Roman, G-C., K.C. Cox, C.D. Wilcox and J.Y. Plun. 1992. "Pavane: A System for Declarative Visualization of Concurrent Computations", Journal of Visual Languages and Computing, 3, 161-193.

Shapiro, E. 1989. "The Family of Concurrent Logic Languages", ACM Computing Surveys, Vol. 21,
No. 3, Sept., 412-510.

Tarau, P. 1999. "Jinni: Intelligent Mobile Agent Programming at the Intersection of Java and Prolog", Proc, of PAAM'99, London, UK, April.

VRML Consortium. 1997a. "The Virtual Reality Modeling Language (VRML), Part 1: Functional Specification and UTF-8 Encoding", ISO/IEC 144772-1:1997, Dec. 1997, Available at http://www.vrml.org/technicalinfo/ specifications/vrml97/index.htm, Feb. 2001.

VRML Consortium. 1997b. "The Virtual Reality Modeling Language (VRML), Annex B: Java Platform Scripting Reference", ISO/IEC 14772-1:1997, Available at http://www.vrml.org/ technicalinfo/ specifications/vrml97/part1/java.html,
Feb. 2001.

AUTHOR BIBLIOGRAPHY

ANDREW DAVISON received his PhD from Imperial College, London in 1989. For five years he was a lecturer in the computer science department at the University of Melbourne, Australia. He has worked in Thailand since 1996. His current research interests are combining logic programming and the Internet, visualization, and teaching methodologies.