Lab 5: Hierarchical Modeling System
Will Moss & Andrew Cantino

This is lab 5 of Computer Graphics.

Sections:

Hierarchical Modeling System API

Our hierarchical modeling system is broken down into a set of classes in an inheritance relationship. This relationship, as depicted below, allows us to easily generate models. An instance of the model class is basically a list of modelItems, from which model itself is derived. This means that models may contain any of the classes listed below in the API, including other models. Besides models, the other three basic virtual classes are modelPrimatives, modelTransforms, and modelImages. modelPrimatives are the drawing elements, such as lines, points, and polygons. modelTransforms are the matrix operations, such as scales and translates. modelImages are pen and image operations, such as setting the pen color or applying a gradient. Please see our question and answer section for more information on how the drawing of models is handled.

Model Class Hierarchy with API

  class modelItem
     int getName()  (All modelItems must implement getName and return an ID which uniquely identifies whether
                        they are a model, modelPrimative, modelTransform, or modelImage.)

     class model
          void addItem(modelItem *i)  (Add any modelItem to this model.)
          void draw(matrix &GTM, image &im)  (Draw this model to image im, premultiplying by GTM.)

     class modelPrimative
          void draw(matrix &m, image &i)  (All modelPrimatives must implement draw.)

          class point3D
              point3D(double x, double y, double z)
              point3D(double x, double y, double z, double h)
          class line3D
              line3D(point3D start, point3D end)
          class polygon3D
              polygon3D(int numberOfPoints)
              void setFilled(bool filled)  (Should this polygon draw as filled or not?)
              void addPoint(point3D p)  (Add a point3D to the polygon.)
          class polyline3D
              polyline3D(int numberOfPoints)
              void addPoint(point3D p)  (Add a point3D to the polyline.)

     class modelTransform
          void apply(matrix &m)  (All modelTransforms must implement apply.)

          class modelTranslate3D
               modelTranslate3D(double tx, double ty, double tz)
          class modelScale3D
               modelScale3D(double s)
               modelScale3D(double sx, double sy, double sz)
               modelScale3D(point3D center, double s)
               modelScale3D(point3D center, double sx, double sy, double sz)
          class modelRotate3Dx
               modelRotate3Dx(double theta)
               modelRotate3Dx(point3D center, double theta)
          class modelRotate3Dy
               modelRotate3Dy(double theta)
               modelRotate3Dy(point3D center, double theta)
          class modelRotate3Dz
               modelRotate3Dz(double theta)
               modelRotate3Dz(point3D center, double theta)
          class modelSheer3Dx
               modelSheer3Dx(double shx, double shy)
               
          class modelSheer3Dy
               modelSheer3Dy(double shx, double shz)
               
          class modelSheer3Dz
               modelSheer3Dz(double shx, double shy)
          class modelMatrixReset
               modelMatrixReset()  (Set the LTM to identity.)

     class modelImage
          void apply(matrix &m)  (All modelImages must implement apply.)

          class modelSetPenColor
              modelSetPenColor(Pixel c)
          class modelSetGradColor
              modelSetGradColor(Pixel c1, Pixel c2)
          class modelSetPenAlpha
              modelSetPenAlpha(unsigned char a)
          class modelSetGradDirection
              modelSetGradDirection(point d1, point d2)
          class modelSetGradMode
              modelSetGradMode(int m)
          class modelClearGradient
              modelClearGradient()
          class modelSetPenPattern
              modelSetPenPattern(image &i)
          class modelSetPatternOrigin
              modelSetPatternOrigin(point p)
          class modelDisablePattern
              modelDisablePattern()
          class modelEnablePattern
              modelEnablePattern()
          class modelClearPattern
              modelClearPattern()

         Additionally, unimplemented prototypes of the following classes exist in modelImage: modelDrawImage

Images
Here are the models that we constructed. For Andrew's models, he recorded points along the outlines of two existing images (cited under the models below) and used those to generate his models. Will re-created his x-wing, except this time he just used polygons and the newly developed modeling system.

The models:


Andrew's plane.
(Outline traced from this image.)

Andrew's balloon with basket.
(Outline traced from this image.)

Will's X-Wing.

The required images:


Unidentified Flying Outlines! (Andrew)
(Please click for full-quality version.)

Balloons Go By. (Andrew)
(Please click for full-quality version.)

Patrol. (Will)
(Click for animated version.)

Barrel Roll. (Will)
(Click for animated version.)

Questions (and Answers!)

  1. Describe your model structure data type.
    Please see the description preceding our discussion of the model API.
  2. Describe the operation of your DrawStructure routine.
    Each model contains a linked list of modelItems. Additionally, our model is passed a GTM from it's parent model or the world and defines a LTM, initially set to the identity matrix. Our model draw method loops through the list of modelItems and switches on the four different model primitives based on their getName() value. If the modelItem is a model, we recursivly call the model's draw method, passing in GTM * LTM and the current image. If the modelItem is a modelPrimative, we call it's draw method which draws it onto the current image after transforming it's points by the current GTM * LTM. If the modelItem is a modelTransform, then we call it's apply method on the current LTM. If the modelItem is a modelImage, then we call it's apply method, passing it the current image.
  3. Describe how you made use of hierarchical modeling when you made your starship. Somehow show a representation of the final structure graph.
    We used hierarchical modeling to save time and space by only having to define models once. For example, we only needed to define the spaceship or plane once, then make higher-level models containing references to the original plane/ship model. Here is how our models were organized:

    Andrew's balloons and planes were organized as follows:
          plane_squad_1         plane_squad_2           balloons
            /    \   \           /   /   \             / / / \ \ \
           /      \  plane      /  plane  plane       / / /   \ \ \
         plane   plane        plane                  / / plane \ \ basket
                                                    / basket    \ plane
                                                   plane        basket
    
     Colors and transforms were applied in the parent models.
    

    Will's X-Wing is organized as follows:

    (Click for larger image.)

Extensions

Complex Scenes
We generated a complex scene with around 50 balloons rising into the sky. This was accomplished by creating a balloon model and a basket model, and then creating 50 models containing the balloon and basket models with random color, opacity, and scale variations. Then, 50 starting locations and velocity vectors were generated and the animation was created by moving the 50 balloon models according to their current position and velocity.

Animated Sequences
We created four animated sequences using our modeling system. Please click to watch the high-quality versions above!

Run Time Parameters
We implemented at system that will allow models to have run-time parameters that they can use. The system will be designed as follows. Each model, along with all the elements described above, will also have two new elements. First it will have a function pointer that will be called before every time the model is drawn. This function will take three arguments, the current model, a list of modelItems that it can modify, and a map of strings onto doubles. The list of modelItems will be passed by reference, and after the function has completed executing, the list will be rendered before the regular list. This allows the function to change the model in any manner it needs to. The map of strings onto doubles is essentially a list of parameters. The function can look at the map to determine how it will change the model (i.e. red->105 blue->200 green->0 could specify the color the model would use to draw itself). The map is also passed by reference, so the child can modify it if it wishes, sending information back up to the parent. The second new element will be a list of maps of strings onto doubles. This list represents the memory stored for each of the children models of this model. This way, a parent model that contains 5 children models can store separate memory for each model. When the parent model is rendered, the memory at the correct location in the list is passed down to the child. To demonstrate this system, we created a another fleet of x-wings. This fleet, however, is controlled completelly by the logic functions. There are three ships in the fleet, the leader and two follower ships. The leader determines its own path, and the followers try to keep up with the leader. The ships are moved based on their own memory. Each ship keeps track of it's own position as well along with its velocity and the position of its leader. There are two major logic functions that control the system. The logic function for the fleet sets up the initial memory for all the x-wings in the fleet, and then updates the follower xwings with the position of their leader. The logic function for the xwing does the bulk of the work. It updates the velocities of the x-wings (for the leader, is it randomly changed slightly, for the followers, it is based on their position relative to their leader, and points towards their desired location), and the positions (by adding the velocity to the current position). It is then in charge of rotating and draw the x-wing at the correct location.

Here is the final product:

(Click for animated version.)

[Back to Lab Index]