Presentation is loading. Please wait.

Presentation is loading. Please wait.

More on Drawable Objects, Hierarchical Objects Glenn G. Chappell U. of Alaska Fairbanks CS 481/681 Lecture Notes Wednesday, January.

Similar presentations


Presentation on theme: "More on Drawable Objects, Hierarchical Objects Glenn G. Chappell U. of Alaska Fairbanks CS 481/681 Lecture Notes Wednesday, January."— Presentation transcript:

1 More on Drawable Objects, Hierarchical Objects Glenn G. Chappell CHAPPELLG@member.ams.org U. of Alaska Fairbanks CS 481/681 Lecture Notes Wednesday, January 21, 2004

2 21 Jan 2004CS 481/6812 Review: Drawable Objects [1/4] Now we begin looking at how to represent a scene internally. It will be convenient to be able to deal with drawable objects independent of their characteristics. There are many ways to do this; we discuss the usual OO solution, as implemented in C++. It is reasonable to represent different kinds of drawable objects with different data types. Deriving all of these from a common base class (“ Drawable ”?) allows us to draw them without knowing what type they are.

3 21 Jan 2004CS 481/6813 Review: Drawable Objects [2/4] Here is one way to write our base class: // class Drawable // Abstract base class for drawable objects class Drawable { public: virtual ~Drawable() {} virtual void draw() const = 0; }; That’s all! The destructor is a C++ detail: a base class should have a virtual destructor. Note that Drawable is an abstract class (due to the “ = 0 ”); we cannot declare objects of type Drawable.

4 21 Jan 2004CS 481/6814 Review: Drawable Objects [3/4] To declare a drawable object type, do something like this: class Cokebottle : public Drawable { public: virtual ~Cokebottle() {} virtual void draw() const; Cokebottle():Drawable(),iscokeit(false) {} void cokeisit() { iscokeit = true; } private: bool iscokeit; // true if Coke is it. }; void Cokebottle::draw() const { Draw a cokebottle here. }

5 21 Jan 2004CS 481/6815 Review: Drawable Objects [4/4] To use objects polymorphically, refer to them via base-class pointers or references: void draw_this(const Drawable & obj) { obj.draw(); // Calls the proper virtual function. } Function draw_this can take a parameter of any type derived from Drawable. The above code would not work correctly if the object were passed by value. Now we can do this: Cokebottle c; draw_this(c);

6 21 Jan 2004CS 481/6816 More on Drawable Objects: Inheritance and Containers [1/3] Since we can deal with all drawable objects the same way, we can stick all of our objects into a container (array, vector, etc.), and iterate through that container to draw the scene. However, the following will get us into trouble. std::vector scene; Why? Hint: There are two big problems here.

7 21 Jan 2004CS 481/6817 More on Drawable Objects: Inheritance and Containers [2/3] std::vector scene; First, this will not compile. Since Drawable is an abstract class, we cannot create objects of type Drawable. But, second, even if we make Drawable a concrete class, this is a problem. A Cokebottle is probably bigger than a Drawable. So we cannot store a Cokebottle in the space meant for a Drawable. The problem resulting from trying to store an object of a derived class in a base-class variable is called slicing.

8 21 Jan 2004CS 481/6818 More on Drawable Objects: Inheritance and Containers [3/3] Solution: Use base-class pointers. Be sure that objects are delete ’d properly! std::vector scene; To add to the scene: scene.push_back(new Cokebottle); To draw the entire scene: std::vector ::const_iterator it; for (it = scene.begin(); it != scene.end(); ++it) (*it)->draw();

9 21 Jan 2004CS 481/6819 Hierarchical Objects: Overview Suppose we wish to draw a moving object with moving parts. This is called a hierarchical object. See face.cpp for an example. Two questions: How can we handle this conveniently with our graphics API? What sorts of data structures are appropriate for storing such an object? We begin with the first question.

10 21 Jan 2004CS 481/68110 Hierarchical Objects: Introduction We think of an object with moving parts as a hierarchy. At the top of the hierarchy is the object as a whole. At the next lower level in the hierarchy are the moving parts (for example, the eyes in face.cpp ). Moving parts can contain moving parts; these are at an even lower level in the hierarchy. We use stack operations to handle the transformations involved in drawing hierarchical objects.

11 21 Jan 2004CS 481/68111 Hierarchical Objects: Transformations [1/4] We want a moving object to have a moving part. We should be able to move the object as a whole. We should also be able to move the part as a part of the object. Thus, one transformation is applied to the object as a whole, but two transformations are applied to the moving part. The transformation for the moving part needs to be done before the transformation of the object as a whole (right?); therefore it comes later in the code (right?).

12 21 Jan 2004CS 481/68112 Hierarchical Objects: Transformations [2/4] Pseudocode: glPushMatrix(); Set up transformation for whole object Draw non-moving parts glPushMatrix(); Multiply current matrix by transformation for moving part Draw moving part glPopMatrix(); This is the general form of the code to draw a hierarchical object. What are the push/pop really good for? See the next slide …

13 21 Jan 2004CS 481/68113 Hierarchical Objects: Transformations [3/4] What if a hierarchical object has more than one moving part? glPushMatrix(); Set up transformation for whole object Draw non-moving parts glPushMatrix(); Multiply current matrix by transformation for moving part 1 Draw moving part 1 glPopMatrix(); glPushMatrix(); Multiply current matrix by transformation for moving part 2 Draw moving part 2 glPopMatrix(); It is convenient to make some of the pieces above into separate functions. Then follow this rule: If a function changes a matrix, then it also restores it to its prior value. This is essentially the form of our example (discussed shortly).

14 21 Jan 2004CS 481/68114 Hierarchical Objects: Transformations [4/4] What if a hierarchical object has more than two levels? glPushMatrix(); Set up transformation for whole object Draw non-moving parts glPushMatrix(); Multiply current matrix by transformation for moving part 1 Draw moving part 1 glPushMatrix(); Multiply current matrix by transformation for sub-part 1 of moving part 1 Draw sub-part 1 of moving part 1 Etc …

15 21 Jan 2004CS 481/68115 Hierarchical Objects: Example ( face.cpp ) [1/4] void display() { glClear(GL_COLOR_BUFFER_BIT); // Draw face glPushMatrix(); glTranslated(face_move, 0.0, 0.0); glRotated(face_angle, 0,0,1); glScaled(face_scale, face_scale, face_scale); draw_face(); glPopMatrix(); This is the beginning of the display routine. It sets up the transformation for the face, then calls draw_face to do the drawing.

16 21 Jan 2004CS 481/68116 Hierarchical Objects: Example ( face.cpp ) [2/4] Here is a portion of the code for function draw_face: // Draw head glColor3d(0.8, 0.6, 0.4); glCallList(disk_list); // Draw left eye (on viewer's right) glPushMatrix(); glTranslated( 0.4, 0.3, 0.0); glScaled(0.2, 0.2, 1.0); draw_eye(); glPopMatrix(); // Draw right eye (on viewer's left) glPushMatrix(); glTranslated(-0.4, 0.3, 0.0); glScaled(0.2, 0.2, 1.0); draw_eye(); glPopMatrix(); Because we handle transformations properly, we can use the same function to draw both eyes.

17 21 Jan 2004CS 481/68117 Hierarchical Objects: Example ( face.cpp ) [3/4] Each function can be written to draw its part within a square of side 2, centered at the origin (x & y go from –1 to 1). Then we set up the transformation to put the part in the proper place before we call the function that draws it. The function that does the drawing uses the transformation it is given, modifies it if necessary, but always restores it to the original value. void draw_eye() { // Draw white of eye glPushMatrix(); glScaled(1.0, 0.4, 1.0); glColor3d(1.0, 1.0, 1.0); glCallList(disk_list); glPopMatrix();

18 21 Jan 2004CS 481/68118 Hierarchical Objects: Example ( face.cpp ) [4/4] Comments Each function is written to draw the appropriate part (and all sub-parts) in some kind of “standard position”. Again, sub-part transformations come before the main transformations, which means they are later in the code, which means they can go in the function that draws the sub-part (right?). This is all very convenient and easy to use, once you wrap your mind around it. We are very clear about expectations for matrix mode, etc., when entering and leaving each function. The initial set-up is done when the reshape function is first called. After that, whenever a function finishes, we are careful to leave things the way they were when it started.


Download ppt "More on Drawable Objects, Hierarchical Objects Glenn G. Chappell U. of Alaska Fairbanks CS 481/681 Lecture Notes Wednesday, January."

Similar presentations


Ads by Google