The Annotated VRML 97 Reference

1 Intro     Concepts     3 Nodes     4 Fields/Events    Conformance
A Grammar     B Java     C JavaScript     D Examples     E Related Info    References
Quick Java         Quick JavaScript         Quick Nodes   
 

  About the Book
  
Help
  Copyright © 1997-99
  Purchase the book from Amazon.com

 

 

Chapter 2
Key Concepts

2.1 Intro

2.1.1 Overview
2.1.2 TOC
2.1.3 Conventions

2.2 Overview
2.2.1 File Structure
2.2.2 Header
2.2.3 Scene graph
2.2.4 Prototypes
2.2.5 Routing
2.2.6 Generating files
2.2.7 Presentation
     Interaction
2.2.8 Profiles

2.3 UTF-8 syntax
2.3.1 Clear text
2.3.2 Statements
2.3.3 Node
2.3.4 Field
2.3.5 PROTO
2.3.6 IS
2.3.7 EXTERNPROTO
2.3.8 USE
2.3.9 ROUTE

2.4 Scene graph
2.4.1 Root nodes
2.4.2 Hierarchy
2.4.3 Descendants
       & ancestors
2.4.4 Hierarchy
2.4.5 Units coord sys

2.5 VRML & WWW
2.5.1 MIME type
2.5.2 URLs
2.5.3 Relative URLs
2.5.4 data:
2.5.5 Scripting protocols
2.5.6 URNs

2.6 Nodes
2.6.1 Intro
2.6.2 DEF/USE
2.6.3 Geometry
2.6.4 Bboxes
2.6.5 Grouping & children
2.6.6 Lights
2.6.7 Sensors
2.6.8 Interpolators
2.6.9 Time nodes
2.6.10 Bindable children
2.6.11 Textures

2.7 Field, eventIn,
     eventOut

2.8 PROTO
2.8.1 Declaration
2.8.2 Definition
2.8.3 Scoping

2.9 EXTERNPROTO
2.9.1  Interface
2.9.2  URL
2.9.3 Extensions

2.10 Events
2.10.1 Intro
2.10.2 Routes
2.10.3 Execution
2.10.4 Loops
2.10.5 Fan-in & fan-out

2.11 Time
2.11.1 Intro
2.11.2 Origin
2.11.3 Discrete/cont

2.12 Scripting
2.12.1 Intro
2.12.2 Execution
2.12.3 Initialize/shutdown
2.12.4 eventsProcessed
2.12.5 Direct outputs
2.12.6 Asynchronous
2.12.7 Languages
2.12.8 EventIns
2.12.9 fields events
2.12.10 Browser interface

2.13 Navigation
2.13.1 Intro
2.13.2 Navigation
2.13.3 Viewing
2.13.4 Collisions

2.14 Lighting
2.14.1 Intro
2.14.2 'off'
2.14.3 'on'
2.14.4 Equations
2.14.5 References

+ 2.10 Event processing

2.10.1 Introduction

Most node types have at least one eventIn definition and thus can receive events. Incoming events are data messages sent by other nodes to change some state within the receiving node. Some nodes also have eventOut definitions. These are used to send data messages to destination nodes that some state has changed within the source node.

If an eventOut is read before it has sent any events (e.g., get_foo_changed), the initial value as specified in "Chapter 4, Field and Event Reference" for each field/event type is returned.

design note

Events are the most important new feature in VRML 2.0. Events make the world move; the only way to change something in a VRML world is to send an event to some node. They form the foundation for all of the animation and interaction capabilities of VRML, and more effort was put into the event model design than any of the other new features in VRML 2.0. VRML's event model design is a result of collaboration between the Silicon Graphics team, the Sony team, and Mitra.

2.10.2 Route semantics

The connection between the node generating the event and the node receiving the event is called a route. Routes are not nodes. The ROUTE statement is a construct for establishing event paths between nodes. ROUTE statements may either appear at the top level of a VRML file, in a prototype definition, or inside a node wherever fields may appear. Nodes referenced in a ROUTE statement shall be defined before the ROUTE statement.

design note

Note that the only way to refer to a node in a ROUTE statement is by its name, which means that you must give a node a name if you are establishing routes to or from it. See Section 2.3.2, Instancing, for the recommended way of automatically generating unique (but boring) names.

The types of the eventIn and the eventOut shall match exactly. For example, it is illegal to route from an SFFloat to an SFInt32 or from an SFFloat to an MFFloat.

design note

Automatic type conversion along routes would often be convenient. So would simple arithmetic operations along SFFloat/SFInt32/SFVec* routes, and simple logical operations for SFBool routes. However, one of the most important design criteria for VRML 2.0 was to keep it as simple as possible. Therefore, since the ROUTE mechanism is such a fundamental aspect of the browser implementation and even simple type conversions require significant amounts of code and complexity, it was decided not to include any data modification along routes.

If type conversion is required, it is easy (although tedious) to define a Script that does the appropriate conversion. Standard prototypes for type conversion nodes have already been proposed to the VRML community. If they are used often enough, browser implementors may begin to provide built-in, optimized implementations of these prototypes, which will be a clear signal that they should be added to a future version of the VRML specification.

Routes may be established only from eventOuts to eventIns. For convenience, when routing to or from an eventIn or eventOut (or the eventIn or eventOut part of an exposedField), the set_ or _changed part of the event's name is optional. If the browser is trying to establish a ROUTE to an eventIn named zzz and an eventIn of that name is not found, the browser shall then try to establish the ROUTE to the eventIn named set_zzz. Similarly, if establishing a ROUTE from an eventOut named zzz and an eventOut of that name is not found, the browser shall try to establish the ROUTE from zzz_changed.

Redundant routing is ignored. If a file repeats a routing path, the second and subsequent identical routes are ignored. This also applies for routes created dynamically via a scripting language supported by the browser.

design note

Three different architectures for applying changes to the scene graph were considered during the VRML 2.0 design process. The key considerations were how much information the VRML browser knows about the world, how little reinvention of existing technology needed to be done, and how easy it would be for nonprogrammers to create interactive worlds. The architecture chosen is a compromise between these conflicting desires.

One extreme would be to keep all behaviors out of VRML and perform all behaviors in an existing language such as Java. In this model, a VRML file looks very much like a VRML 1.0 file, containing only static geometry, and instead of loading a .wrl VRML file into your browser, you would load an applet that referenced a VRML file and then -proceed to modify the objects in the world over time. This is similar to conventional programming; the program (applet) loads the data file (VRML world) into memory and then proceeds to make changes to it over time. The advantages of this approach are that it would make the VRML file format simpler and it matches the traditional way applications are created.

There are several disadvantages to this approach, however. Tools meant to help with the creation of interactive worlds would either have to be able to parse and understand

the code for an applet (since all of the interactive code would be contained inside an applet) or would be forced to use their own proprietary format for representing behaviors, which were then "published" into the required applet+VRML world form. This would severely limit the interoperability between tools and would make it very difficult for tools or world creators to update the geometry of a VRML world without breaking the behaviors that affect the world.

In addition, it isn't clear that the scalability and composability goals for VRML could be met if all behaviors were performed outside the VRML world. Architectures for composing arbitrary applets (such as Microsoft's ActiveX or Netscape's LiveConnect) have only recently been defined and are designed for the case of a small number of applets on a Web page. The vision for VRML is a potentially infinite, continuous landscape containing an arbitrary number of interacting entities; a very different environment than a Web page!

Another extreme would be to redefine VRML to be a complete programming language, allowing any behavior to be expressed completely in VRML. In this model, a VRML browser would act as a compiler and runtime system, much like the Java runtime reads in Java byte codes and runs them. This approach has all of the disadvantages just described. Defining a specialized language just for VRML would make it possible to do many VRML-specific optimizations, but the disadvantages of defining Yet Another Programming Language probably outweigh the potential gains.

The architecture chosen treats behaviors as "black boxes" (Script nodes) with well-defined interfaces (routes and events). Treating behaviors as black boxes allows any scripting language to be used without changing the fundamental architecture of VRML. Implementing a browser is much easier because only the interface between the scene and the scripting language needs to be implemented, not the entire scripting language.

Expressing the interface to behaviors in the VRML file allows an authoring system to deal intelligently with the behaviors and allows most world creation tasks to be done with a graphical interface. A programming editor only need appear when a sophisticated user decides to create or modify a behavior—opening up the black box. The authoring system can safely manipulate the scene hierarchy (add geometry, delete geometry, rename objects, etc.) and still maintain routes to behaviors, and yet the authoring system does not need to be able to parse or understand what happens inside the behavior.

The VRML browser also does not need to know what happens inside each behavior to optimize the execution and display of the world. Since the possible effects of a Script are expressed by the routes coming from it (and by the nodes it may directly modify, which are also known), browsers can perform almost all of the optimizations that would be possible if VRML were a specialized programming language. Synchronization and scheduling can also be handled by the browser, making it much easier for the world creator since they can express their intent rather than worry about explicit synchronization between independent applets. For example, giving a sound and an animation the same starting time synchronizes them in VRML. Performing the equivalent task with an architecture that exposes the implementation of sounds and animations as asynchronous threads is more difficult.

2.10.3 Execution model

Once a sensor or Script has generated an initial event, the event is propagated from the eventOut producing the event along any ROUTEs to other nodes. These other nodes may respond by generating additional events, continuing until all routes have been honored. This process is called an event cascade. All events generated during a given event cascade are assigned the same timestamp as the initial event, since all are considered to happen instantaneously.

Some sensors generate multiple events simultaneously. In these cases, each event generated initiates a different event cascade with identical timestamps.

Figure 2-6 provides a conceptual illustration of the execution model. This figure is for illustration purposes only and is not intended for literal implementation.

Event model diagram

Figure 2-6: Conceptual Execution Model

design note

The task of defining the execution model for events is simplified by breaking it down into three subtasks:

  1. Defining what causes an initial event
  2. Defining an ordering for initial events
  3. Defining exactly what happens during an event cascade

    The only nodes in the VRML 2.0 specification that can generate initial events are the sensor nodes, Collision group, and Script nodes. ExposedFields never generate initial events (they are always part of the event cascade) and neither do the interpolator nodes. So the first subtask, defining what causes an initial event, is satisfied by precisely defining the conditions under which each sensor or Script node will generate events. See Section 2.7, Scripting, for a discussion of when Script nodes generate initial events, and see the description for each sensor node for a discussion of when they generate initial events.

    The second subtask, defining an ordering for initial events, is made easier by introducing the notion that all events are given time stamps. We can then guarantee determinism by requiring that an implementation produce results that are indistinguishable from an implementation that processes events in time stamp order, and defining an order for events that have the same time stamp (or declare that the results are inherently indeterministic and tell world creators, "Don't do that!"). Defining the execution model becomes manageable only if each change can be considered in isolation. Implementations may choose to process events out of order (or in parallel, or may choose not to process some events at all!) only if the results are the same as an implementation that completely processes each event as it occurs. VRML 2.0 is carefully designed so that implementations may reason about what effects a particular event might possibly have, allowing sophisticated implementations to be very efficient when processing events.

    The third subtask, defining what happens during an event cascade, is made easier by not considering all possible route topologies at once. In particular, event cascades that contain loops and fan-ins are difficult to define and are considered separately (see -Sections 2.4.4, Loops, and 2.4.5, Fan-in and Fan-out).

    Processing an event cascade ideally takes no time, which is why all events that are part of a given event cascade are given the same time stamp. ROUTE statements set up explicit dependencies between nodes, forcing implementations to process certain events in an event cascade before others.

    For example, given nodes A, B, and C in the arrangement in Figure 2-7, where A is a TouchSensor detecting the user touching some geometry in the world, B is a Script that outputs TRUE and then FALSE every other time it receives input, and C is a TimeSensor that starts an animation, the ROUTE statements would be

        ROUTE A.touchTime TO B.toggleNow 
        ROUTE A.touchTime TO C.set_startTime 
        ROUTE B.toggle_changed TO C.set_enabled 

Routing example diagram

Figure 2-7: Routing Example

In this case, whether or not TimeSensor C will start generating events when TouchSensor A is touched depends on whether or not it is enabled, so an implementation must run Script B's script before deciding which events C should generate. If B outputs TRUE and C becomes active, then C should generate startTime_changed, enabled_changed, is-Active, fraction_changed, cycleTime, and time events. If B outputs FALSE and C becomes inactive, then it should only generate startTime_changed, enable_changed, and isActive events.

Paradoxical dependencies (when, for example, results of A depend on B and results of B depend on A) can be created, and implementations are free to do whatever they wish with them—results are undefined. See Section 2.4.5, Fan-in and Fan-out, for an explanation of what happens when more than one event is sent to a single eventIn.

2.10.4 Loops

Event cascades may contain loops, where an event E is routed to a node that generates an event that eventually results in E being generated again. To break such loops, implementations shall not generate two events from the same eventOut or to the same eventIn that have identical timestamps. This rule shall also be used to break loops created by cyclic dependencies between different sensor nodes.

tip

In general, it is best to avoid route loops. There are some situations in which they're useful, however, and the loop-breaking rule combined with the dependencies implied by the routes are sufficient to make loops deterministic, except for some cases of cyclic dependencies (which are inherently indeterministic and must be avoided by world creators) and some cases of fan-in (which must also be avoided and are discussed later).

One simple situation in which a route loop might be useful is two exposedFields, A.foo and B.foo, with values that you want to remain identical. You can route them to each other, like this:

        ROUTE A.foo_changed TO B.set_foo 
        ROUTE B.foo_changed TO A.set_foo 

First, note that no events will be generated unless either A or B is changed. There must be either another route to A or B or a Script node that has access to and will change A or B, or neither A nor B will ever change. A route is a conduit for events; it does not establish equality between two fields. Or, in other words, if A.foo and B.foo start out with different values, then establishing a route between them will not make their values become equal. They will not become equal until either A receives a set_foo event or B receives a set_foo event. See Section 2.7, Scripting, for a description of how to write a script that generates initial events after the world has been loaded, if you want to guarantee equality between exposedFields.

The loop-breaking rule prevents an infinite sequence of events from being generated and results in "the right thing" happening. If A receives a set_foo event from somewhere, it sets its value and sends a set_foo event to B. B then sets its value and sends A another set_foo event, which A ignores since it has already received a set_foo event during this event cascade.

2.10.5 Fan-in and fan-out

Fan-in occurs when two or more routes write to the same eventIn. If two events with different values but the same timestamp are received at an eventIn, the results are indeterminate.

Fan-out occurs when one eventOut routes to two or more eventIns. This results in sending any event generated by the eventOut to all of the eventIns.

design note

Like loops, in general it is best to avoid fanning into a single eventIn, since it is possible to create situations that lead to undefined results. Fan-in can be useful if used properly, though. For example, you might create several different animations that can apply to a Transform node's translation field. If you know that only one animation will ever be active at the same time and all of the animations start with and leave the objects in the same position, then routing all of the animations to the set_translation eventIn is a safe and useful thing to do. However, if more than one animation might be active at the same time, results will be undefined and you will likely get different results in different browsers. In this case, you should insert a Script that combines the results of the animations in the appropriate way, perhaps by adding up the various translations and outputting their sum. The Script must have a different eventIn for each animation to avoid the problem of two events arriving at the same eventIn at the same time.

While designing VRML 2.0, various schemes for getting rid of ambiguous fan-in were considered. The simplest would be to declare all fan-in situations illegal, allowing only one route to any eventIn. That solution was rejected because it makes some simple things hard to do. Other possibilities that were considered and rejected included determining a deterministic ordering for each connection to an eventIn (rejected because determining an order is expensive and difficult) and built-in rules to automatically combine the values of each eventIn type, such as logical "OR" for SFBool events (rejected because it would make implementations more complex and because some event types [e.g., SFNode] don't have obvious combination rules). World creators are given the power to create ambiguous situations and are trusted with the responsibility to avoid such situations.

design note

Fan-out is very useful and, by itself, can never cause undefined results. It can also be implemented very efficiently, because a node can't modify the events it receives. Only one event needs to be created for any eventOut, even if there are multiple routes leading from that eventOut.