Title: Extra Slides on Viewing
1Extra Slides on Viewing
2Camera Viewing
Consider the scene to the left. In previous
discussions we have assumed the viewer positioned
at the origin looking down the negative z axis
scene1
In terms of the final image this would be
equivalent to the scene on the right which is a
lot easier to work with
scene2
3Viewing Transformation
- Effectively, viewing transformations involve
re-interpreting the scene so that we need only
deal with the simpler problem (viewer at origin) - The viewing transformation is applied to all
points in the scene before image is projected - Note that in terms of operations involved this is
not much different than the standard
transformations we have been using on our models
4What is the transformation required to transform
scene1 to scene2?
- Considering the viewer in the diagram a
translation by (ex, ey, ez) brings the eye to the
origin - Then (possibly) a number of rotations to swing
the viewing direction onto the z-axis (N.B. this
is not quite what is done in practice) and the up
direction onto the y-axis - If this transformation is applied to the whole
scene we have our simpler scene2
(ex, ey, ez)
Translate to origin
Align Z-axis
5OpenGL Viewing
- Apply viewing transformations, using the
MODELVIEW MATRIX, to determine positions of
vertices in Camera Coordinates - Default OpenGL camera is located at the origin
looking down the -z axis. - We then employ a projection matrix defined by
GL_PROJECTION to map this to 2D viewport
coordinates. - Finally, this 2D coordinate is mapped to device
coordinates using the viewport definition (given
by glViewport()).
6void display() glClear( GL_COLOR_BUFFER_BIT
GL_DEPTH_BUFFER_BIT ) glViewport(0, 0,
vpWidth/2, vpHeight/2) //bottom left
glPushMatrix() gluLookAt(1, 0, 0, 0, 0, 0,
0, 1, 0) //looking down x axis drawScene()
glPopMatrix() glViewport(vpWidth/2, 0,
vpWidth/2, vpHeight/2) //bottom right
glPushMatrix() gluLookAt(0, 0, 1, 0, 0, 0,
0, 1, 0) //looking down z axis drawScene()
glPopMatrix() glViewport(0, vpHeight/2,
vpWidth/2, vpHeight/2) //top left
glPushMatrix() gluLookAt(0, 1, 0, 0, 0, 0,
0, 0, 1) //down the y axis z-axis is up
drawScene() glPopMatrix()
////////next one drawn in perspective
glViewport(vpWidth/2, vpHeight/2,
vpWidth/2, vpHeight/2) //top right
glMatrixMode(GL_PROJECTION) glPushMatrix()
glLoadIdentity() gluPerspective(45, 1, 1,
10000) glMatrixMode(GL_MODELVIEW)
glPushMatrix() glTranslatef(0, 0, -5)
gluLookAt(.25, 1, 1, 0, 0, 0, 0, 1, 0)
drawScene() glPopMatrix()
glMatrixMode(GL_PROJECTION) glPopMatrix()
glPopMatrix() glFlush() glutSwapBuffers()
7 include "glut.h" //some variables int vpWidth,
vpHeight void init() glClearColor(1.0f,
1.0f, 1.0f, 1.0f) glColor3f(0, 0, 0)
glClearDepth(1) glMatrixMode(GL_PROJECTION)
glLoadIdentity() glOrtho(-2, 2, -2, 2, -2,
2) glMatrixMode(GL_MODELVIEW)
glLoadIdentity() void reshape (int w, int
h) vpWidth w vpHeight h
void drawScene() glColor3f(.5, .5, .5)
glPushMatrix() glTranslatef(0, -1, 0)
glBegin(GL_QUADS) glVertex3f(2, 0,
2) glVertex3f(2, 0, -2) glVertex3f(-2, 0,
-2) glVertex3f(-2, 0, 2) glEnd()
glPopMatrix() glColor3f(0, 0, 0)
glutWireTeapot(1)
8int main() vpWidth 800 vpHeight 800
glutInitDisplayMode(GLUT_SINGLE GLUT_RGBA
GLUT_DEPTH) glutInitWindowSize(vpWidth,
vpHeight) glutCreateWindow ("Sample
Viewports") init() glutDisplayFunc(display)
glutReshapeFunc(reshape) glutMainLoop()
return 0
9Hidden Surface Removal
10Hidden Surface Removal
- In 3d we must be concerned with whether or not
objects are obscured by other objects - Most objects are opaque so should obscure things
behind them - A.K.A. visible surface detection methods or
hidden surface elimination methods - Related problem Hidden Line Removal
11Hidden Surface Removal
? ?
12HSR Algorithms
- In OpenGL we use Backface Culling and Z-buffer
methods but they are many different approaches
varying in Efficiency w.r.t. time and storage
space - Object Precision Methods Based on Modelling
coordinates. Correct to the precision of the
machine (and the model) - Image Precision Per pixel, decide which colour
it should be drawn in. Correct to the precision
of screen window system.
13Back Face Culling
- quick test for fast elimination. It is not always
suitable and rarely sufficient but can reduce
workload considerably - we can choose to render only front facing
polygons
if -90 lt q lt 90 (or cos q gt 0) then the
polygon can be considered front facing and can be
drawn other wise it is culled
u
v
n
14Culling in OpenGL
- OpenGL uses winding to determine front and back
sides of polygons - It is important to wind in a consistent direction
when specifying polygons
glFrontFace(GL_CW) glEnable(GL_CULL_FACE)
15The Z-buffer Algorithm
- most widely used and easy to implement (hardware
or software) - image-space algorithm but loops over polygons
rather than pixels - we rasterize polygon by polygon and determine
which (parts of) polygons get drawn on the screen - Depth testing in OpenGL uses the z-buffer
algorithm
16The Z-buffer Algorithm
- initialize all depth(x,y) to 0 and refresh(x,y)
to background - for each pixel compare evaluated depth value z to
current depth(x,y) - if z gt depth(x,y)
- then
- depth(x,y)z
- refresh(x,y) Isurface(x,y)
17Depth Testing in OpenGL
- Support required for the z-buffer (you need to
enable this in GLUT) - Enable Depth testing in OpenGL
- Set a Clear Depth
- Clear Depth Buffer before displaying
- Glut Initialization
- glutInitDisplayMode(GLUT_DEPTH)
- OpenGL Initialization
- glEnable(GL_DEPTH_TEST)
- glClearDepth(1.0)
- glDepthFunc( )
- Start of display Function
- glClear(GL_DEPTH_BUFFER_BIT )
18We could cull the front faces to see inside the
solid
Without Hidden surface removal the wrong polygons
can be drawn over
OpenGL supports z-buffer and backface culling
glutInitDisplayMode(GLUT_DEPTH ..
) glEnable(GL_DEPTH_TEST) glClearDepth(1.0)
glClear (GL_DEPTH_BUFFER_BIT)
glEnable(GL_CULL_FACE) glFrontFace(GL_CW)
Or
glEnable(GL_CULL_FACE)
19No hidden surface removal
Backface Culling only correct in some places but
not adequate for objects which have holes, are
non convex or multiple objects
Culling can reduce workload for depth testing but
we need to ensure that objects are proper solids.
This teapot is not quite a proper solid and as a
result the image is incorrect. However, combining
backface culling with more expensive
depth-testing is usually a good practice.
Depth Testing Only
20 int main() glutInitDisplayMode(GLUT_SINGLE
GLUT_RGBA GLUT_DEPTH) //initialize GLUT
with a depth buffer glutInitWindowSize(vpWidth,
vpHeight) glutCreateWindow ("Sample")
init() glutDisplayFunc(display)
glutMainLoop() return 0
void init() // glClearDepth(1)
glEnable(GL_CULL_FACE) //enable backface
culling glFrontFace(GL_CW) //cull clockwise
wound polygons glEnable(GL_DEPTH_TEST)
//enable z-buffer depth testing void
display() glClear( GL_DEPTH_BUFFER_BIT
GL_COLOR_BUFFER_BIT) //clear both frame
buffer and z-buffer glutSolidTeapot(1.5)
glFlush()
21The Painters Algorithm
- sort polygons according to their z values and
render from back to front - we end up drawing over the polygons in the back
(more or less) - problems arise when polygons overlap or are
allowed to pierce one another - Heedless Painters Algorithm sort by farthest
point and draw in order - Depth sort improves on this by splitting up
overlapping polygons into less ambiguous pieces
22Depth Sort
Heedless Painter generates erroneous result
y
B
A
x
Front view
Far A
z
Far B
B
Ambigous Polygons Split Into two
A
x
Better Depth Sort Result
Top view
23Scan Line Algorithm
- Similar in some respects to the z-buffer method
but handles the image scan-line by scan-line - scanning across each line we determine the colour
of each pixel - default colour everything as background if we
encounter the edge of one polygon colour it
accordingly - for multiple edges do depth evaluation