3D computer graphics: Getting the hang of VRML

Learn about VRML and how you can use it to define your own virtual world

Until fairly recently the Internet and its vast resources were the domain of academics and government agencies. However, by the spring of 1994, that had all changed. With the combination of a universal addressing scheme for resources on the Internet (the URL or Universal Resource Locator), a structured hypertext system for documents on the Internet (the HTML or HyperText Markup Language), and a protocol that tied them together (the HTTP or HyperText Transfer Protocol), the Internet -- via the World Wide Web -- became a very accessible medium for the average person.

The combination of a URL, HTML, and HTTP made the Internet look like a vast universe of electronic pages -- flat, two-dimensional documents containing text, images, and links to other locations.

Most of us were satisfied with this new-found means of data gathering. Two dimensions, however, left a few folks feeling, well, a bit flat. While HTML was quickly gaining ground, several adventurous individuals, perhaps having digested a few too many Gibson-esque cyberpunk novels, were looking to add a third dimension to the Web.

The eventual result was the Virtual Reality Modeling Language (VRML). Based on the Open Inventor ASCII format from Silicon Graphics, VRML made it possible to describe three-dimensional scenes, complete with shapes, lights, textures, and other effects. VRML provided Web surfers with the added ability to interact with the Web via objects in the virtual world.

Java, as it turns out, it ideally suited for the task of implementing VRML. It is reasonably fast, portable, and, like VRML, tightly coupled with the Internet.

Let's begin our journey into three dimensions with a look at how a VRML document is structured.

The structure of a VRML document

The information provided in this section is based on the VRML 1.0 specification. We'll be focusing on the overall structure of a VRML document, but you can find more detailed information in the

Resources

section of this article.

Scene descriptions in VRML are made up of entities called nodes. Nodes can be shapes, properties, transformations, cameras, and lights. Nodes can also be clusters of other nodes, as we'll see a bit later.

A VRML description isn't just a haphazard collection of nodes; rather, the nodes are organized hierarchically in a structure called a scene graph. A VRML description consists of a single top-level node. That top-level node may contain other nodes, called children, as illustrated in the diagram below.

A hierarchy of nodes

In this case, the top-level node is A, and nodes B, C, and F are its children. We can rearrange the figure to indicate containment, with descending line segments between adjacent nodes. This top-down arrangement is illustrated below.

A node graph

The nodes that make up a scene graph are ordered -- a fact that has important implications during processing. Take a look at Traversing a node graph. The dotted line indicates the order in which nodes are processed, or traversed. Note that nodes E and G will be affected by the transformations indicated by nodes B and D. This order may seem odd because node D is in a different subtree than node G, but it is important to realize that nodes processed earlier affect nodes processed later no matter what subtree of the scene graph they are in. If node D defines a rotation, that rotation will be applied to all subsequent nodes, including both node E and G.

Traversing a node graph

VRML does provide a way to isolate portions of a tree or subtree from the rest of the scene graph with Separators. I'll talk more about Separators later on.

A node is defined as follows:

  
 name type {
    fields
    children
 }

Only the node type and the braces are required. The node type must be one of a set of predefined types. The VRML 1.0 standard defines such types as Sphere, Cube, Rotation, PointLight, and WWWAnchor, among others. The other items follow these guidelines:

  • Names may be used to identify nodes, but they do not have to be unique.

  • Fields override the default values of the properties of a node. Each node type defines a set of fields that can be specified explicitly. Fields have names and take values of specific types. The Cube node type, for example, has the following fields and default values:

       
    Cube {
        width 2
        height 2
        depth 2
     }
    

    Any or all of a node's fields can be included in a definition.

  • Some node types can have children. For example, the Separator node can include within its definition the definition of child nodes. Grouping nodes, like Separator, provide a convenient way to associate related nodes. The following example shows how a Separator defines a Cube node as its sole child:

       
    Separator {
       Cube {
          width 5
       }
    }
    

With this information as our foundation, we're ready to build a VRML system. Rather than taking on the gargantuan task of building a complete VRML 1.0 compliant system, we'll be tackling a much-simpler task -- building a mini-VRML system. Mini-VRML is a small subset of VRML 1.0, which supports only four nodes.

Building a mini-VRML system

The system we'll be examining in this section serves as an educational exercise and also serves to complement the machinery for drawing the scenes presented in the previous three columns. It provides a subset of the full VRML 1.0 specification. I'll leave it as an exercise for you to add the missing pieces.

As I mentioned a moment ago, mini-VRML supports only four nodes. I will provide a brief description of each node, its fields and default values, and an example of its use.

Triangle

The Triangle node type is the only shape provided. The Triangle node is not part of the VRML 1.0 specification, but fits in nicely with the code from previous columns. The Triangle has three vertices corresponding to the fields a, b, and c. The corresponding default values are the coordinates (0, 0, 0), (50, 0, 0), and (50, 0, 50). The following example illustrates its use:

   
Triangle {
   a 50 50  0
   b  0 50 50
   c 50  0 50
}

Translation

The Translation node type defines a translation to be applied to all subsequent nodes. It has only one field, translation, whose default value is the vector (50, 0, 0) -- a translation along only the X axis. The following example illustrates its use:

   
Translation {
   translation 10 0 50
}

Rotation

The Rotation node type defines a rotation to be applied to all subsequent nodes. It has only one field, rotation, whose default value is the set of values (50, 0, 0), 1.57, which performs an approximately ninety-degree rotation clockwise about the X axis. The following example illustrates its use:

   
Rotation {
   rotation 25 10 -40 -1.57
}

Separator

The Separator node type is a grouping node that isolates all of its children from the applied translations and rotations of any other portion of the VRML description. It has no fields, but may have any number of nodes as its children.

Because the Separator is an important concept, I'll illustrate its use with two nearly identical examples -- one in which it is employed, and one in which it is not. Note that the first Separator serves only to group the other nodes together. The VRML 1.0 specification states that there can be only one top-level node. With that understood, the first example shows the Separator at work:

Separator {
   Rotation {
      rotation 0 1 1 1.57
   }
   Separator {
      Translation {
         translation 20 0 0
      }
      Triangle {
         a -10 -10 0
         b  10 -10 0
         c   0  15 0
      }
   }
   Separator {
      Translation {
         translation 0 20 0
      }
      Triangle {
         a -10 -10 0
         b  10 -10 0
         c   0  15 0
      }
   }

The nodes in this example are all part of a group of nodes making up a scene or portion of a scene. The first node, a Rotation, would affect both of the additional nodes if they were not isolated from the rest of the scene graph with Separator nodes. In this case, both of the Triangles are only translated, not rotated. Compare this situation with the following example:

Separator {
   Rotation {
      rotation 0 1 1 1.57
   }
   Translation {
      translation 20 0 0
   }
   Triangle {
      a -10 -10 0
      b  10 -10 0
      c   0  15 0
   }
   Translation {
      translation 0 20 0
   }
   Triangle {
      a -10 -10 0
      b  10 -10 0
      c   0  15 0
   }

In this example, the nodes are not isolated from the rest of the scene graph. (In fact, the second Triangle is not even isolated from the effects of the first translation.) Consequently, both of the Triangles will be rotated and translated when the scene is drawn.

Parsing VRML

Because of its simple structure, VRML is easy to parse. The class

Parser

contains all of the code necessary to transform a textual description of a scene into a scene graph.

The public method parse() calls the method parseNode() in order to begin the parsing. parseNode(), in turn, examines the input stream and calls specialized parsing routines that know how to parse each of the valid node types: Triangle, Translation, Rotation, and Separator. The specialized parsing routines know how to read the textual description and create the appropriate instance of the classes TriangleShape, Translation, and Rotation, which we covered in June's column "3D computer graphics: Slide it, spin it, make it move -- transforming your virtual world." A Separator is implemented with an instance of the Vector class.

When the parse() method is finished parsing the VRML, it returns a scene graph structure composed of Vectors and the instances of the classes TriangleShape, Translation, and Rotation. The illustration below depicts schematically how the VRML shown in the first Separator example would look once it had been parsed.

An instantiated scene graph

Once the VRML has been parsed and a scene graph generated, the scene graph is handed over to an instance of the GraphedScene class, which knows how to traverse a scene graph to build a scene that a portal can draw. Once the scene has been assembled, it can be presented to any portal and drawn.

And that brings us to the big hurrah -- the applet that puts together all the hard work we've done over the past several months.

Java and VRML peacefully coexisting

Our VRML-enabled shaded beach scene applet pulls it all together. When the applet initializes itself, it loads in a mini-VRML file, parses it, traverses the scene graph, and builds the scene. It can draw the scene in any one of three flavors: wire-frame, solid, or shaded. A mini-VRML description of the beach scene is available

here

. The complete code is available in the

Resources

section at the end of this article.

You need a Java-enabled browser to see this applet.

If the applet code is run locally as a standalone application, it will present you with a file selector that allows you to select your own mini-VRML files.

Conclusion

That concludes our four-month-long journey into 3D graphics and Java. You've learned how to create a model of our world (or an imaginary world) within the confines of the computer and how to make that world come alive on your computer screen. It's not the type of thing most of you will do every day, but as virtual reality moves further and further into the mainstream, you can bet you'll run into it on down the road.

Todd Sundsted has been writing programs since computers became available in desktop models. Though originally interested in building distributed object applications in C++, Todd moved to the Java programming language when Java became the obvious choice for that sort of thing. Todd is co-author of the Java Language API SuperBible, now in bookstores everywhere. In addition to writing, Todd is president of Etcee, which offers Java-centric training, mentoring, and consulting.
1 2 Page 1
Page 1 of 2