VRML Behaviors

This paper proposes a way to add behaviors to VRML. It address mainly the extensions needed to VRML to author links to seperate behavior scripts.

This document is part of a collection of VRML2.0 history at http://www.mitra.biz/vrml/vrml2/mw_history.html
This version: Mitra <mitra@mitra.biz>, 2 Dec 95.


History and Dependencies

This proposal is based on the 12th November version [1]. With changes made as a result of the VRML behaviors meeting in San Diego.

This paper draws heavily on discussions with, and the proposals by Sony [6], [7] [8] and SDSC [9], and is an attempt to merge the best ideas from these and my own papers.

This paper also reflects a number of concerns brought up by SGI, both in their behaviors paper [11], and in meetings.

Their are several other papers that should be considered part of this proposal, they are mostly orthogonal to this paper.

Changes since 12 Nov 95

Overview

Firstly - it appears that we are all looking for a Object-Oriented approach, but I think older proposals diverged from this to a certain extent. To be O-O the author should probably be thinking something like ...

An Object has:

If our O-O model is essentially that a Separator is our Object (since any lower level of detail may have been thrown away by the browser), then this could get fairly easy. Basically we have to:

The various Nodes in SDSC, Sony and my proposals composite some or all of three sections,

ScriptNode

Behavior files are references through a new ScriptNode
    Script { 
        behavior  "http://foo.com/bar.class"  ; MFSTRING
        scriptType "JAVA" ; SFSTRING
        eventIn SFSTRING name	
        eventIn SFVEC3F lookfrom
        eventIn PICK selected
        eventOut SFSTRING lookto
        optimisation  SFBITMASK (CULLEVENTS | LODEVENTS | WORLDINOUT |  
                          UNKNOWNOUTPUTS | ALWAYSEVAL )                 
    }
ScriptNodes can only appear as children of Frames, and have an implicit object which they are attached to.

Examples

The following examples are taken from various papers, and converted to this scheme, note that most of the examples in all of the existing proposals get syntactically more complex with the Interfaces proposal, and VRML1.1 style separators.

A cube that changes color when picked and again when released

This is an easy example because the action is performed on the same object on which the event occurs.
    This example needs rewriting            

Turning the lights on when the switch is grabbed

    This example needs rewriting

Inline behaviors

Short scripts

Short programs may be specified by placing directly in the behavior field of the ScriptNode (or the Separator if the change planned happens).

Trivial Methods

A tiny language can be embedded in the "actionMethod" field directly to describe some simple methods. For example,
EventHandler {
    eventType GRAB
   actionMethod "set SFBOOL on TRUE"
}
Only the following syntax can be used for describing methods.

    set FIELDTYPE FIELDNAME CONSTANT

    load URL

Open issue

If we have input events on nodes, then it may be possible to get rid of this language entirely and use EventHandlers, and do all scripting in the external language. For example, the above becomes either:
    EventHandler {
        eventType GRAB
        actionMethod "setOn"
        actionParameters "SFBOOL TRUE"
    } 
At this time I can't see how to do this using ROUTES without a GrabSensor, a ROUTE and a LOGIC node?

EventTypes

We need a complete list of possible events, although the eventType field could be extended to new events later. This requirement is because the browsers are going to implement the event detection and propogation at a fairly low level.

For each event we have to define the paramaters that are passed across to the script in the case that a actionMethod is not specified. All events, and messages, include the following information.

The first set are events sent by sensors. (The ... refers to the parameters sent with all events, and listed above).

The second set of events are sent by the browser in response to various culling, and administration situations. They are controlled by flags on the scriptNode.

Field events

The Sensor structure doesn't support events which require parameters in order to be triggered. So a small set of extra nodes will need defining for more complex events. The FieldEvent is one example of this, it allows a behavior to be triggered when a field changes value.
FieldEvent {
    eventOn   ""  ; SFSTRING Node name to watch, default to this Separator
    field     ""  ; SFSTRING field to watch

    actionOn, actionMethod, actionParameters  ; as for Sensors     
}
The defaults for actionMethod and actionParameters are to send a data structure - to be defined - containing a pointer to the node changed, the name of the field changed and the value it changed to. This may need more thought

This could be extended to allow more complex tests - for example only trigger when this field goes to TRUE, however is is not clear that the added complexity is worth it, as compared to having the full power of a programming language available in the behavior. Typically the field being watched will be passed to the Applet in one of the actionParameters.

Open issue

Note that if we adopt Gavin's suggestion of using events as inputs to regular nodes, then FieldEvent can be used for routing fields of one node to another, or from a node to a ScriptNode. In fact, FieldEvent and ROUTE become semantically, and functionally equivalent. For example:
     ROUTE foo.alpha -> ascript.timein
is equivalent to
    FieldEvent {
        eventOn        foo
        field          alpha
        actionOn       ascript
        actionMethod   setTimein   # Or whatever naming convention is used.
        actionParameters  SFFLOAT alpha
    }
Since ROUTE will actually get implemented as adding something akin to a FieldEvent to a node, it might be better to specify FieldEvent itself, or it might be better and syntactically cleaner to just use ROUTE.

Timers

Two features facilitate timers indepndantly of functionality that may or may not be available in the language being used (e.g. Java probably has it, Perl probably doesn't).

_Time

A pseudo-object allows a behavior to read the time via GetField calls. The fields need more discussion, but there are probably several different time values that could be watched - so these are made available as seperate fields. The OpenInventor SFTIME type is specified, there might be a better class to use since SFTIME is specified in seconds, or alternatively a millisecond field could be added.
_Time {
    realTime    ; SFTIME - the time asserted by the machine's clock. 
                ; This might not be accurate, especially on low-end 
                ; machines.
    wallClock   ; SFTIME - in a simulation this is the time being 
                ; simulated in most circumstances this will be the 
                ; same as realTime.
    elapsedTime ; SFTIME - time since this simulation started, 
                ; or the world was loaded. (This might not be useful)
}

Culling rules

To deal with concerns about optimisation, some rules must be laid down about when a browser can, and when it cannot, optimise away, or cull, a behavior (or a node).
  1. If a script has an output that is visible, it must be evaluated when it receives events.
  2. If a script has the UNKNOWNOUPUTS flag set, meaning that it might effect other things in the scene graph, then it must be assumed to be connected to a visible object, so rule 1 applies.
  3. If a script has the ALWAYSEVAL flag set, then it must be evaluated whenever it receives events. (this might be equivalent to UNKNOWNOUTPUTS, but I'm not sure it will be for all systems).
  4. If a script would be evaluated, then any Node that it depends on will need evaluating.

Further Work

Nasties

In the interests of full disclosure - I've spotted the following nasty features of this proposal that may need addressing.

Consider

References

References are now in a seperate document which seems to have been lost