Lab 5. The Hierarchical Modeling System

M. Stone and A. Pshenichkin. 11.11.04.

Note: There is much overlap between this lab and Lab 4.

Model Files

Our model files are stored using human-readable text and interpreted by a parser. Though XML seems like a very nice structure for models, the lack of a truly useful truly-C++ library for parsing it lead us to create our own simpler structure instead.

The syntax of our model files is very similar to that of our two-dimensional primitive drawer for Lab 3, though far more complex. Each of our model files includes a Definitions list and a Model. In addition to graphics primitives like Lines, Polygons, and Circles, models can contain Items, which are wrappers for primitives or other items. An Item includes a use command, usually referencing a primitive from the Definitions section, and can have a list of transformations. Primitives only take one of each Rotation, Translation, and Scale matrix, applied in the following order: Scale, Rotate, Translate.

The reason we differentiate between a model and definitions is that everything in a model file is drawn if it is the top-level model in the hierarchy, whereas definitions allow us to set up its basic components without having to hard code them into the parser or create smaller models for them.

Files are whitespace-delimited and use {} when commands span multiple lines. An example model file (our Enterprise, in this case) can be found here.

The Hierarchy

Parsing a file constructs a scene graph, which is a model hierarchy represented structurally by a tree. The leaf nodes are primitive objects; attribute modifiers make up the rest. For example, the Enterprise consists of a body, a saucer, two struts, and two nacelles. Each of those objects, with the exception of the saucer, of course, uses a unit box as its base. Several layers of transformations are then applied to resize each component to the proper relative size. The various bits are then put together using translations and turned into one big object that can be manipulated as a single unit. Our starship formations are, similarly, just three copies of the Enterprise model put together into a single scene object. Here the ability to name models really pays off: all we have to do to create each ship in the formation is specify a the name of the model to import and a transformation to align it correctly with the others.

Our scene consists of a tree of SceneNodes, which are then traversed by a Buffer Visitor. Calling visit on a SceneNode recurses down through the scene graph, collecting color and transformation information. When a leaf node (a primitive) is reached, our program concatenates all of the transform and color data (nodes have a getCombinedTransform function), essentially flattening the many Rotations, Scales, and Translations along the path down to a single transformation matrix. It then saves this information in the RenderBuffer and goes on to the next SceneNode. This procedure creates a scene from our hierarchical model tree. Perspective transformations, also known as the View Transformation Matrix, can then be applied over this. Moving one's view and transforming everything in the scene are mathemtically identical, so this operation is performed simply by putting another matrix in front of the buffered scene objects before rendering them.

Sample Images


M. Stone and A. Pshenichkin.