Tuesday, 1 October 2013

Implementation: Applying Geometric Transformations

Changing Coordinate Systems

Last time we talked about transforms in terms of an object (polygon, line, point) in the same coordinate system of the world, that is (0,0) for the object is the same as (0,0) for the world.
An alternative (and usually preferable) way is for each object to have its own local coordinate system separate from all of the other objects and the world coordinate system. This allows each object to be created separately and then added into the world, using transformations to place the object at the appropriate point.
This is especially useful when you build larger objects out of reusable smaller objects.
For example we could have a square with 2 unit long sides and the center of the square at its origin.
The vertices of the square are: (-1,-1) ( 1,-1) ( 1, 1) (-1, 1)
This is nice because the center of the square is where we probably want the center of rotation/scaling to be. We can rotate/scale it where it is and then translate it where it belongs in the world (e.g. T(5,5) to move the center to (5,5) in world-space)
When we design the object we place the center of rotation/scaling where we wish it to be. For a wheel the center of rotation would be where the axle is to be attached, for a hinged gate the center would be at the hinge.
Each object must then be translated/rotated/scaled (from its local co-ordinate system) to place it at the proper location in the world (in the world co-ordinate system).
Say we are drawing an automobile and we want to draw the 4 tires. We can either draw each of the 4 tires independently at the appropriate location, or draw the same tire centered at its origin 4 times, and each time move it to the appropriate location in the world.

OpenGL Example: Sun and Planet

Some OpenGL code to create a solar system with a single sun and a single planet in orbit about it. We will bend the laws of physics slightly and say that the planet is orbiting about the center of the sun rather than having the objects in orbit about their shared center of mass. We also assume a circular orbit and that the plane of the solar system matches the Y=0 plane
We place the sun at 0,0,0 and it will be a sphere of radius 1
The planet has a radius of 0.2 and orbits the sun at a radius of 2
The planet rotates about its axis once per day
The planet revolves around the sun once each year

glPushMatrix(); // Copies the top matrix on the stack and pushes it.
    glLoadIdentity(); //reset the matrix to the identity matrix
    drawSphere(1.0) // user defined function to draw the sun
glRotatef(yearPercentage, 0.0, 1.0, 0.0); // Rotation about the sun
glTranslatef(2.0, 0.0, 0.0); // Translate to distance away from the sun
glRotatef(dayPercentage, 0.0, 1.0, 0.0); // Rotate about own axis.
drawSphere(0.2) // user defined function to draw the planet
glPopMatrix(); // Return stack to original condition
Note:
dayPercentage is the amount the planet rotates about ITS center.
yearPercentage is the amount the planet rotates about the center of the sun.
If you think about each object having its own coordinate system then the operations on the matrix are done in the SAME order as they are called:
    Initially the transformation matrix is the identity matrix
    The sun is drawn as a circle with radius 1 at (0,0,0)
    • The planet is rotated about its Y-axis by the percentage of year that has passed turning its coordinate system in the process
    • The planet is translated 2 units on its now rotated X-axis to its position in orbit
    • The planet is rotated about its Y-axis by the percentage of day that has passed. Since the planet is still at (0,0,0) by its coordinate system, it rotates about its center.
    • The planet is drawn as a circle with radius 0.2
If you think about the single coordinate system then the operations on the matrix are done in the REVERSE order from which they are called:
    Initially the transformation matrix is the identity matrix
    The sun is drawn as a circle with radius 1 at (0,0,0)
    • The planet is drawn as a circle with radius 0.2 at (0,0,0)
    • The planet is rotated about the Y-axis by the percentage of day that has passed. Since the planet is still at the origin this rotates the planet about its center.
    • The planet is translated 2 units on the X-axis moving its center to (2, 0, 0)
    • The planet is rotated about the Y-axis by the percentage of year that has passed. Since the planet is no longer at the origin it rotates about the origin at a radius of 2.
if the matrix operations are not performed in reverse order then the year and day rotation percentages get reversed.
Either way of thinking about it is equivalent, and irregardless of how you think about it, that is how OpenGL function calls must be issued.
Say you have three polygonal drawing functions available to you:
  • Draw a square centered at the origin with sides of length 1
  • Draw a circle centered at the origin with diameter of length 1
  • Draw a equilateral triangle with the center of its base at the origin with sides of length 1
How can I draw the following scene?


Object Hierarchies

Single polygons are generally too small to be of interest ... its hard to think of a single polygon as an 'object' unless you are writing Tetris(tm).
Even in a 2D world it is more convenient to think of objects which are a collection of polygons forming a recognizable shape: a car, a house, or a laser-toting mutant monster from Nebula-9. This object can then be moved/rotated/scaled as a single entity, at least at the conceptual level.
This is especially true in a 3D world where you need more than one (planar) polygon to create a 3D object.
Creating an object polygon by polygon is very slow when you want to create a very large complex object. On the other hand it does give you much more control over the object than creating it from higher-level primitives (cube, cone, sphere)
The following two examples are from Silicon Graphics' OpenInventor(tm) a library which sits on top of OpenGL and allows higher-level objects to be created. The first shows a tree constructed from a cube and a cone. The second shows the same tree but constructed from triangular polygons.

note, triangular polygons are often used instead of 4-sided ones because the 3 vertices in the triangle are guaranteed to form a plane, while the 4 vertices of a 4-sided polygon may not all fall in the same plane which may cause problems later on.
Hierarchies are typically stored as Directed Acyclic Graphs, that is they are trees where a node can have multiple parents as long as no cycle is generated.
Hierarchies store all information necessary to draw an object:
    polygon information
    material information
    transformation information
Hierarchies are useful when you want to be able to manipulate an object on multiple levels:
    With an arm you may want to rotate the entire arm about the shoulder, or just the lower arm about the elbow, or just the wrist or just a finger. If you rotate the entire arm then you want the rest of the arm parts to follow along as though they were joined like a real arm - if you rotate the arm then the elbow should come along for the ride.
    With a car the wheels should rotate but if the car body is moving then the wheels should also be moving the same amount.
An object hierarchy gives a high degree of encapsulation.
An object heierarchy allows inheritance
    Attributes to be set once and then used by multiple sub-objects.
    For example, at the top of the hierarchy the object could be set to draw only as a wireframe, or with different lighting models, or different colours, or different texture maps. This would then be inherited by the sub-objects and not have to be explicitely set each of them.
Hierarchies increase modularity.
Hierarchies decrease storage space
    Only store one copy of each object in the hierarchy and then using pointers to that object.
Hierarchies make it easy to propagate changes.
    For example if you decide to change the style of the 4 tires on your car model,the tire is only stored once and referenced four times so only one model needs to be updated instead of four.
Hierarchies are common in 'real life' so it can be easier to model hierarchical things in a hierarchy.
How can I redraw the house and tree scene to make better use of objects?

Fonts

Text is handled in one of two ways.
  • Using a bitmap for each character in the font
  • Using lines / polygons for each character in the font
bitmaps:
rectangular array of 0s and 1s
00000000
00011000
00100100
01000010
01111110
01000010
01000010
01000010
  • need a set of bitmaps for each size and style of font
  • 2D only
  • always aligned with the screen
  • dealt with specially, while manipulating the frame buffer
  • faster
polygons:
  • rescalable so that the definition can generate a 'smooth' character of any size
  • can be either 2D or 3D
  • can be rotated
  • treated like any other line/polygon to be displayed
  • slower
OpenGL provides minimal font support - only bitmapped fonts. Fortunately there are free 3D fonts available such as the Hershey library.

No comments:

Post a Comment