VIEWS: 12 PAGES: 5 POSTED ON: 3/30/2010 Public Domain
COMP 557 lecture 12 Oct. 7, 2008 Coordinate system trees and object hierarchies The concept of object hierarchies has come up a few times in the course. It arose when we discussed various coordinate systems and how they are related to each other.1 For example, an object such as a person might be deﬁned by a set of parts that are deﬁned with respect to a common coordinate system. It also arose in the context of eﬃcient ray casting, where we deﬁned a hierarchy of scene objects and their parts, each of which might have its own bounding box. Take the case of a person hierarchy. Various coordinate systems might be deﬁned here, some of which are shown in the ﬁgure below on the left. Transformations between these coordinate systems are arranged into a tree, sketched on the right. The black nodes indicate coordinate systems. The (downward) edges indicate transformations between coordinate systems, namely from parent to child. To draw the person, you draw the parts. For example, consider how to draw points on the hand. They would be deﬁned in a coordinate system that is centered on the wrist. The points on the hand in the wrist coordinate system would have to be transformed to camera coordinates. This would be done by transforming from wrist coordinates to person coordinates (the torso coordinates are treated as “person coordinates”) Mtorso←wrist = Mtorso←shoulder Mshoulder←elbow Melbow←wrist = T1 R1 T2 R2 T3 R3 and then the person coordinates would have to be transformed to camera coordinates. head torso torso shoulder shoulder hips camera shoulder head hip joint elbow wrist hip joint elbow elbow world wrist wrist head hips leg leg hand hand The ﬁgure on the right is a sketch of the tree-like structure which relates the various coordinate systems. A similar tree could be used for any articulated object such as a person, tree or ﬂower, car, etc. In OpenGL, object parts are drawn by traversing the tree. Each branch from parent to child involves a change in coordinates, typically done with a glRotate and/or glTranslate operation. Object parts are drawn during the traversal. For example, upper arm is drawn within the shoulder coordinate system. Traversing from parent to child involves a change in the MODELVIEW matrix. If a node has multiple children below it that correspond to diﬀerent coordinate systems, then one saves the MODELVIEW matrix by pushing it on a stack before traversing to each of the children2 . As you have discovered 1 This was part of the class discussion in an earlier lecture, but not part of the oﬃcial lecture notes. 2 since, otherwise, the only way to return the MODELVIEW matrix to its current value would be to apply an inverse of the glRotate or glTranslate – but OpenGL doesn’t do that 1 COMP 557 lecture 12 Oct. 7, 2008 with your reading and with the code from Assignment 1, OpenGL has functions glPushMatrix() and glPopMatrix for pushing and popping the MODELVIEW matrix. If we represent the drawing with commands D, and we represent the pushing and popping with brackets [,], then we can express the sequence of OpenGL commands for drawing a person Dperson roughly as follows: Dtorso [TRDhead ] [TR Dleftleg ][TR Drightleg ][TR Dleftarm] [TR Drightarm ] Notice that the draw commands D hide all the details. These commands are function calls. The head, for example, will generally be a complex object consisting of many parts. L-systems Let’s think of OpenGL program as a string of symbols that represent commands3 , including MOD- ELVIEW transformations, pushing and popping, and drawing (e.g. glVertex). In the above example, symbols such as D were placeholders for other sequences of commands – drawing the head could involve specifying many vertices, and might involve drawing separate parts such as the ears and eyes, and may involve coordinate transforms as well. To fully specify the program, we would need to replace each D command by its speciﬁc string. This idea of replacing strings recursively will be familiar to most of you. It is reminiscent of formal grammars that are used to deﬁne programming languages. 4 . Here we not interested in characterizing and/or parsing such strings, but rather we are interested only in generating such strings. We brieﬂy consider the formalism of L-systems which are named after their inventor Astrid Lindemayer, who was interested in growth and form of biological structures, in particular, plants. The idea is that the parts of a plant (stems, leaves, ﬂowers, branches, etc) at any given time can be described using a tree structure. As the plant grows over time, some parts grow, some parts create new parts, some parts die. In its most basic form, an L-system is deﬁned by a set of symbols (alphabet) A, a special symbol a ∈ A called an axiom or starting symbol, and a set of production rules P : A → A∗ where A∗ is the set of strings over A, which may include the empty string. A production p ∈ P is written p:a→χ where χ ∈ A∗ . If no production is explicitly speciﬁed for a symbol a, then we assume the identity production p:a→a. L-systems are similar to formal grammars that you learn about in COMP 330. The diﬀerence is that with L-systems the productions are applied to each symbol in the string in parallel. With formal grammars, only one production is applied at each step (and the ordering in which productions are applied is often important for the analysis). 3 we ignore loops here 4 and those of you who have taken COMP 302 or 330 should be familiar with such grammars 2 COMP 557 lecture 12 Oct. 7, 2008 Example 1: Koch curve In lecture 10, I discussed several fractal objects, in particular, the Koch curve. These objects were deﬁned recursively, as a limit, using a production in which each line segment is replaced by a sequence of smaller line segments. At any depth d, the object – which is an approximation to the Koch curve – can be drawn using OpenGL commands, namely a sequence of translations, rotations, scalings, and glVertex commands, etc. Let L refer to the drawing of a unit line, and T a unit translation in the x direction. Let S be 1 scaling by a factor 3 . Let R+ be a rotation by 60 degrees clockwise and let R− be a rotation 60 degrees counterclockwise. The ﬁrst step of approximating a Koch curve is just to draw a line of length 1, so the string is just L. In the second step, the string L is replaced by the production, L → [SLTR+ LTR− R− LTR+ LT] In the third step, each occurence of L in the second step is replaced by the same production, etc. You can do the same thing with the Sierpinski carpet and the other fractals we discussed. Note that this recursion, as written, doesn’t terminate. Later this lecture we will see how to terminate such recursions using parametric L systems. Example 2: tree Consider the two productions: p1 : X → D[R+ X]D[R− X]R+ X p2 : D → DD where D draws a unit length straight line in the y direction and translates by a distance 1 in the y direction (so we don’t explicitly include the translate symbol), and R+ and R− are rotations by 20 degrees in the clockwise and counter-clockwise directions, respectively. As with the Koch curve, the above production deﬁne an inﬁnite recursion. If we stop the recursion after a certain number of steps, then you need to say what to do with the X symbols. For the moment, let’s just suppose that we use a production p3 : X → D. Later in the lecture we will see how it is possible to extend the deﬁnition of L-systems to allow two productions to the same left side. Shown below are four stages of the tree. (I have not included then zeroth stage, in which there is a single vertical line.) I also have shrunk the tree at stage i by a factor 2−i , in order to present the trees side by side. To undo this shrinking we need to rescale by the factor shown beneath each tree. This example was taken from the book “The Algorithmic Beauty of Plants” by Przemyslaw Prusinkiewicz and Astrid Lindemayer. The book was published in 1990 and is now out of print, but it is available online at http://algorithmicbotany.org/papers/#abop Other similar examples can be found in Chapter 1 (p. 25) of that book. 3 COMP 557 lecture 12 Oct. 7, 2008 ×2 ×4 ×8 Example 3: probabilistic L-systems Many variations of L-systems have been invented to give them more power. For example, suppose one has more than one production with the identical symbol on the left side. One can deﬁne a probability for each of these productions, such that the probabilities sum to 1. For example, suppose the ﬁrst branch of the above L-system could branch clockwise or counterclockwise with probabilitities 0.4 and 0.6, respecitively. Then we could write the productions as: p1 : X → D[R+ X] : 0.4 p2 : X → D[R− X] : 0.6 Notice that we have increased the notation to specify the probabilities. Example 4: parametric L-systems Another variation is that the symbols can have parameters associated with them. Since the symbols are basically just functions calls, these parameters would act just as function parameters. Here we will be more explicit about stopping the recursion. For example, here is an L-system that produces a vertically growing plant, such that you get a pair of unit length branches coming oﬀ the main vertical axis. These branch pairs occur every unit distance. p1 : X(n) : n > 1 → D[R+ D][R− D]X(n − 1) p2 : X(n) : n = 0 → D A slightly more interesting L-system would put a leaf L at the end of each branch, and would put a little ﬂower F at the top of the plant when the recursion terminates. p1 : X(n) : n > 1 → D[R+ DL][R− DL]X(n − 1) p2 : X(n) : n = 0 → F 4 COMP 557 lecture 12 Oct. 7, 2008 Parametric L-systems allow for delays to be built into the system. A certain production might occur only after a delay of t time steps. X(n) : n > 0 → X(n − 1) X(n) : n = 0 → .... where ..... indicates the production that you should do once the counter has decreased to zero. Context sensitive L-systems The L-systems we have seen up to now are “context free” in that each production is applied based on looking at an individual symbol only (and possibly a probability). “Context sensitive” L-systems allow for more general choice of productions. The general form is: id: lc < pred > rc : cond -----> succ : prob which means that the production id is deﬁned by replacing a predecessor symbol pred by a successor symbol succ if the symbol on the left of the predecessor is lc and the symbol on the right of the predecessor is rc and the condition cond holds. For example, w : A(1)B(3)A(5) p1 : A(x) → A(x + 1) : 0.4 p2 : A(x) → B(x − 1) : 0.6 p3 : A(x) < B(y) > A(z) : y < 4 → B(x + z)[A(y)] For example, we might have the following: A(1)B(3)A(5) → A(2)B(6)[A(3)]B(4) Open L-systems Another powerful technique is to allow the productions to depend on global variables. This allows plants to interact with each other and with the environment. For example, suppose we consider the roots of a plant growing into the ground. We could deﬁne a 2D array5 water(x,y) that represents the amount of water at each point in the soil. As the roots grow, the plant absorbs water from the soil. At each time step, a root growth production could occur if there is a suﬃcient amount of water present in the grid cell closest to the tip of the root. Moreover, as the root grows, it could decrease the amount of water in that grid cell.6 Another idea, similar to what you will explore in Assignment 2, is to allow a branches to grow only if they receive a suﬃcient amount of light from the sky. At each time step, you could cast a set of rays toward the sky and count the percentage of rays that do not intersect branches or leaves above. If the number of rays that “reach the sky” is suﬃciently large, then you could allow the growth production to occur; otherwise, not. In Assignment 2, you will do something slightly simpler which is to choose the brightness (color) of a leaf to be proportional to the percentage of cast rays that reach the sky. 5 or 3D array if we are in 3D 6 For examples, see Radomir Mech and Przemyslaw Prusinkiewicz. Visual models of plants interacting with their environment. Proceedings of SIGGRAPH 96, pp. 397-410. 5