The Virtual Reality Modeling Language Specification

4. Concepts

Version 2.0, Official Draft #3, ISO/IEC 14772

July 15, 1996

This section describes key concepts related to the definition and use of the VRML 2.0 specification. This includes how nodes are combined into scene graphs, how nodes receive and generate events, how to create node types using prototypes, how to add node types to VRML and export them for use by others, how to incorporate programmatic scripts into a VRML file, and various topics on nodes.

4.1 File Syntax and Structure

4.1.1 Syntax Basics

4.1.2 File Syntax vs. Public Interface

4.1.3 URLS and URNs

4.1.4 File Extension and MIME Types

4.2 Nodes, Fields, and Events

4.2.1 Introduction

4.2.2 General Node Characteristics

4.3 The Structure of the Scene Graph

4.3.1 Grouping Nodes and Leaves

4.3.2 Instancing

4.3.3 Coordinate Systems and Transformations

4.3.4 Viewing Model

4.3.5 Bounding Boxes

4.4 Events

4.4.1 Routes

4.4.2 Sensors

4.4.3 Execution Model

4.4.4 Loops

4.4.5 Fan-in

4.5 Time

4.5.1 Introduction

4.5.1 Discrete and continuous changes

4.6 Prototypes

4.6.1 Introduction to Prototypes

4.6.2 Defining Prototypes in External files

4.7 Scripting

4.7.1 Introduction

4.7.2 Script execution

4.7.3 initialize

4.7.4 eventsProcessed

4.7.5 Scripts with direct outputs

4.7.6 Asynchronous scripts

4.7.7 Script Languages

4.7.8 Receiving and Sending Events

4.7.9 Browser Script Interface

4.8 Browser Extensions

4.8.1 Creating Extensions

4.8.2 Reading Extensions

4.9 Node concepts

4.9.1 Bindable leaf nodes

4.9.2 Geometry

4.9.3 Grouping nodes

4.9.4 Interpolators

4.9.5 Lights and Lighting

4.9.6 Sensors

4.1 File Syntax and Structure

4.1.1 Syntax Basics

For easy identification of VRML files, every VRML 2.0 file based on this draft specification must begin with the characters:

#VRML V2.0 utf8

The identifier utf8 allows for international characters to be displayed in VRML using the UTF-8 encoding of the ISO 10646 standard. Unicode is an alternate encoding of ISO 10646. UTF-8 is explained under the Text node.

Any characters after these on the same line are ignored. The line is terminated by either the ASCII newline or carriage-return characters.

The # character begins a comment; all characters until the next newline or carriage return are ignored. The only exception to this is within double-quoted SFString and MFString fields, where the # character will be part of the string.

Note: Comments and whitespace may not be preserved; in particular, a VRML document server may strip comments and extra whitespace from a VRML file before transmitting it. WorldInfo nodes should be used for persistent information such as copyrights or author information. To extend the set of existing nodes in VRML 2.0, use prototypes or external prototypes rather than named information nodes.

Commas, blanks, tabs, newlines and carriage returns are whitespace characters wherever they appear outside of string fields. One or more whitespace characters separate the syntactical entities in VRML files, where necessary.

After the required header, a VRML file can contain the following:

See the Syntax Reference section for more details.

Field, event, prototype, and node names must not begin with a digit (0x30-0x39) but may otherwise contain any characters except for non-printable ASCII characters (0x0-0x20), double or single quotes (0x22: ", 0x27: '), sharp (0x23: #), plus (0x2b: +), comma (0x2c: ,), minus (0x2d: -), period (0x2e: .), square brackets (0x5b, 0x5d: []), backslash (0x5c: \) or curly braces (0x7b, 0x7d: {}). Characters in names are as specified in ISO 10646, and are encoded using UTF-8. VRML is case-sensitive; "Sphere" is different from "sphere" and "BEGIN" is different from "begin."

The following reserved keywords shall not be used for node, PROTO, EXTERNPROTO, or DEF names:

DEF EXTERNPROTO FALSE IS NULL PROTO ROUTE TO TRUE USE
eventIn eventOut exposedField field

For example, each line of the following has various errors (in italics):

PROTO [ field field eventIn eventOut field ROUTE ] { ... }
DEF PROTO Transform {
    children [
        DEF USE Shape { geometry DEF EXTERNPROTO ... }
        USE DEF
    ]
}

4.1.2 File syntax vs. public interface syntax

In this document, the first item in a node specification is the public interface for the node. The syntax for the public interface is the same as that for that node's prototype. This interface is the definitive specification of the fields, names, types, and default values for a given node. Note that this syntax is not the actual file format syntax. However, the parts of the interface that are identical to the file syntax are in bold. For example, the following defines the Collision node's public interface and file format:


    Collision { 
      eventIn      MFNode   addChildren
      eventIn      MFNode   removeChildren
      exposedField MFNode   children        []
      exposedField SFBool   collide         TRUE
      field        SFVec3f  bboxCenter      0 0 0
      field        SFVec3f  bboxSize        -1 -1 -1      
      field        SFNode   proxy           NULL
      eventOut     SFTime   collideTime
    }

Fields that have associated implicit set_ and _changed events are labeled exposedField. For example, the on field has an implicit set_on input event and an on_changed output event. Exposed fields may be connected using ROUTE statements, and may be read and/or written by Script nodes. Also, any exposedField or EventOut name can be prefixed with get_ to indicate a read of the current value of the eventOut. This is used only in Script nodes or when accessing the VRML world from an external API.

Note that this information is arranged in a slightly different manner in the actual file syntax. The keywords "field" or "exposedField" and the types of the fields (e.g. SFColor) are not specified when expressing a node in the file format. An example of the file format for the Collision node is:

Collision {
  children        []
  collide         TRUE
  bboxCenter      0 0 0
  bboxSize        -1 -1 -1
  proxy           NULL
}

The rules for naming fields, exposedFields, eventOuts and eventIns for the built-in nodes are as follows:

User defined field names (in Script and PROTO nodes) are not required to follow these rules but doing so would improve the consistency and readability of the file.

4.1.3 URLs and URNs

Issue: This section needs to be tightened up and clarified, esp. wrt URNs.

A URL (Universal Resource Locator) specifies a file located on a particular server and accessed through a specified protocol. A URN (Universal Resource Name) provides a more persistent way to refer to data than is provided by a URL. The exact definition of a URN is currently under debate. See the discussion at http://www.w3.org/hypertext/WWW/Addressing/Addressing.html for further details.

All URL/URN fields are of type MFString. The strings in such a field indicate multiple places to look for files, in decreasing order of preference. If the browser can't locate the first file or doesn't know how to deal with the URL or URN, it can try the second location, and so on.

VRML 2.0 browsers are not required to support URNs. If they do not support URNs, they should ignore any URNs that appear in MFString fields along with URLs. URN support is specified in a separate document at http://earth.path.net/mitra/papers/vrml-urn.html, which may undergo minor revisions to keep it in line with parallel work happening at the IETF.

Relative URLs are handled as described in IETF RFC 1808, "Relative Uniform Resource Locators."

Data Protocol

Issue: Is this required or even advisable? I think it should be removed from the spec until data: is finalized...rc

Data can be included directly in the VRML file using the data: protocol. The data: protocol is described at http://www.acl.lanl.gov/HTML_WG/html-wg-96q1.messages/0599.html. It allows inclusion of binary data in base64 encoding. In this way, for instance, JPEG images can be included inline, taking advantage of the image compression offered by JPEG while avoiding multiple fetch requests over the network.

Scripting Language Protocols

The Script node's URL field may also support a custom protocol for the various scripting languages. For example, a script URL prefixed with javascript: shall contain JavaScript source, with newline characters allowed in the string. A script prefixed with javabc: shall contain Java bytecodes using a base64 encoding. The details of each language protocol are defined in the appendix for each language. Browsers are not required to support any specific scripting language, but if they do then they shall adhere to the protocol for that particular scripting language. The following example, illustrates the use of mixing custom protocols and standard protocols in a single url (order of precedence determines priority):

#VRML V2.0 utf8
Script {
    url [ "javascript: ...",               # custom protocol JavaScript
          "javabc: ...",                   # custom protocol Java byte
          "java: ...",                     # custom protocol Java src
          "http://bar.com/foo.javascript", # std protocol JavaScript
          "http://bar.com/foo.class",      # std protocol Java byte
          "http://bar.com/foo.java" ]      # std protocol Java src
}

Issue: Sony guys needs to verify that this is ok.

4.1.4 File Extension and Mime Type

The file extension for VRML files is .wrl (for world).

The MIME type for VRML files is defined as follows:

        x-world/x-vrml

where the MIME major type for 3D world descriptions is x-world, and the minor type for VRML documents is x-vrml.

It is anticipated that the official type will change to "model/vrml". At this time, servers should present files as being of type x-world/x-vrml. Browsers should recognise both x-world/x-vrml and model/vrml.

IETF work-in-progress on this subject can be found in "The Model Primary Content Type for Multipurpose Internet Mail Extensions" , (ftp://ds.internic.net/internet-drafts/draft-nelson-model-mail-ext-01.txt).

4.2 Nodes, Fields, and Events

4.2.1 Introduction

At the highest level of abstraction, VRML is simply a file format for describing objects. Theoretically, the objects can contain anything -- 3D geometry, MIDI data, JPEG images, and so on. VRML defines a set of objects useful for doing 3D graphics and interactive object/world building. These objects are called nodes, and contain data which is stored in fields.

4.2.2 General Node Characteristics

A node has the following characteristics:

The syntax for representing these pieces of information is as follows:

      nodetype { fields }

Only the node type and braces are required; nodes may or may not have field values specified. Unspecified field values are set to the default values in the specification.

4.3 The Structure of the Scene Graph

This section describes the general scene graph hierarchy, how to reuse nodes within a file, coordinate systems and transformations in VRML files, and the general model for viewing and interaction within a VRML world.

4.3.1 Grouping Nodes and Leaves

A scene graph consists of grouping nodes and leaf nodes. Grouping nodes, such as Transform, LOD, and Switch, can have child nodes. These children can be other grouping nodes or leaf nodes, such as shapes, browser information nodes, lights, viewpoints, and sounds. Appearance, appearance properties, geometry, and geometric properties are contained within Shape nodes.

Transformations are stored within Transform nodes. Each Transform node defines a coordinate space for its children. This coordinate space is relative to the parent (Transform) node's coordinate space--that is, transformation accumulate down the scene graph hierarchy.

4.3.2 Instancing

A node may be referenced in a VRML file multiple times. This is called instancing (using the same instance of a node multiple times; called "sharing", "aliasing" or "multiple references" by other systems) and is accomplished by using the DEF and USE keywords.

The DEF keyword gives a node a name and creates a the node of that type. The USE keyword indicates that a reference to a previously named node should be inserted into the scene graph. This has the affect of sharing a single node in more than one location in the scene. If the node is modified, then all references to that node are modified. DEF/USE name scope is limited to a single file. If multiple nodes are given the same name, then the last DEF encountered during parsing is used for USE definitions.

Tools that create VRML files may need to modify user-defined node names to ensure that a multiply instanced node with the same name as some other node will be read correctly. The recommended way of doing this is to append an underscore followed by an integer to the user-defined name. Such tools should automatically remove these automatically generated suffixes when VRML files are read back into the tool (leaving only the user-defined names).

Similarly, if an un-named node is multiply instanced, tools will have to automatically generate a name to correctly write the VRML file. The recommended form for such names is just an underscore followed by an integer.

4.3.3 Coordinate Systems and Transformations

VRML uses a Cartesian, right-handed, 3-dimensional coordinate system. By default, objects are projected onto a 2-dimensional display device by projecting them in the direction of the positive Z axis, with the positive X axis to the right and the positive Y axis up. A modeling transformation (Transform and Billboard) or viewing transformation (Viewpoint) can be used to alter this default projection.

The standard unit for lengths and distances is meters. The standard unit for angles is radians.

VRML scenes may contain an arbitrary number of local (or object-space) coordinate systems, defined by the transformation fields of the Transform and Billboard nodes.

Conceptually, VRML also has a world coordinate system. The various local coordinate transformations map objects into the world coordinate system, which is where the scene is assembled. Transformations accumulate downward through the scene graph hierarchy, with each Transform and Billboard inherit transformations of their parents. (Note however, that this series of transformations takes effect from the leaf nodes up through the hierarchy. The local transformations closest to the Shape object take effect first, followed in turn by each successive transformation upward in the hierarchy.)

4.3.4 Viewing Model

This specification assumes that there is a real person viewing and interacting with the VRML world. The VRML author may place any number of viewpoints in the world -- interesting places from which the user might wish to view the world. Each viewpoint is described by a Viewpoint node. Viewpoints exist in a specific coordinate system, and both the viewpoint and the coordinate system may be animated. Only one Viewpoint may be active at a time. See the description of Bindable Leaf Nodes for details. When a viewpoint is activated, the browser parents its view (or camera) into the scene graph under the currently active viewpoint. Any changes to the coordinate system of the viewpoint have effect on the browser view. Therefore, if a user teleports to a viewpoint that is moving (one of its parent coordinate systems is being animated), then the user should move along with that viewpoint. It is intended, but not required, that browsers support a user-interface by which users may "teleport" themselves from one viewpoint to another.

4.3.5 Bounding Boxes

Several of the nodes in this specification include a bounding box field. This is typically used by grouping nodes to provide a hint to the browser on the group's approximate size for culling optimizations. The default size for boundings boxes (-1, -1, -1) implies that the user did not specify the bounding box and the browser must compute it on-the-fly or assume the most conservative case. A bounding box size of (0, 0, 0) is valid and represents a point in space (i.e. infinitely small box).

The bboxCenter and bboxSize fields may be used to specify a maximum possible bounding box for the objects inside a grouping node (e.g. Transform). These are used as hints to optimize certain operations such as determining whether or not the group needs to be drawn. If the specified bounding box is smaller than the true bounding box of the group, results are undefined. The bounding box should be large enough to completely contain the effects of all sounds, lights and fog nodes that are children of this group. If the size of this group may change over time due to animating children, then the bounding box must also be large enough to contain all possible animations (movements). The bounding box should typically be the union of the group's children bounding boxes; it should not include any transformations performed by the group itself (i.e. the bounding box is defined in the local coordinate system of the group).

4.4 Events

Most nodes 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 other nodes or to alert monitoring nodes that some state has changed within the source node. Nodes can also have exposedField definitions which bundle an eventIn, a field, and an eventOut. For example, the Transform node has an translation exposedField that can receive translation events that change the translation field, and then send a translation output event.

4.4.1 Routes

The connection between the node generating the event and the node receiving the event is called a route. A node that produces events of given type can be routed to a node that receives events of the same type using the following syntax:

ROUTE NodeName.eventOutName_changed TO NodeName.set_eventInName

The prefix set_ and the suffix _changed are recommended conventions, not strict rules. Thus, when creating prototypes or scripts, the names of the eventIns and the eventOuts can be any legal identifier name. Note however, that exposedField's implicitly define set_xxx as an eventIn, xxx_changed as an eventOut, and xxx as a field for a given exposedField named xxx. It is strongly recommended that developers follow these guidelines when creating new types. There are three exceptions in the VRML Specification to this recommendation: Bool events, Time events, and children events. All SF/MFBool eventIns and eventOuts are named isFoo (e.g. isActive). All SF/MFTime eventIns and eventOuts are named fooTime (e.g. enterTime). The eventIns on groups for adding and removing children are named: addChildren and removeChildren. These exceptions were made to improve readability.

Routes are not nodes; ROUTE is merely a syntactic construct for establishing event paths between nodes. ROUTE statements may appear at either the top-level of a .wrl file or prototype implementation, or may appear inside a node wherever fields may appear.

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

Routes may be established only from eventOuts to eventIns. Since exposedField's implicitly define a field, an eventIn, and an eventOut, it is legal to use the exposedField's defined name when routing to and from it, (rather than specifying the set_ prefix and _changed suffix). For example, the following TouchSensor's enabled exposedField is routed to the DirectionalLight's on exposed field. Note that all four routing examples below are legal syntax:

DEF CLICKER TouchSensor { enabled TRUE }
DEF LIGHT DirectionalLight { on  FALSE }

ROUTE CLICKER.enabled TO LIGHT.on
or
ROUTE CLICKER.enabled_changed TO LIGHT.on
or
ROUTE CLICKER.enabled TO LIGHT.set_on
or
ROUTE CLICKER.enabled_changed TO LIGHT.set_on

Redundant routing is ignored. If a file repeats a routing path, the second (and all subsequent identical routes) are ignored. Likewise for dynamically created routes via a scripting language supported by the browser.

4.4.2 Sensors

Sensor nodes generate events. Geometric sensor nodes (ProximitySensor, VisibilitySensor, TouchSensor, CylinderSensor, PlaneSensor, SphereSensor and the Collision group) generate events based on user actions, such as a mouse click or navigating close to a particular object. TimeSensor nodes generate events as time passes.

Each type of sensor defines when an event is generated. The state of the scene graph after several sensors have generated events must be as if each event is processed separately, in order. If sensors generate events at the same time, the state of the scene graph will be undefined if the results depends on the ordering of the events (world creators must be careful to avoid such situations).

It is possible to create dependencies between various types of sensors; for example, a TouchSensor may result in a change to a VisibilitySensor's transformation, whcih may cause it's visibility status to change. World authors must be careful to avoid creating indeterministic or paradoxical situations (such as a TouchSensor that is active if a VisiblitySensor is visible, and a VisibilitySensor that is NOT visible if a TouchSensor is active).

4.4.3 Execution Model

Once a Sensor has generated an initial event, the event is propogated along any ROUTES to other nodes. These other nodes may respond by generating additional events, and so on. This process is called an event cascade. All events generated during a given event cascade are given the same timestamp as the initial event (they are all considered to happen instantaneously).

Some sensors generate multiple events simultaneously; in these cases, each event generated initiates a different event cascade.

4.4.4 Loops

Event cascades may contain loops, where an event 'E' is routed to a node that generated an event that eventually resulted in 'E' being generated. Loops are broken as follows: implementations must not generate two events from the same eventOut that have identical timestamps. Note that this rule also breaks loops created by setting up cyclic dependencies between different Sensor nodes.

4.4.5 Fan-in

Fan-in occurs when two routes lead to the same eventIn. If two events with different values but the same timestamp are received at an eventIn, then the results are undefined. World creators must be careful to avoid such situations.

4.5 Time

4.5.1 Introduction

The browser controls the passage of time in a world by causing TimeSensors to generate events as time passes. Specialized browsers or authoring applications may cause time to pass more quickly or slowly than in the real world, but typically the times generated by TimeSensors will roughly correspond to "real" time. A world's creator must make no assumptions about how often a TimeSensor will generate events but can safely assume that each time event generated will be greater than any previous time event.

Time (0.0) starts at 12 midnight GMT January 1, 1970.

Events that are "in the past" cannot be generated; processing an event with timestamp 't' may only result in generating events with timestamps greater than or equal to t.

4.5.2 Discrete and continuous changes

VRML does not distinguish between discrete events (like those generated by a TouchSensor) and events that are the result of sampling a conceptually continuous set of changes (like the fraction events generatedy by a TimeSensor). An ideal VRML implementation would generate an infinite number of samples for continuous changes, each of which would be processed infinitely quickly.

Before processing a discrete event, all continuous changes that are occuring at the discrete event's timestamp should behave as if they generate events at that same timestamp.

Beyond the requirements that continuous changes be up-to-date during the processing of discrete changes, implementations are free to otherwise sample continuous changes as often or as infrequently as they choose. Typically, a TimeSensor affecting a visible (or otherwise perceptible) portion of the world will generate events once per "frame," where a "frame" is a single rendering of the world or one time-step in a simulation.

4.6 Prototypes

4.6.1 Introduction to Prototypes

Prototyping is a mechanism that allows the set of node types to be extended from within a VRML file. It allows the encapsulation and parameterization of geometry, behaviors, or both.

A prototype definition consists of the following:

Square brackets enclose the list of events and fields, and braces enclose the definition itself:

PROTO prototypename [ eventIn      eventtypename name
                      eventOut     eventtypename name
                      exposedField fieldtypename name defaultValue
                      field        fieldtypename name defaultValue
                      ... ] {
  Zero or more Scene graph(s)
  (nodes, prototypes, and routes, containing IS statements)
}

A prototype does not define a node into the scene graph; it merely creates a new node type (named prototypename) that can be created later in the same file as if it were a built-in node. It is thus necessary to define a node of the type of the prototype to actually create an object.

The first scene graph, (referred to as the primary scene graph), found in the prototype definition containing the IS syntax is used to represent this node. The other scene graphs are not rendered, but may be referenced via routes or scripts and thus cannot be ignored.

PROTO and EXTERNPROTO statements may appear anywhere ROUTE statements may appear-- at either the top-level of a .wrl file or prototype implementation, or wherever fields may appear.

The eventIn and eventOut declarations export events from the primary scene graph. Specifying each event's type both in the prototype declaration and in the primary scene graph is intended to prevent errors and to provide consistency with external prototypes.

Events generated or received by nodes in the prototype's implementation are associated with the prototype using the keyword IS. For example, the following statement exposes a Transform node's built-in set_translation event by giving it a new name (set_position) in the prototype interface:

PROTO FooTransform [ eventIn SFVec3f set_position ] {
  Transform { set_translation IS set_position }
}

Fields hold the persistent state of VRML objects. Allowing a prototype to export fields allows the initial state of a prototyped object to be specified when an instance of the prototype is created. The fields of the prototype are associated with fields in the implementation using the IS keyword. For example:

PROTO BarTransform [ exposedField SFVec3f position ] {
  Transform {  translation IS position }
}

IS statements may appear inside nodes wherever fields may appear. Specifying an IS statement for a node in the primary scene graph which is not part of the prototype's implementation is an error. Inversely, it is also an error for an IS statement to refer to a non-existant declaration. It is an error if the type of the field or event being exposed does not match the type declared in the prototype's interface declaration.

The following table defines the rules for mapping between the prototype declarations and the primary scene graph's nodes (yes denotes a legal mapping, no denotes an error):

Prototype declaration
exposedField field eventIn eventOut
N exposedField yes yes yes yes
o field no yes no no
d eventIn no no yes no
e eventOut no no no yes

It is valid to specify both the field (or exposedField) default values and the IS association inside a prototype definition. For example, the following prototype maps a Material node's diffuseColor (exposedField) to the prototype's eventIn myColor and also defines the default diffuseColor values:

PROTO foo [ eventIn myColor ] {
    Material {
        diffuseColor  1 0 0
        diffuseColor  IS myColor   # or set_diffuseColor IS myColor
    }
}

A prototype is instantiated as if typename were a built-in node. The prototype name must be unique within the scope of the file, and cannot rename a built-in node or prototype.

Prototype instances may be named using DEF and may be multiply instanced using USE as any built-in node. A prototype instance can be used in the scene graph wherever the first node of the primary scene graph can be used. For example, a prototype defined as:

PROTO MyObject [ ... ] {
  Box { ... }
  ROUTE ...
  Script { ... }
  ...
}

can be instantiated wherever Box can be used, since the first node of the prototype's primary scene graph is a Box node.

A prototype's scene graph defines a DEF/USE name scope separate from the rest of the scene; nodes DEF'ed inside the prototype may not be USE'ed outside of the prototype's scope, and nodes DEF'ed outside the prototype scope may not be USE'ed inside the prototype scope.

Prototype definitions appearing inside a prototype implementation (i.e. nested) are local to the enclosing prototype. For example, given the following:

PROTO one [...] {
    PROTO two [...] { ... }
    ...
    two { } # Instantiation inside "one":  OK
}
two { } # ERROR: "two" may only be instantiated inside "one".

The second instantiation of "two" is illegal. IS statements inside a nested prototype's implementation may refer to the prototype declarations of the innermost prototype. Therefore, IS statements in "two" cannot refer to declarations in "one".

A prototype may be instantiated in a file anywhere after the completion of the prototype definition. A prototype may not be instantiated inside its own implementation (i.e. recursive prototypes are illegal). The following example produces an error:

PROTO Foo [] {
  Foo {}
}

4.6.2 Defining Prototypes in External Files

The syntax for defining prototypes in external files is as follows:

EXTERNPROTO prototypename [ eventIn eventtypename name
                            eventOut eventtypename name
                            field fieldtypename
                            ... ]
  "URL" or [ "URL", "URL", ... ]

The external prototype is then given the name prototypename in this file's scope. It is an error if the eventIn/eventOut declaration in the EXTERNPROTO is not a subset of the eventIn/eventOut declarations specified in the PROTO referred to by the URL. If multiple URLs or URNs are specified, the browser searches in the order of preference (see "URLs and URNs").

Unlike a prototype, an external prototype does not contain an inline implementation of the node type. Instead, the prototype implementation is fetched from a URL or URN. The other difference between a prototype and an external prototype is that external prototypes do not contain default values for fields. The external prototype references a file that contains the prototype implementation, and this file contains the field default values.

To allow the creation of libraries of small, reusable PROTO definitions, browsers shall recognize EXTERNPROTO URLs that end with "#name" to mean the prototype definition of "name" in the given file. For example, a library of standard materials might be stored in a file called "materials.wrl" that looks like:

#VRML V2.0 utf8
PROTO Gold []   { Material { ... } }
PROTO Silver [] { Material { ... } }
...etc.

A material from this library could be used as follows:

#VRML V2.0 utf8
EXTERNPROTO Gold [] "http://.../materials.wrl#Gold"
...
    Shape { appearance Appearance { material Gold {} }
            geometry ...
    }

The advantage is that only one http fetch needs to be done if several things are used from the library; the disadvantage is that the entire library will be transmitted across the network even if only one prototype is used in the file.

4.7 Scripting

Issue: This section needs to be tightened up. Specically, the Browser Interface to Script nodes needs to be defined in a language-neutral manner, and it needs to be a comprehensive definition of the required semantics of any scripting implementation. This will occur before the final spec (obviously)...rc

4.7.1 Introduction

Decision logic and state management is often needed to decide what effect an event should have on the scene -- "if the vault is currently closed AND the correct combination is entered, then open the vault." These kinds of decisions are expressed as Script nodes that receive events in, process them, and generate other events. A Script node can also keep track of information between invocations, (i.e. managing internal state over time).

Event processing is done by a program or script contained in (or referenced by) the Script node's url field. This program or script can be written in any programming language that the browser supports. Browsers are not required to implement any specific scripting languages in VRML 2.0.

A Script node is activated when it receives an event. At that point the browser executes the program in the Script node's url field (passing the program to an external interpreter if necessary). The program can perform a wide variety of actions: sending out events (and thereby changing the scene), performing calculations, communicating with servers elsewhere on the Internet, and so on. See Execution Model for a detailed description of the ordering of event processing.

4.7.2 Script execution

Scripts nodes allow the world author to insert arbitrary logic into the middle of an event cascade. They also allow the world author to generate an event cascade when a Script node is created or, in some scripting languages, at arbitrary times.

Script nodes receive events in timestamp order. Any events generated as a result of processing a given event are given timestamps corresponding to the event that generated them. Conceptually, it takes no time for a Script node to receive and process an event, even though in practice it does take some amount of time to execute a Script.

4.7.3 initialize

Some scripting language bindings for VRML may define an initialization method (or constructor or whatever). This method must be called before any events are generated. Any events generated by the initialize method must have timestamps less than any other events that are generated by the Script node.

4.7.4 eventsProcessed

The scripting language binding may also define an eventsProcessed routine that is called after some set of events has been received. It allows Scripts that do not rely on the order of events received to generate fewer events than an equivalent Script that generates events whenver events are received. If it is used in some other way, eventsProcessed can be indeterministic, since different implementations may call eventsProcessed at different times.

For a single event cascade, a given Script node's eventsProcessed routine must be called at most once.

Events generated from an eventsProcessed routine are given the timestamp of the last event processed.

4.7.5 Scripts with direct outputs

Scripts that have access to other nodes (via SFNode or MFNode fields or eventIns) and that have their "directOutputs" field set to TRUE may directly post eventIns to those nodes. They may also read the last value sent from any of the node's eventOuts.

When setting a value in another node, implementations are free to either immediately set the value or to defer setting the value until the Script is finished. When getting a value from another node, the value returned must be up-to-date; that is, it must be the value immediately before the time of the current timestamp (the current timestamp is the timestamp of the event that caused the Script node to execute).

The order of execution of Script nodes that do not have ROUTES between them is undefined. If multiple directOutputs Scripts all read and/or write the same node, the results may be undefined. Just as with ROUTE fan-in, these cases are inherently indeterministic and it is up to the world creator to ensure that these cases do not happen.

4.7.6 Asynchronous scripts

Some languages supported by VRML browser may allows Script nodes to spontaneously generate events, allowing users to create Script nodes that function like new Sensor nodes. In these cases, the Script is generating the initial event that cause the event cascade, and the scripting language and/or the browser will determine an appropriate timestamp for that initial event. Such events are then sorted into the event stream and processed like any other event, following all of the same rules for looping, etc.

4.7.7 Script Languages

Scripts can be written in any language supported by the browser. The instructions for the script are referenced by the url field. This field may contain a URL which points to data on a server. The mime-type of the returned data defines the language type. Additionally instructions can be included inline using either the data: protocol (which allows a mime-type specification) or a custom language protocol defined for the specific language (in which the language type is inferred).

ISSUE: Gavin suggests that we add a subsection "Time during Script execution" here........rc

4.7.8 Receiving and Sending Events

ISSUE: This section is needed to define the semantics of get/set that ALL langs must support...rc

4.7.9 Browser Script Interface

The browser interface provides a mechanism for scripts contained by Script nodes to get and set browser state, such as the URL of the current world. This section describes the semantics that functions/methods that the browser interface supports. A C-like syntax is used to define the type of parameters and returned values, but is hypothetical. See the specific appendix for a language for the actual syntax required. In this hypothetical syntax, types are given as VRMLfield types. Mapping of these types into those of the underlying language (as well as any type conversion needed) is described in the appropriate language reference.

SFString getName( );

SFString getVersion( );

The getName() and getVersion() methods get the "name" and "version" of the browser currently in use. These values are defined by the browser writer, and identify the browser in some (unspecified) way. They are not guaranteed to be unique or to adhere to any particular format, and are for information only. If the information is unavailable these methods return empty strings.

SFFloat getCurrentSpeed( );

The getCurrentSpeed() method returns the speed at which the viewpoint is currently moving, in meters per second. If speed of motion is not meaningful in the current navigation type, or if the speed cannot be determined for some other reason, 0.0 is returned.

SFFloat getCurrentFrameRate( );

The getCurrentFrameRate() method returns the current frame rate in frames per second. The way in which this is measured and whether or not it is supported at all is browser dependent. If frame rate is not supported, or can't be determined, 0.0 is returned.

SFString getWorldURL( );

The getWorldURL() method returns the URL for the root of the currently loaded world.

void loadWorld( MFString url );

The loadWorld() method loads one of the URLs in the passed string and replaces the current scene root with the VRML file loaded. The browser first attempts to load the first URL in the list; if that fails, it tries the next one, and so on until a valid URL is found or the end of list is reached. If a URL cannot be loaded, some browser-specific mechanism is used to notify the user. Implementations may either block on a loadWorld() until the new URL finishes loading, or may return immediately and at some later time (when the load operation has finished) replace the current scene with the new one.

void replaceWorld( MFNode nodes );

The replaceWorld() method replaces the current world with the world represented by the passed nodes. This will usually not return, since the world containing the running script is being replaced.

MFNode createVrmlFromString( SFString vrmlSyntax );

The createVrmlFromString() method takes a string consisting of a VRML scene description, parses the nodes contained therein and returns the root nodes of the corresponding VRML scene.

void createVrmlFromURL( MFString url, SFNode node, SFString event );

The createVrmlFromURL() asks the browser to load a VRML scene description from the given URL or URLs. After the scene is parsed event is sent to the passed node returning the root nodes of the corresponding VRML scene. The event parameter contains a string naming an MFNode eventIn on the passed node.

void addRoute( SFNode fromNode, SFString fromEventOut, SFNode toNode,

                             SFString toEventIn );

void deleteRoute( SFNode fromNode, SFString fromEventOut,

                                  SFNode toNode, SFString toEventIn );

These methods respectively add and delete a route between the given event names for the given nodes.

4.8 Browser Extensions

4.8.1 Creating Extensions

Browsers that wish to add functionality beyond the capabilities in the specification should do so by creating prototypes or external prototypes. If the new node cannot be expressed using the prototyping mechanism (i.e. it cannot be expressed as VRML scene graph), then it should be defined as an external prototype with a unique URN specification. Authors who use the extended functionality may provide multiple, alternative URLs or URNs to represent the content to ensure that it is viewable on all browsers.

For example, suppose a browser A wants to create a Torus geometry node:

EXTERNPROTO Torus [ field SFFloat bigR, field SFFloat smallR ]
    ["urn:libary:Torus", "http://.../proto_torus.wrl" ]

Browser A will recognize the URN and use its own private implementation of the Torus node. Other browsers may not recognize the URN, and skip to the next entry in the URL list and search for the specified prototype file. If no URLs or URNs are found, the Torus is assumed to be a an empty node.

Note that the prototype name, "Torus", in the above example has no meaning whatsoever. The URN/URL uniquely and precisely defines the name/location of the node implementation. The prototype name is stricly a convention chosen by the author and shall not be interpreted in any semantic manner. The following example uses both "Ring" and "Donut" to name the torus node, but that the URN/URL, "urn:library:Torus, http://.../proto_torus.wrl", specify the actual definition of the Torus node:

#VRML V2.0 utf8

EXTERNPROTO Ring [field SFFloat bigR, field SFFloat smallR ]
    ["urn:library:Torus", "http://.../proto_torus.wrl" ]

EXTERNPROTO Donut [field SFFloat bigR, field SFFloat smallR ]
    ["urn:library:Torus", "http://.../proto_torus.wrl" ]

Transform { ... children Shape { geometry Ring } }
Transform { ... children Shape { geometry Donut } }

4.8.2 Reading extensions

VRML-compliant browsers must recognize and implement the PROTO, EXTERNPROTO, and URN specifications. Note that the prototype names (e.g. Torus) has no semantic meaning whatsoever. Rather, the URL and the URN uniquely determine the location and semantics of the node. Browsers shall not use the PROTO or EXTERNPROTO name to imply anything about the implementation of the node.

4.9 NodeConcepts

4.9.1 Bindable Leaf Nodes

The Background, Fog, NavigationInfo, and Viewpoint nodes have the unique behavior that only one of each type can be active (i.e. affecting the user's experience) at any point in time. The browser maintains a stack for each type of binding node. Each of these nodes includes a set_bind eventIn and an isBound eventOut. The set_bind eventIn is used to push and pop a given node from its respective stack. A TRUE value sent to set_bind, pushes the node to the top of the stack, and FALSE pops it from the stack. The bind_changed event is output when a given node's binding state changes (i.e. whenver set_bind is received). The node at the top of stack, (the most recently bound node), is the active node for its type and is used by the browser to set state. If an already bound node receives a set_bind TRUE event, then that node is moved to the top of the stack - there are not two entries for this node in the stack. If a node that is not bound receives a set_bind FALSE event, the event has no effect. If there are no bound nodes on the stack, then use the default values for each node.

Issue: Can the bind stack be popped to empty? (rc answer: yes) If so, what is the view? (rc answer:t he view is either at the origin or no-change, regardless of jump value.) Also, what is the view, if the file has zero Viewpoints? (probably undefined, up to browser) Does the isBound send when the node is pushed to top-of-stack and vice versa, OR when it is pushed onto the stack and out of the stack (these are very different behaviors)? (fouts answer: use top-of-stack behavior.)

Bind Stack Behavior

4.9.2 Geometry

Geometry nodes must be contained by Shape nodes - they are not leaf nodes and thus cannot be children of group nodes. The Shape node contains exactly one geometry node in its geometry field. This node must be one of the following node types:

A geometry node can appear only in the geometry field of a Shape node. Several geometry nodes also contain Coordinate, Color, Normal, and TextureCoordinate as geometry property nodes. These geometry property nodes are separated out as individual nodes so that instancing and sharing is possible between different geometry nodes. All geometry nodes are specified in a local coordinate system determined by the parent(s) nodes of the geometry.

ISSUE: This section needs a major clarification of the interaction between Material, Texture, and the various property binding flags (per vertex, per face, overall). This will include the lighting model equations. The subsection that follows is inadequate and must be improved.
Application of material, texture, and colors:
The final rendered look of a piece of geometry depends on the Material and Texture in the associated Appearance node along with any Color node specified with the geometry (such as per-vertex colors for an IndexedFaceSet node). The following describes ideal behavior; implementations may be forced to approximate the ideal behavior:
Shape Hints Fields:
The ElevationGrid, Extrusion, and IndexedFaceSet nodes all have three SFBool fields that provide hints about the shape--whether it contains ordered vertices, whether the shape is solid, and whether it contains convex faces. These fields are ccw, solid, and convex.

The ccw field indicates whether the vertices are ordered in a counter-clockwise direction when the shape is viewed from the outside (TRUE). If the order is clockwise or unknown, this field value is FALSE. The solid field indicates whether the shape encloses a volume (TRUE), and can be used as a hint to perform backface culling. If nothing is known about the shape, this field value is FALSE (and implies that backface culling cannot be performed and that the polygons are two-sided). The convex field indicates whether all faces in the shape are convex (TRUE). If nothing is known about the faces, this field value is FALSE.

These hints allow VRML implementations to optimize certain rendering features. Optimizations that may be performed include enabling backface culling and disabling two-sided lighting. For example, if an object is solid and has ordered vertices, an implementation may turn on backface culling and turn off two-sided lighting. If the object is not solid but has ordered vertices, it may turn off backface culling and turn on two-sided lighting.

Crease Angle Field:
The creaseAngle field, used by the ElevationGrid, Extrusion, and IndexedFaceSet nodes, affects how default normals are generated. For example, when an IndexedFaceSet has to generate default normals, it uses the creaseAngle field to determine which edges should be smoothly shaded and which ones should have a sharp crease. The crease angle is the angle between surface normals on adjacent polygons. For example, a crease angle of .5 radians means that an edge between two adjacent polygonal faces will be smooth shaded if the normals to the two faces form an angle that is less than .5 radians (about 30 degrees). Otherwise, it will be faceted. Crease angles must be greater than or equal to 0.0.

4.9.3 Grouping nodes

Grouping nodes are used to create hierarchical transformation objects. Grouping nodes have a children field that contains a list of nodes which are the descendants of the group. Children nodes are restriced to the following node types:

Anchor NavigationInfo SpotLight
Background NormalInterpolator SphereSensor
Billboard OrientationInterpolator Switch
Collision PlaneSensor TimeSensor
ColorInterpolator PointLight TouchSensor
CoordinateInterpolator PositionInterpolator Transform
CylinderSensor ProximitySensor Viewpoint
DirectionalLight ScalarInterpolator VisibilitySensor
Fog Script WorldInfo
Group Shape
LOD Sound

All grouping also nodes have addChildren and removeChildren eventIn definitions. addChildren event adds the nodes passed in to the group's children field. Any nodes passed to the addChildren event that are already in the group's children list are ignored. The removeChildren event removes the nodes passed in from the group's children field. Any nodes passed in the removeChildren event that are not in the group's children list are ignored.

The following nodes are grouping nodes:

4.9.4 Interpolators

Issue: This section needs to remove the references to time - the key field is not time, but the abscissa (sp?) of a linear function.

Interpolators nodes are designed for linear keyframed animation. That is, an interpolator node defines a piecewise linear function, f(t), on the interval (-infinity, infinity). The piecewise linear function is defined by n values of t, called key, and the n corresponding values of f(t), called keyValue. The keys must be monotonic non-decreasing and are not restricted to any interval. An interpolator node evaluates f(t) given any value of t (via the set_fraction eventIn).

Let the n keys k0, k1, k2, ..., k(n-1) partition the domain (-infinity, infinity) into the n+1 subintervals given by (-infinity, k0), [k0, k1), [k1, k2), ... , [k(n-1), infinity). Also, let the n values v0, v1, v2, ..., v(n-1) be the values of an unknown function, F(t), at the associated key values. That is, vj = F(kj). The piecewise linear interpolating function, f(t), is defined to be

     f(t) = v0,     if t < k0,
          = v(n-1), if t > k(n-1),
          = vi,     if t = ki for some value of i, where -1<i<n,
          = linterp(t, vj, v(j+1)), if kj < t < k(j+1),

where linterp(t,x,y) is the linear interpolant, and -1< j < n-1. The third conditional value of f(t) allows the defining of multiple values for a single key, i.e. limits from both the left and right at a discontinuity in f(t).The first specified value will be used as the limit of f(t) from the left, and the last specified value will be used as the limit of f(t) from the right. The value of f(t) at a multiply defined key is indeterminate, but should be one of the associated limit values.

There are six different types of interpolator nodes, each based on the type of value that is interpolated (e.g. scalar, color, normal, etc.). All interpolator nodes share a common set of fields and semantics:

      exposedField MFFloat      key           [...]
      exposedField MF<type>     keyValue      [...]
      eventIn      SFFloat      set_fraction
      eventOut     [S|M]F<type> value_changed

The type of the keyValue field is dependent on the type of the interpolator (e.g. the ColorInterpolator's keyValue field is of type MFColor). Each value in the keyValue field corresponds in order to a parameterized time in the key field. Therefore, there exists exactly the same number of values in the keyValue field as key values in the key field.

The set_fraction eventIn receives a float event and causes the interpolator function to evaluate. The results of the linear interpolation are sent to value_changed eventOut.

Four of the six interpolators output a single-valued field to value_changed. The exceptions, CoordinateInterpolator and NormalInterpolator, send multiple-value results to value_changed. In this case, the keyValue field is an nxm array of values, where n is the number of keys and m is the number of values per key. It is an error if m is not a positive integer value.

The following example illustrates a simple ScalarInterpolator which contains a list of float values (11.0, 99.0, and 33.0), the keyframe times (0.0, 5.0, and 10.0), and outputs a single float value for any given time:

    ScalarInterpolator [
       key      [ 0.0,  5.0,  10.0]
       value    [11.0, 99.0, 33.0]
    }

For an input of 2.5 (via set_fraction), this ScalarInterpolator would send an output value of:

    eventOut SFFloat value_changed 55.0
                         # = 11.0 + ((99.0-11.0)/(5.0-0.0)) * 2.5

Whereas the CoordinateInterpolator below defines an array of coordinates for each keyframe value and sends an array of coordinates as output:

    CoordinateInterpolator [
       key   [ 0.0,  0.5,  1.0]
       value [ 0  0  0,    10 10 30,   # 2 keyValue(s) at key 0.0
                10 20 10,   40 50 50,  # 2 keyValue(s) at key 0.5
                33 55 66,   44 55 65 ] # 2 keyValue(s) at key 1.0

    }

In this case, there are two coordinates for every keyframe. The first two coordinates (0, 0, 0) and (10, 10, 30) represent the value at keyframe 0.0, the second two coordinates (10, 20, 10) and (40, 50, 50) represent that value at keyframe 0.5, and so on. If a set_fraction value of 0.25 (meaning 25% of the animation) was sent to this CoordinateInterpolator, the resulting output value would be:

     eventOut MFVec3f value_changed [ 5 10 5,  25 30 40 ]

Note: Given a sufficiently powerful scripting language, all of these interpolators could be implemented using Script nodes (browsers might choose to implement these as pre-defined prototypes of appropriately defined Script nodes). Keyframed animation is sufficiently common and performance intensive to justify the inclusion of these classes as built-in types.

4.9.5 Lights and Lighting

Issue: This section will have a detailed description of the lighting model in VRML. This will include all the various permuations of material, texture, color, and vertex/face bindings. This needs to include Fog too.

Objects are illuminated by the sum of all of the lights in the world. This includes the contribution of both the direct illumination from lights (PointLight, DirectionalLight, and SpotLight) and the ambient illumination from these lights. Ambient illumination results from the scattering and reflection of light originally emitted directly by the light sources. Therefore, ambient light is associated with the lights in the scene, each having an ambientIntensity field. The contribution of a single light to the overall ambient lighting is computed as:

    if ( light is "on" )
        ambientLight = intensity * ambientIntensity * diffuse color
    else
        ambientLight = (0,0,0)

This allows the light's overall brightness, both direct and ambient, to be controlled by changing the intensity. Renderers that do not support per-light ambient illumination shall approximate by setting the ambient lighting parameters when the world is loaded.

PointLight and SpotLight illuminate all objects in the world that fall within their volume of lighting influence regardless of location within the file. PointLight defines this volume of influence as a sphere centered at the light (defined by a radius). SpotLight defines the volume of influence a solid angle defined by a radius and a cutoff angle. DirectionalLights illuminate only the objects contained by the light's parent group node (including any descendant children of the parent group node).


Temporary: Until the lighting model is clarified above, the following info should help:


4.9.6 Sensors

There are several different kinds of sensor nodes: ProximitySensor, TimeSensor, VisibilitySensor, and a variety of pointer device sensors. Sensors are leaf nodes in the hierarchy and therefore may be children of grouping nodes.

The ProximitySensor detects when the user navigates into a specified invisible region in the world. The TimeSensor is a stop watch that has no geometry or location associated with it - it is used to start and stop time-based nodes, such as interpolators. The VisibilitySensor detects when a specific part of the world becomes visible to the user. Pointer device sensors detect user pointing events, such as the user clicking on a piece of geometry (i.e. TouchSensor).

Proximity, time, and visibility sensors are additive. Each one is processed independently of whether others exist or overlap.

Pointer device sensors are activated when the user points to geometry that is influenced by a specific geometry sensor. Geometry sensors have influence over all geometry that is a descendent of the geometry sensor's parent group. Typically, the geometry sensor is a sibling child to the geometry that it influences. In other cases, the geometry sensor is a sibling to groups which contain geometry (that is influenced by the geometry sensor). For a given user gesture, the lowest, enabled geometry sensor in the hierarchy is activated - all other geometry sensors above it are ignored. The hierarchy is defined by the geometry leaf node which is activated and the entire hierarchy upward. If there are multiple geometry sensors tied for lowest, then each of these is activated simultaneously and independently. This last feature allows useful combinations of geometry sensors (e.g. TouchSensor and PlaneSensor).

Drag Sensors

VRML has 3 drag sensors (CylinderSensor, PlaneSensor, SphereSensor) in which pointer motions cause events to be generated according to the "virtual shape" of the sensor. For instance the output of the SphereSensor is an SFRotation, rotation_changed, which can be connected to a Transform's set_rotation field to rotate an object. The effect is the user grabs an object and spins it about the center point of the SphereSensor.

To simplify the application of these sensors, each node has an offset and an autoOffset exposed field. Whenever the sensor generates output, (as a response to pointer motion), the offset is added to the output value (e.g. SphereSensor's rotation_changed). If autoOffset is TRUE (default), this offset is set to the last output value when the pointing device button is released (isActive FALSE). This allows subsequent grabbing operations to generate output relative to the last release point. A simple dragger can be constructed by sending the output of the sensor to a Transform whose child is the object being grabbed. For example:

    Group {
        children [
            DEF S SphereSensor { autoOffset TRUE }
            DEF T Transform {
                children [ Shape { geometry Box { } } ]
            }
        ]
        ROUTE S.rotation_changed TO T.set_rotation
    }

The box will spin when it is grabbed and moved via the pointer.

When the pointing device button is released, offset is set to the last output value and an offset_changed event is sent out. This behavior can be disabled by setting the autoOffset field to FALSE.

 Contact rikk@best.com , cmarrin@sgi.com, or gavin@acm.org with questions or comments.
This URL: http://vrml.sgi.com/moving-worlds/spec/part1/concepts.html