The Annotated VRML 97 Reference

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

  About the Book
  Copyright © 1997-99
  Purchase the book from

Chapter 3:
Node Reference


+3.26 LOD

LOD { 
  exposedField MFNode  level    [] 
  field        SFVec3f center   0 0 0    # (-INF,INF)
  field        MFFloat range    []       # (0,INF)

The LOD node specifies various levels of detail or complexity for a given object, and provides hints allowing browsers to automatically choose the appropriate version of the object based on the distance from the user. The level field contains a list of nodes that represent the same object or objects at varying levels of detail, ordered from highest level of detail to the lowest level of detail. The range field specifies the ideal distances at which to switch between the levels. Section "2.6.5 Grouping and children nodes" contains details on the types of nodes that are legal values for level.

TECHNICAL NOTE: It might seem strange that the "children" of an LOD node aren't stored in a field called children, but are stored in the level field. Grouping nodes that have a children field (Anchor, Transform, Collision, Group, Billboard) all share similar semantics. The order of the nodes in the children field doesn't matter and they always draw all of them. LOD levels have different semantics--the order of levels is critical and only one level is drawn at a time.

TIP: It is often useful to use an empty Group or WorldInfo node as the last level of an LOD so nothing is displayed when an object is far enough away. It can also be very useful to use an empty Group or WorldInfo as the first LOD level so that very large objects disappear if the user gets too close to them. For example, the exterior of a skyscraper might be modeled in several levels of detail, separately from each part of the building's interior. The center of the model is the center of the building. The highest level of detail, shown when the user is inside the building, might be nothing at all since there is no reason to show the exterior when the user is inside the building.

The center field is a translation offset in the local coordinate system that specifies the centre of the LOD node for distance calculations.

The number of nodes in the level field shall exceed the number of values in the range field by one (i.e., N+1 level values for N range values). The range field contains monotonic increasing values that shall be greater than 0. In order to calculate which level to display, first the distance is calculated from the viewer's location, transformed into the local coordinate system of the LOD node (including any scaling transformations), to the center point of the LOD node. The LOD node evaluates the step function L(d) to choose a level for a given value of d (where d is the distance from the viewer position to the centre of the LOD node).

Let n ranges, R0, R1, R2, ..., Rn-1, partition the domain (0, +infinity) into n+1 subintervals given by (0, R0), [R0R1)... , [Rn-1, +infinity). Also, let n+1 levels L0, L1, L2, ..., Ln-1 be the values of the step function function L(d). The level node, L(d), for a given distance d is defined as follows:

    L(d) = L0,   if d < R0,
         = Li+1, if Ri <= d < Ri+1, for -1 < i < n-1,
         = Ln-1, if d >= Rn-1.

Specifying too few levels will result in the last level being used repeatedly for the lowest levels of detail. If more levels than ranges are specified, the extra levels are ignored. An empty range field is an exception to this rule. This case is a hint to the browser that it may choose a level automatically to maintain a constant display rate. Each value in the range field shall be greater than the previous value; otherwise results are undefined.

LOD nodes are evaluated top-down in the scene graph. Only the descendants of the currently selected level are rendered. All nodes under an LOD node continue to receive and send events regardless of which LOD node's level is active. For example, if an active TimeSensor node is contained within an inactive level of an LOD node, the TimeSensor node sends events regardless of the LOD node's state.

LOD node example

Figure 3-35: LOD Node

TIP: LOD is meant to be used to optimize performance by drawing fewer or simpler polygons for objects that are far away from the viewer. Because browsers may adjust or ignore the LOD switching distances to maintain a reasonable frame rate, content creators should refrain from using LODs for other special effects. For example, if you want a door to open as the user approaches it, you should use a ProximitySensor. If you use an LOD (with the closest level being a door fully open and the farthest being a door fully closed), you may not get the behavior you expect in all implementations.

Various other types of level-of-detail schemes can be created using ProximitySensors, Scripts, and Switch nodes. For example, a ProximitySensor can report the orientation of the viewer with respect to the ProximitySensor's coordinate system. You could give that information to a Script that then sets the Switch to display a rectangle with a prerendered texture map of the object from that viewing angle. In fact, an LOD that just switches based on distance can be recreated using a ProximitySensor, and a Switch node.

TIP: LOD is the most important node in VRML for performance tuning. Use it whenever possible to avoid unnecessary rendering complexity of objects that are far away or out of view. Note that a large percentage of the scene will be at a low LOD level most of the time. Thus, it is important to create very low-complexity versions of the objects (e.g., one to four polygons) for the lowest or second-to-lowest level of the LOD. Authors will find that making the lowest level invisible (e.g., WorldInfo node) helps performance considerably and is hardly noticed by the user (especially when used with a Fog node to hide popping). Three to four levels are recommended, with the lowest containing a WorldInfo and the second-to-lowest containing a very low polygon count Shape.

TIP: Use the Inline node to define the children of the more complex levels of the LOD. This has the nice result of delaying the download of the geometry until it is needed. Often, large portions of the scene will not be downloaded since the user restricted navigation to a small part of the world and is not penalized by waiting for the entire world to download. It is recommended that the lowest visible level of the LOD not be inlined. This ensures that there is always something to render whether the browser is busy downloading or not (or if the connection is down).

TECHNICAL NOTE: The ideal distance to switch between levels is the nearest distance at which a viewer with the default field-of-view (45 degrees; see the Viewpoint node) cannot detect the change, assuming a display device with infinite resolution being viewed by a person with 20/20 vision. Theoretically, given a set of LOD levels, a computer could compute the ideal distance by rendering the levels at various distances and resolutions, performing pixel comparisons on the results, and taking into account average human physiology. However, it is more practical for the scene creator to specify reasonable switching distances based on their knowledge of how much " LOD popping" they are willing to tolerate for each object. For unimportant objects it is best to omit ranges entirely, allowing the browser to choose the best level it has time to render. For important objects, you might combine the two techniques. For example, there might be three representations of an object that are acceptable as close-up views when the user is within ten meters. And there might be two simpler representations (perhaps a simple Box and nothing at all) that are acceptable when the user is farther than ten meters. This can be expressed to the VRML browser as
     LOD {          # Two level LOD, near and far:
       range [ 10 ]
       level [
         LOD {      # Performance LOD:  Any of these OK when near:
           level [
             DEF HIGH Inline { url "...High.wrl" }
             DEF MEDIUM Inline { url "...Medium.wrl" }
             DEF LOW Inline { url "...Low.wrl" }
        LOD {       # Second performance LOD: these OK when far:
           level [
             USE LOW        # Lowest level OK when far away,
             Shape {        # or display a simple Box,
               geometry Box { size ... }
               appearance Appearance { material Material { ... } }
             WorldInfo { }   # or, display nothing.

TECHNICAL NOTE: Actually, implementations can optimize away changes made to things that cannot be seen (or heard or otherwise detected by the user interacting with the virtual world), and might not generate events for a TimeSensor modifying objects underneath an LOD level that is not being seen. Since there are no guarantees about how often a TimeSensor generates events while it is active, it is perfectly legal to have unseen TimeSensors generate no events while they are hidden. This is the key to VRML's scalability and is what makes VRML theoretically capable of dealing with arbitrarily large worlds.

Combining LOD with the Inline node or EXTERNPROTO instances is very powerful, allowing optimization of both rendering speed and conservation of network bandwidth. If the user never gets close to an object, only a coarse representation of the object needs to be loaded from across the network and displayed. Implementations can globally optimize rendering time, figuring out which LODs are most important (based on the range hints given by the scene creators and any built-in heuristics) and adjusting which levels are drawn to give the best results possible. Implementations can also globally optimize network bandwidth, allocating more bandwidth to important objects (or to objects that it might predict will soon be important, perhaps based on the direction the user is moving) and less to unimportant objects. If LOD was not a built-in node, these kinds of global optimizations done by the browser would not be possible.

EXAMPLE (click to run): The following example illustrates typical use of the LOD node (see Figure 3-35). Note that each level may contain any type of node. For example, level 0 contains a Cone node for maximum fidelity, while levels 1 and 2 use an IndexedFaceSet, level 3 uses a Billboard, and the last level is basically empty but uses a WorldInfo node as a placeholder. It is very good for performance to keep the last level empty. There are several options for creating an empty level. WorldInfo is the best choice since it contains no state and should have a small memory overhead. An empty Group node is a second option (and possibly more logical) for creating an empty level, but may incur traversal overhead.

#VRML V2.0 utf8
  range [ 25, 100, 200, 400 ]
  level  [
    # level 0 - default gray, lit cone
    Transform { translation 0 1.5 0  children
      Shape {
        appearance DEF AP Appearance { material Material {} }
        geometry Cone { bottomRadius 1  height 3 }
    # level 1 - lit, 8 triangle cone approximation
    Shape {
      appearance USE AP
      geometry IndexedFaceSet {
        coord Coordinate {
          point [ 1 0 0, .707 0 -.707, 0 0 -1,
                  -.707 0 -.707, -1 0 0, -.707 0 .707, 0 0 1,
                  .707 0 .707, 0 3 0 ] }
          coordIndex [ 0 1 8 -1  1 2 8 -1  2 3 8 -1  3 4 8 -1  
                       4 5 8 -1  5 6 8 -1  6 7 8 -1  7 0 8 -1
                       0 7 6 5 4 3 2 1 ]
      # level 2 - lit, tetrahedron
      Shape {
      appearance USE AP
      geometry IndexedFaceSet {
        coord Coordinate {
          point [ 1 0 0, 0 0 -1, -1 0 0, 0 0 1, 0 3 0 ] }
        coordIndex [ 0 1 4 -1  1 2 4 -1  2 3 4 -1 
                     3 0 4 -1  0 3 2 1  ]
    # level 3 - unlit, medium gray billboarded polygon
    Billboard {
      children Shape {
        geometry IndexedFaceSet {
          coord Coordinate { point [ 1 0 0, 0 3 0, -1 0 0 ] }
          coordIndex [ 0 1 2 ]
          colorPerVertex FALSE
          color Color { color 0.5 0.5 0.5 }
    # level 4 - empty
    WorldInfo {}