VRML++: Adding Classes to VRML

VRML++ source of this logo

Stephan Diehl, Universität des Saarlandes

Download
Examples

see also


Abstract

We present a new object-oriented language called VRML++ which extends VRML 2.0. The new features of VRML++ are classes and inheritance, an improved type system and dynamic routing. As a net result we get inclusion polymorphism and dynamic binding. We argue, that these features are essentials of object-oriented programming languages. Furthermore using these new features it is possible to define abstractions of routing structures which we call connection classes. VRML++ increases reuseability of specifications while reducing run-time errors. Finally we discuss our implementation of VRML++.


Introduction

In VRML 1.0 we can reuse nodes by instantiating them (DEF/USE) and then applying transformations and changes of field properties. In VRML 2.0 prototypes provide a more powerful mechanism to define node types and create instances of these node types. By introducing scripts, events and routes VRML 2.0 added programming language concepts and thus behavior to VRML scenes. We would like to reuse and parameterize such behavior. This is possible to some extend in VRML 2.0, but when we look at programming languages, reuse of code was greatly simplified by the development of object-oriented programming languages (OOPLs). Huge libraries of classes are common to object-oriented languages and make programming an easier task. In software-engineering object-oriented analysis and design is propagated as the way to manage the development of large scale applications. Cox (90) predicts a revolution in software industry by reuseable, reliable, abstract software components which can be plugged together to create new applications. At any time a component can be replaced by a more efficient one, which provides the same interface.

VRML++ and Authoring Virtual Worlds

The object-oriented features of VRML++ and its improved type system increase reuseability of specifications and prevent run-time errors in animated VRML scenes. VRML++ provides a better way to structure huge libraries of objects and behaviours.

VRML++ and Shared Virtual Worlds

We expect, that adding object-orientation to VRML will ease the design of shared virtual worlds in a similar way. Moreover using class libraries can help to solve one of the main problems in shared virtual worlds -- the bandwidth problem. Using classes we can reduce the amount of data to be send between browsers. Similar to the Java class library we would have the same library of objects and behaviours on each client. Thus messages would contain new class definitions or instantiations of classes.

Essential Features of Object Orientation

In VRML 2.0 we can use OOPLs within a Script node. The goal of our research is to lift object-orientiation into VRML. To achieve this we first have to identify key ideas of OOPLs.

The concepts of OOPLs we will deal with in this paper are

How object-oriented is VRML ?

In the paper "Sony's approach to behavior and scripting aspects of VRML: an Object-Oriented perspective" K. Matsuda, Y. Honda and R. Lea point out, that objects in VRML have properties, state variables and behaviors. Using standard terminology of the object-oriented programming community, this can only be considered object-based. The extension suggested by Park(97) is to replace ROUTEs and Scripts by Eventhandlers. He calls the resulting language OO-VRML. But his extension does not increase object-orientation. The work of Curtis(97) shows that there is a need for object hierarchies or even better class hierarchies when it comes to implementing simulations involving behaviours in VRML. He tries to use VRML 2.0 and Java to this end, but because of the lack of inheritance in VRML his implementation becomes complicated.

In our view the concepts present in VRML 2.0 correspond roughly to those of OOPLS as follows: prototypes are classes without inheritance, nodes are objects, events and Script nodes, which process events are methods, fields are variables. But VRML lacks inheritance, the essential feature of object-orientation. Furthermore in VRML there is no elaborate type system and thus neither dynamic binding nor inclusion polymorphism.

Inheritance

In this section we explain how inheritance works in VRML++. If we define a new prototype B to be a sub-prototype of another prototype A, then it has all the events and fields of A. But B can change some of these events or fields or add new ones. We say, B inherits from A. The problem is, that if we program this in VRML 2.0 using prototypes, we also have to list all fields and events which remain unchanged. This makes the specifications hard to read and maintain. To solve this problem, we extend the syntax of VRML 2.0 and use a preprocessor, which converts the extended syntax into standard VRML 2.0 syntax.

Classes

The following example shows the basic idea of how we use classes in VRML++. Assume, we have a prototype Robot which provides the input events walk and jump. Now we want to define a new prototype MyRobot which only differs from Robot in that it provides a different implementation of the event walk.
CLASS Robot [eventIn SFTime walk
             eventIn SFTime jump]
 { ...
   Script { field SFNode self USE SELF
            eventIn SFTime walker IS walk
            url "vrmlscript: function walker(value) ...."
          }

   Script { field SFNode self USE SELF
            eventIn SFTime jumper IS jump
            url "vrmlscript: function jumper(value) ...."
          }
 }

CLASS MyRobot [eventIn SFTime walk]
   EXTENDS Robot
 {    
   Script { eventIn SFTime runner IS walk
            url "vrmlscript: function runner(value) ...."
          }
 }
Note, that the jump event, which was not changed is passed on to Robot.

In a class definition SELF denotes the instance of the class, when it is instantiated. More precisely: if the class inherits only form SFNode, then SELF denotes the first node in the class definition. Otherwise, it denotes an instance of the first superclass. A class can inherit from other classes, from other prototypes or from standard VRML nodes like Sphere or Transform. The top class of the inheritance hierarchy is always SFNode.

Multiple Inheritance

In VRML++ it is also possible for a class to have several superclasses. In this case every field and event is only inherited from the first class in the list of superclasses which supports it. In other words the values of fields and events are only propagated to the first superclass providing it.

Improved Type System and Inclusion Polymorphism

The lack of a powerful type system in VRML 2.0 can lead to many errors at run-time. Usually these errors are reported when a node is instantiated which tries to add a route to an event not supported by a node. The situation becomes worse when we create new nodes at run-time or allow dynamic routing (see below). To make sure at compile-time, that a node passed to another node has a certain event or field, we add user defined types to VRML. As a result we also get inclusion polymorphism.
CLASS MoveAble [eventIn SFTime move] EXTENDS SFNode
 { ...
 }

CLASS MyRobot [eventIn SFTime walk
               field MoveAble legs ... ] EXTENDS Robot
 { ...
   ROUTE walk TO legs.move
 }
In this example we require, that legs is of type MoveAble and not just of type SFNode as in VRML. Since by definition all instances of MoveAble have an event move there can not be a run-time error like "Error: Cannot route to a node, that does not provide EventIn move ".

Dynamic Binding / Dynamic Routing

What we would like to do, is to get a node at instantiation- (as a value of a field) or run-time (as a value of an event or exposedField) and invoke one of its methods. In VRML 2.0 we can do the following:
PROTO Example []
 { 
   DEF EX1 node{}
   DEF EX2 node{}
   ROUTE EX1.out TO EX2.in
 }
The following three examples show the dynamic routing features of VRML++:
PROTO Example1 [field SFNode node1 ...
                field SFNode node2 ...]
 { ...
   ROUTE node1.out TO node2.in
 }

PROTO Example2 [field MFNode node1 ...
                field MFNode node2 ...]
 { ...
   ROUTE node1.out TO node2.in
 }
Such dynamic routing can be implemented by using a Script node and the function addRoute() of the browser script interface (see 4.7.10 in the VRML 2.0 specification).

In combination with the type system of VRML++ we get dynamic binding, i.e. what method (Script implementing an eventIn) is actually called depends on the type at run-time. For example consider the classes Robot and MyRobot defined above. If we define a a class WalkRobot as follows and instantiate it, it is not clear until run-time whether the function walker or jumper is invoked:

CLASS WalkRobot  [ field TimeSensor trigger NULL
                   field Robot robot NULL
                 ] EXTENDS SFNode
 { ROUTE trigger.time TO robot.walk
 }
If the value of robot is an instance of class Robot then walker is called, if it is an instance of MyRobot then jumper is called.

By using the keyword UNROUTE instead of ROUTE routes can also be dynamically deleted. As an example an object can be statically routed to a touch sensor. If the user clicks at it, the object is dynamically routed to some other node and by some other event, e.g. when clicking at another sensor node, this route is deleted again.

Connection Classes

Using dynamic routing we can define connection classes. A connection class abstracts a routing structure, i.e. a connection class is a generic set of routes which can be instantiated. For example a class FanOut which given a TimeSensor will propagate the event fraction_changed to a set of other nodes, e.g. Interpolators.
CLASS FanOut [field TimeSensor trigger NULL
              field MFNode targets []
             ] EXTENDS SFNode
 { ROUTE trigger.fraction_changed TO targets.set_fraction
 }

DEF O1 OrientationInterpolator { ... }
DEF O2 OrientationInterpolator { ... }
DEF TS TimeSensor{ ... }
               
FanOut { trigger USE TS
         targets [ USE O1 USE O2 ]
       }
Another typical connection class is Filter which routes different source nodes like sensors to a filter, e.g. an Interpolator, and routes the result of this filter to several target nodes.
CLASS Filter [field MFNode sources [] 
              filter OrientationInterpolator filter NULL
              field MFNode targets []
             ] EXTENDS SFNode
 { ROUTE source.fraction_changed TO filter.set_fraction
   ROUTE filter.value_changed TO targets.set_rotation
 }
The following example shows that one can use a connection class (here: MoveBall) to add an interface to another class.
#VRML++ draft utf8

CLASS Ball [] EXTENDS SFNode
 {  Transform { children Shape { geometry Sphere { } } }
 }

CLASS MoveBall[ field TimeSensor timer NULL
                field PositionInterpolator interpol NULL
            ] EXTENDS Ball
  { 
    ROUTE timer.fraction_changed TO interpol.set_fraction
    ROUTE interpol.value_changed TO SELF.set_translation
  }


DEF PI PositionInterpolator 
  { key [ 0, 0.5, 1 ]
    keyValue [ -1 0 0, 1 0 0, -1 0 0 ]
  }


DEF TS TimeSensor { startTime 1 stopTime 0 loop TRUE }

DEF DD MoveBall { timer USE TS
                  interpol USE PI }
Here SELF is a special node name denoting the current instance of this class. Instead of wrapping the connections around the class we could write, which is almost the expansion of the above definition of MoveBall:
#VRML++ draft utf8

CLASS MoveBall[ field TimeSensor from NULL
                field PositionInterpolator to NULL
            ] EXTENDS SFNode
  { DEF BALL Transform { children Shape { geometry Sphere { } } }
    ROUTE from.fraction_changed TO to.set_fraction
    ROUTE to.value_changed TO BALL.set_translation
  }

...

Implementation

We are currently implementing a preprocessor which translates VRML++ files into VRML 2.0 files. By using such a preprocessor VRML++ becomes very portable and can be used with every VRML 2.0 browser. Currently our preprocessor is able to translate class definitions with multiple superclasses and dynamic routing based on SFNode/MFNode fields and events. We are working on the implementation of the static type checking on the basis of the improved type system right now.
You can download of the current version of our preprocessor. For the executables you will also need the initialization file standardClasses.vpp. The VRML 2.0 code generated by the preprocessor was tested with the WorldView browser. The preprocessor was written in C++ using GNUs g++, the standard template library, bison and flex. The original VRML 2.0 parser underlying our preprocessor was implemented by Gavin and Woods for Borland's C++ 5.0 and Microsoft's MSDEV C++ 4.0. So it should be fairly portable. For dynamic routing we use Script nodes with functions in VrmlScript code. As we only use the browser interface, we could generate Java source as well.

Usage

To convert a VRML++ file sample.wrl into a VRML 2.0 file sample20.wrl you can type:
vpp sample.wrl > sample20.wrl
In this case VRMLScript is used in Script nodes. To use JavaScript instead you have to type:
vpp -js sample.wrl > sample20.wrl
If not specified otherwise the initialization file standardClasses.vpp is looked up in the local directory. To use a different initialization file or put it in a different path type:
vpp -init /usr/lib/vrml++/standardNodes.wrl sample.wrl > sample20.wrl

Future Work

To prove the claims and design goals of VRML++ in practice we will have to write object and behaviour libraries and combine these with authoring tools. Another interesting project would be to integrate VRML++ into an implementation of a shared virtual world to see, whether it can reduce the network traffic.

Examples

References


Curtis (97)
  Curtis A. Beeson,
  "An Object Oriented Approach to VRML Development", 
  VRML'97

Park (97)
  Sungwoo Park
  "Object-Oriented VRML for Multi-user Environments", 
  VRML'97

Cardelli and Wegner (1985),
   L. Cardelli and P. Wegner,
   "On Understanding Types, Data Abstraction and Polymorphism", 
   ACM Computing Surveys, volume 17(4), 1985

Cox (90),
   Brad J. Cox,
   "Planning the Software Industrial Revolution:
    The Impact of Object-Oriented Technologies", 
   IEEE Software, 1990

Sony (96),
   K. Matsuda, Y. Honda and R. Lea
   "Sony's approach to behavior and scripting aspects of VRML: 
    an Object-Oriented perspective",
   http://www.csl.cony.co.jp/project/vs/proposal/behascri.html

VRML 2.0 Specification
   http://vag.vrml.org/VRML2.0/FINAL/    

Hartman and Wernecke (1996)
   Jed Hartman and Josie Wernecke
   "The VRML 2.0 Handbook - Building Moving Worlds on the Web",
   Addison-Wesley, 1996