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
- A wing of Constitution-class starships, created as a single model. Note the renderer's ability to parse circles. Also, we have not yet implemented polygon clipping. This results in a minor visual artifact - a wraparound effect when the outermost Enterprise moves off of the left edge of the viewing window. The differing sizes of the ships, however, are purely intentional: the near one has been scaled up by a factor of 25%, while the far one has been scaled down by the same amount.
- Multiple Federation starships moving in tight triangular formations. With that many ships, we've clearly entered into Deep Space 9 territory.
- The Enterprise jumping to Warp Speed: To the stationary viewer, our starship appears to be stretching as it accelerates to faster-than-light velocities, like in TNG. The graphics in the original series couldn't handle it, so they'd just kind of gloss over this part.
M. Stone and A. Pshenichkin.