The Moving Worlds VRML 2.0 Specification

Key Concepts

Draft #2b, June 4, 1996

This section describes key concepts related to the definition and use of Moving Worlds VRML 2.0. 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.

File Syntax and Structure

Nodes, Fields, and Events

The Structure of the Scene Graph

Time

Events

Prototypes

Scripting

File syntax

Nodes concepts

File Syntax and Structure

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

#VRML Draft #2 V2.0 utf8

Note that the final VRML 2,.0 specification will not have Draft #n in the header. However, all draft versions of VRML files must contain the appropriate draft number to guarantee compatibility between browsers.

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: #), comma (0x2c: ,), 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."

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 DirectionalLight node's public interface and file format:

    DirectionalLight {  
      exposedField SFFloat ambientIntensity 0
      exposedField SFColor color            1 1 1
      exposedField SFVec3f direction        0 0 -1
      exposedField SFFloat intensity        1 
      exposedField SFBool  on               TRUE
    }

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.

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 DirectionalLight is:

DirectionalLight {
  on               TRUE
  intensity        1
  ambientIntensity 0
  color            1 1 1
  direction        0 0 -1
}

URLs and 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 fields in VRML 2.0 that have URLs 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 given as the first file, 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 can be included directly in the VRML file using the data: and vrmlscript: protocols. 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 the need to fetch multiple URLs.

The vrmlscript: protocol is specific to VRML. It can be used only in the url field of the Script node. It allows inlining of VRMLScript functions. All UTF8 characters are allowed as well as the newline character, facilitating multiline scripts. Unlike other URLs no character need be escaped except the double quote, which is done with (/").

File Extension

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

MIME Type

The MIME type for VRML files is defined as follows:

x-world/x-vrml

The MIME major type for 3D world descriptions is x-world. The MIME minor type for VRML documents is x-vrml. Other 3D world descriptions, such as oogl for The Geometry Center's Object-Oriented Geometry Language, or iv, for SGI's Open Inventor ASCII format, can be supported by using different MIME minor types.

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."

Nodes, Fields, and Events

At the highest level of abstraction, VRML is just 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. These objects are called nodes. Nodes contain data, which is stored in fields.

VRML defines several different classes of nodes. Most of the nodes can be classified into one of two categories; grouping nodes or leaf nodes. Grouping nodes gather other nodes together, allowing collections of nodes (specified in a grouping-node field called children) to be treated as a single object. Some grouping nodes also control which of their children are drawn.

Leaf nodes may not have children. Nodes that are considered leaf nodes include shapes, lights, viewpoints, sounds, scripts, sensors, interpolators, and nodes that provide information to the browser.

Shape nodes contain two kinds of additional information: geometry and appearance. For purposes of discussion, this specification uses a third node category, subsidiary nodes, for nodes that are always used within fields of other nodes and cannot be used alone. These nodes include geometry (for example, Cone and Box), geometric property (for example, Coordinate3 and Normal), appearance (Appearance) and appearance property nodes (for example, Material and ImageTexture).

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 fields.

Sample File

For example, this file contains a simple scene defining a view of a red sphere and a blue box, lit by a directional light:

#VRML Draft #2 V2.0 utf8
Transform {
  children [

    DirectionalLight {        # First child
        direction 0 0 -1      # Light illuminating the scene
    }

    Transform {               # Second child - a red sphere
      translation 3 0 1
      children [
        Shape {
          geometry Sphere { radius 2.3 }
          appearance Appearance
             material Material { diffuseColor 1 0 0 }   # Red
        }
      ]
    }

    Transform {               # Third child - a blue box 
      translation -2.4 .2 1
      rotation     0 1 1  .9
      children [
        Shape {
          geometry Box {}
          appearance Appearance
             material Material { diffuseColor 0 0 1 }  # Blue
        }
      ]
    }

  ] # end of children for world
}

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.

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.

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 "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 an instance of the node. The USE keyword indicates that a previously named node should be used again. If several nodes were given the same name, then the last DEF encountered during parsing "wins." DEF/USE is limited to a single file; EXTERNPROTO/PROTO must be used to refer to a node type that is defined in another file. For example, if a node is defined inside a file referenced by a Inline node, the file containing the Inline node cannot USE that node.

Rendering the following scene results in three spheres being drawn. Both of the spheres are named "Joe"; the second (smaller) sphere is drawn twice, on either side of the first (larger) sphere:

#VRML Draft #2 V2.0 utf8
Transform {
  children [

    DEF Joe Sphere { }
    Transform {
      translation 2 0 0
      children [
        DEF Joe Sphere { radius .2 }
      ]
    }

    Transform {
      translation -2 0 0
      children [
        # radius .2 sphere will be used here; most recent one defined
        USE Joe ]
    }

  ]
}

Tools that create VRML files may need to modify the 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.

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 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 node. These fields are translation, rotation, scale, scaleOrientation, and center.

Given a vertex V and a series of transformations such as:

Transform {
  translation T
  rotation    R
  scale       S
  children [
    Shape {
      geometryPointSet { ... }
    }
  ]
}

the vertex is transformed into vertex V' in its parent's coordinate system by first scaling, then rotating, and finally translating. In matrix-transformation notation, thinking of T, R, and S as the equivalent transformation matrices,

V' = T·R·S·V

(if you think of vertices as column vectors)

or

V' = V·S·R·T

(if you think of vertices as row vectors).

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 inheriting the transformations of its 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.)

Viewing Model

This specification assumes that there is a user viewing and interacting with the VRML world. It is expected that a future extension to this specification will provide mechanisms for creating multi-participant worlds. The viewing and interaction model that should be used for the single-participant case is described here.

The world creator 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 particular coordinate system, and either the viewpoint or the coordinate system may be animated.

It is expected that browsers will support user-interface mechanisms by which users may "teleport" themselves from one viewpoint to another, and scripting-language mechanisms by which a viewer can be bound to a viewpoint which can then be animated. 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.

The browser may provide a user interface that allows the user to change his or her viewing position or orientation, which will also change the currently bound viewpoint.

Time

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.

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.

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

Events

Most nodes can receive events, which have names and types corresponding to their fields, with the effect that the corresponding field is changed to the value of the event received. For example, the Transform node can receive set_translation events (of type SFVec3f) that change the Transform's translation field (it may also receive set_rotation events, set_scale events, and so on).

Nodes can also generate events that have names and types corresponding to their fields when those fields are changed. For example, the Transform node generates a translation_changed event when its translation field changes.

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 field 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: add_children and remove_children. 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 the browser scripting language.

Sensors

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

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
                      ... ] {
  Scene graph
  (nodes, prototypes, and routes, containing IS statements)
}

A prototype is not a node; it merely defines a prototype (named prototypename) that can be instantiated later in the same file as if it were a built-in node. The implementation of the prototype is contained in the scene graph rooted by node. That node may be followed by Script and/or ROUTE declarations, as necessary to implement the prototype.

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

The eventIn and eventOut declarations export events from the scene graph rooted by node. Specifying the type of each event in the prototype is intended to prevent errors when the implementation of prototypes is changed 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 that is not part of a prototype's implementation is an error. It is an error for an IS statement to refer to something that is not part of the prototype's interface 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.

[ISSUE: Rules for mapping exposedFields through the IS mechanism need to be nailed down. For example, is it ok to map an intenal field as an exposedField in the PROTO? Is it ok to map an intenal eventIn to an exposedField in the PROTO? etc...]

A prototype is instantiated as if typename were a built-in node. For example, a simple chair with variable colors for the leg and seat might be prototyped as:

PROTO TwoColorChair [ field MFColor legColor  .8 .4 .7
                      field MFColor seatColor .6 .6 .1 ] {
  Transform {
    children [

      Transform { # chair seat
        children [
          Shape {
            appearance Appearance {
              material Material { diffuseColor IS seatColor }
            }
            geometry Box { ... }
          }
        ]
      }

      Transform { # chair leg
        translation ...
        children [
          Shape {
            appearance Appearance {
              material Material { diffuseColor IS legColor }
            }
            geometry Cylinder { ... }
          }
        ]
      }

    ] # End of root Transform's children
  } # End of root Transform
} # End of prototype

The prototype is now defined. Although it contains a number of nodes, only the legColor and seatColor fields are public. Instead of using the default legColor and seatColor, this instance of the chair has red legs and a green seat:

TwoColorChair {
  legColor 1 0 0
  seatColor 0 1 0
}

Prototype instances may be named using DEF and may be multiply instanced using USE.

A prototype instance can be used in the scene graph wherever its root node can be used. For example, a prototype defined as:

PROTO MyObject [ ... ] {
  Transform { ... }
}

can be instantiated wherever a Transform can be used, since the root node of this prototype's implementation is a Transform node.

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

Prototype definitions appearing inside a prototype implementation 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 such a nested prototype's implementation may not refer to the enclosing prototype's interface.

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 {}
}

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 are specified, the first one found should be used.

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 points to a file that contains the prototype implementation, and this file contains the default values.

To allow the creation of libraries of small, re-usable PROTO definitions, browsers should 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 Draft #2 V2.0 utf8
PROTO Gold [] { Material { ... appropriate fields ... } }
PROTO Silver [] { Material { ... } }
   etc.

A material from this library could be used as follows:

#VRML Draft #2 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 thing is used from it.

Extensibility

The set of built-in VRML nodes can be extended using either prototypes or external prototypes. External prototypes provide a way to extend VRML in a manner that all browsers will understand. If a new node type is defined as an external prototype, other browsers can parse it and understand what it looks like, or they can ignore it. An external prototype uses the URL syntax to refer to an internal or built-in implementation of a node. For example, suppose your system has a Torus geometry node. This node can be exported to other systems using an external prototype:

EXTERNPROTO Torus [ field SFFloat bigRadius
                    field SFFloat smallRadius ]
  ["urn:yourdomain:Torus", "http://machine/directory/protofile" ]

The browser can recognize the URN and look for its own internal implementation of the Torus node. If it does not recognize the URN, it goes to the next URL and searches for the specified prototype file. In this case, if the file is not found, it ignores the Torus. If more URLs are listed, the browser tries each one until it succeeds in locating an implementation for the node or it reaches the end of the list.

Naming Conventions for Prototypes

Check the "File Syntax and Structure" section of this standard for the rules on valid characters in names.

To avoid namespace collisions with nodes defined by other people, any of the following conventions should be followed.

  1. Anyone can pick names that include a suffix of an underscore followed by a domain name that you own with the periods changed into underscores. For example, a company owning foo.com could create an extension node "Cube_foo_com".
  2. If you are building a product-- for example, an authoring tool or a browser-- or defining a lot of new nodes, then you can apply for a short prefix. Email type_registry@vrml.org to register for the prefix. This will normally be accepted if it is the most significant part of a .com, .org, or .net address. In the above example, foo.com could register the extension "_foo" and create nodes of the form "Cube_foo".
  3. Extensions supported by several companies should be registered and use the "_X" extension.

Scripting

Logic is often necessary 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 take in events, process them, and generate other events. A Script node can also keep track of information between invocations, "remembering" what its internal state is over time.

The event processing is done by a program contained in (or referenced by) the Script node's url field. This program can be written in any programming language that the browser supports.

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.

Script Languages

Scripts can be written in any language supported by the browser. VRMLScript and Java are the most common scripting language implementations. VRMLScript is a simple language designed to be tightly integrated with VRML and simple to author. VRMLScript functions can be included inline in the url field using the vrmlscript: protocol, or a URL can be specified as with other languages.

A Language other than VRMLScript can be used as well as long as the browser supports it. Languages are typed using the standard mime-type capability of the URL specification. Functions for the script are obtained from a file specified in the url field. The data: protocol allows script functions to be included inline. The binding of the script functions to VRML are as defined in the language definition for the particular language and is beyond the scope of the VRML specification.

Execution Model

TBD (Gavin)

Browser Interface

The API provides ways for scripts to get and set global information associated with the VRML browser, such as the URL of the current world. Here are descriptions of the functions/methods that the browser API supports. In the syntax below, a C-like syntax is used to define the type of parameters and returned values. Types are given as VRML field types. Mapping of these types into those of the underlying language (as well as any type conversion needed) is a binding issue. Please refer to 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, 100.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 createVRMFromURL() 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.

Scripting Example

This Script node decides whether or not to open a bank vault given openVault and combinationEntered messages To do this it remembers whether or not the correct combination has been entered:

DEF OpenVault Script {
  # Declarations of what's in this Script node:
  eventIn SFTime openVault
  eventIn SFBool combinationEntered
  eventOut SFTime vaultUnlocked
  field SFBool unlocked FALSE

  # Implementation of the logic:
  url "vrmlscript:
       function combinationEntered(value) { unlocked = value; }
       function openVault(value) {
           if (unlocked) vaultUnlocked = value;
       }"
}

Note that the openVault eventIn and the vaultUnlocked eventOut are or type SFTime. This is so they can be wired directly to a TouchSensor and TimeSensor, respectively. The TimeSensor can output into an interpolator which performs an opening door animation.

Appearance Nodes

The Material, Texture, and TextureTransform appearance property nodes are always contained within fields of an Appearance node. The FontStyle node is always contained in the fontStyle field of a Text node.

Bindable Leaf Nodes

The Background, NavigationInfo, and Viewpoint leaf 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: Background stack, NavigationInfo stack, and Viewpoint stack. Each of these nodes includes a set_bind eventIn and an bind_changed 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.

Bind Stack Behavior

Bindable Nodes

Geometry Nodes

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.

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). If nothing is known about the shape, this field value is FALSE. 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.

Geometric Property Nodes

Geometric properties must be contained in the corresponding SFNode fields of geometry nodes such as the IndexedFaceSet, IndexedLineSet, and PointSet nodes. The following nodes are geometric properties:

For example, the following IndexedFaceSet (contained in a Shape node) uses all four of the geometric property nodes to specify vertex coordinates, colors per vertex, normals per vertex, and texture coordinates per vertex (note that the material sets the overall transparency):

Shape {
  geometry IndexedFaceSet {
     coordIndex  [ 0, 1, 3, -1, 0, 2, 5, -1, ...]
     coord       Coordinate        { point [0.0 5.0 3.0, ...] }
     color       Color             { rgb [ 0.2 0.7 0.8, ...] }
     normal      Normal            { vector [0.0 1.0 0.0, ...] }
     texCoord    TextureCoordinate { point [0 1.0, ...] }
  }
  appearance Appearance { material Material { transparency 0.5 } }
}

Global Nodes

The Script and WorldInfo nodes are not part of the world's transformational hierarchy.

WorldInfo nodes are global nodes that affect everything in the scene. They can be used anywhere in the scene description and may appear in fields of a Script node. If more than one WorldInfo node appears in a file, the first one encountered during read is the one that is used.

Grouping Nodes

Grouping nodes are container objects that have other nodes as children. Each grouping node treats its children in a different manner.

Interpolator Nodes

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 keys, and the n corresponding values of f(t), called values. The keys must be monotonic nondecreasing 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      keys         [...]
      exposedField MF<type>     values       [...]
      eventIn      SFFloat      set_fraction 
      eventOut     [S|M]F<type> outValue

The type of the values field is dependent on the type of the interpolator (e.g. the ColorInterpolator's values field is of type MFColor). Each value in the values field corresponds in order to a parameterized time in the keys field. Therefore, there exists exactly the same number of values in the values field as key values in the keys 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 outValue eventOut.

Four of the six interpolators output a single-valued field to outValue. The exceptions, CoordinateInterpolator and NormalInterpolator, send multiple-value results to outValue. In this case, the values 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 [
       keys      [ 0.0,  5.0,  10.0]
       values    [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 outValue 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 [
       keys   [ 0.0,  0.5,  1.0]
       values [ 0  0  0,    10 10 30,  # 2 values at key 0.0
                10 20 10,   40 50 50,  # 2 values at key 0.5
                33 55 66,   44 55 65 ] # 2 values 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 outValue [ 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.

Leaf Nodes

Leaf nodes are ???

Lights and Lighting

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 * 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 may simply use this information to set the ambient lighting parameters when the world is loaded.

PointLight and SpotLight illuminate all objects in the world that fall within their volume of influence of the light 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 descendent children of the group node).

Sensor Nodes

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 object in the world becomes visible to the user and vice versa. Geometric sensor nodes detect user pointing events, such as the user clicking on a piece of geometry (i.e. TouchSensor). They are leaf nodes that exist in the local coordinate system determined by their place in the scene hierarchy.

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).

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