You are on page 1of 177

OpenGL Programming Guide

About This Guide
The OpenGL graphi cs system i s a software i nterface to graphi cs hardware. (The GL stands for
Graphi cs Li brary.) I t al l ows you to create i nteracti ve programs that produce col or i mages of movi ng
three−di mensi onal objects. Wi th OpenGL, you can control computer−graphi cs technol ogy to produce
real i sti c pi ctures or ones that depart from real i ty i n i magi nati ve ways. Thi s gui de expl ai ns how to
program wi th the OpenGL graphi cs system to del i ver the vi sual effect you want.
What This Guide Contains
Thi s gui de has the i deal number of chapters: 13. The fi rst si x chapters present basi c i nformati on that
you need to understand to be abl e to draw a properl y col ored and l i t three−di mensi onal object on the
screen:
• Chapter 1, "Introduction to OpenGL,"provi des a gl i mpse i nto the ki nds of thi ngs OpenGL can
do. I t al so presents a si mpl e OpenGL program and expl ai ns essenti al programmi ng detai l s you
need to know for subsequent chapters.
• Chapter 2, "Drawing Geometric Objects,"expl ai ns how to create a three−di mensi onal
geometri c descri pti on of an object that i s eventual l y drawn on the screen.
• Chapter 3, "Viewing,"descri bes how such three−di mensi onal model s are transformed before bei ng
drawn onto a two−di mensi onal screen. You can control these transformati ons to show a parti cul ar
vi ew of a model .
• Chapter 4, "Display Lists,"di scusses how to store a seri es of OpenGL commands for executi on at
a l ater ti me. You’l l want to use thi s feature to i ncrease the performance of your OpenGL program.
• Chapter 5, "Color,"descri bes how to speci fy the col or and shadi ng method used to draw an object.
• Chapter 6, "Lighting,"expl ai ns how to control the l i ghti ng condi ti ons surroundi ng an object and
how that object responds to l i ght (that i s, how i t refl ects or absorbs l i ght). Li ghti ng i s an i mportant
topi c, si nce objects usual l y don’t l ook three−di mensi onal unti l they’re l i t.
The remai ni ng chapters expl ai n how to add sophi sti cated features to your three−di mensi onal scene.
You mi ght choose not to take advantage of many of these features unti l you’re more comfortabl e wi th
OpenGL. Parti cul arl y advanced topi cs are noted i n the text where they occur.
• Chapter 7, "Blending, Antialiasing, and Fog,"descri bes techni ques essenti al to creati ng a
real i sti c sceneal pha bl endi ng (whi ch al l ows you to create transparent objects), anti al i asi ng, and
atmospheri c effects (such as fog or smog).
• Chapter 8, "Drawing Pixels, Bitmaps, Fonts, and Images,"di scusses how to work wi th sets of
two−di mensi onal data as bi tmaps or i mages. One typi cal use for bi tmaps i s to descri be characters
i n fonts.
• Chapter 9, "Texture Mapping,"expl ai ns how to map one− and two−di mensi onal i mages cal l ed
textures onto three−di mensi onal objects. Many marvel ous effects can be achi eved through texture
mappi ng.
• Chapter 10, "The Framebuffer,"descri bes al l the possi bl e buffers that can exi st i n an OpenGL
i mpl ementati on and how you can control them. You can use the buffers for such effects as
hi dden−surface el i mi nati on, stenci l i ng, maski ng, moti on bl ur, and depth−of−fi el d focusi ng.
• Chapter 11, "Evaluators and NURBS,"gi ves an i ntroducti on to advanced techni ques for
effi ci entl y generati ng curves or surfaces.
• Chapter 12, "Selection and Feedback,"expl ai ns how you can use OpenGL’s sel ecti on
mechani sm to sel ect an object on the screen. I t al so expl ai ns the feedback mechani sm, whi ch al l ows
you to col l ect the drawi ng i nformati on OpenGL produces rather than havi ng i t be used to draw on
the screen.
1
• Chapter 13, "Now That You Know,"descri bes how to use OpenGL i n several cl ever and
unexpected ways to produce i nteresti ng resul ts. These techni ques are drawn from years of
experi ence wi th the technol ogi cal precursor to OpenGL, the Si l i con Graphi cs I RI S Graphi cs
Li brary.
I n addi ti on, there are several appendi ces that you wi l l l i kel y fi nd useful :
• Appendix A, "Order of Operations,"gi ves a techni cal overvi ew of the operati ons OpenGL
performs, bri efl y descri bi ng them i n the order i n whi ch they occur as an appl i cati on executes.
• Appendix B, "OpenGL State Variables,"l i sts the state vari abl es that OpenGL mai ntai ns and
descri bes how to obtai n thei r val ues.
• Appendix C, "The OpenGL Utility Library,"bri efl y descri bes the routi nes avai l abl e i n the
OpenGL Uti l i ty Li brary.
• Appendix D, "The OpenGL Extension to the X Window System,"bri efl y descri bes the
routi nes avai l abl e i n the OpenGL extensi on to the X Wi ndow System.
• Appendix E, "The OpenGL Programming Guide Auxiliary Library,"di scusses a smal l C code
l i brary that was wri tten for thi s book to make code exampl es shorter and more comprehensi bl e.
• Appendix F, "Calculating Normal Vectors,"tel l s you how to cal cul ate normal vectors for
di fferent types of geometri c objects.
• Appendix G, "Homogeneous Coordinates and Transformation Matrices,"expl ai ns some of
the mathemati cs behi nd matri x transformati ons.
• Appendix H, "Programming Tips,"l i sts some programmi ng ti ps based on the i ntenti ons of the
desi gners of OpenGL that you mi ght fi nd useful .
• Appendix I, "OpenGL Invariance,"descri bes the pi xel −exact i nvari ance rul es that OpenGL
i mpl ementati ons fol l ow.
• Appendix J , "Color Plates,"contai ns the col or pl ates that appear i n the pri nted versi on of thi s
gui de.
Fi nal l y, an extensi ve Glossary defi nes the key terms used i n thi s gui de.
How to Obtain the Sample Code
Thi s gui de contai ns many sampl e programs to i l l ustrate the use of parti cul ar OpenGL programmi ng
techni ques. These programs make use of a smal l auxi l i ary l i brary that was wri tten for thi s gui de. The
secti on "OpenGL−related Libraries" gi ves more i nformati on about thi s auxi l i ary l i brary. You can
obtai n the source code for both the sampl e programs and the auxi l i ary l i brary for free vi a ftp
(fi l e−transfer protocol ) i f you have access to the I nternet.
Fi rst, use ftp to go to the host sgi gate.sgi .com, and use anonymous as your user name and your_name@
machineas the password. Then type the fol l owi ng:
cd pub/opengl
binary
get opengl.tar.Z
bye
The fi l e you recei ve i s a compressed tar archi ve. To restore the fi l es, type:
uncompress opengl.tar
tar xf opengl.tar
The sampl e programs and auxi l i ary l i brary are created as subdi rectori es from wherever you are i n the
fi l e di rectory structure.
Many i mpl ementati ons of OpenGL mi ght al so i ncl ude the code sampl es and auxi l i ary l i brary as part of
the system. Thi s source code i s probabl y the best source for your i mpl ementati on, because i t mi ght have
been opti mi zed for your system. Read your machi ne−speci fi c OpenGL documentati on to see where the
code sampl es can be found.
2
What You Should Know Before Reading This Guide
Thi s gui de assumes onl y that you know how to program i n the C l anguage and that you have some
background i n mathemati cs (geometry, tri gonometry, l i near al gebra, cal cul us, and di fferenti al
geometry). Even i f you have l i ttl e or no experi ence wi th computer−graphi cs technol ogy, you shoul d be
abl e to fol l ow most of the di scussi ons i n thi s book. Of course, computer graphi cs i s a huge subject, so
you may want to enri ch your l earni ng experi ence wi th suppl emental readi ng:
• Computer Graphics: Principles and Practiceby James D. Fol ey, Andri es van Dam, Steven K.
Fei ner, and John F. Hughes (Readi ng, Mass.: Addi son−Wesl ey Publ i shi ng Co.)Thi s book i s an
encycl opedi c treatment of the subject of computer graphi cs. I t i ncl udes a weal th of i nformati on but
i s probabl y best read after you have some experi ence wi th the subject.
• 3D Computer Graphics: A User’s Guidefor Artists and Designers by Andrew S. Gl assner (New York:
Desi gn Press)Thi s book i s a nontechni cal , gentl e i ntroducti on to computer graphi cs. I t focuses on
the vi sual effects that can be achi eved rather than on the techni ques needed to achi eve them.
Once you begi n programmi ng wi th OpenGL, you mi ght want to obtai n the OpenGL ReferenceManual
by the OpenGL Archi tecture Revi ew Board (Readi ng, Mass.: Addi son−Wesl ey Publ i shi ng Co., 1993),
whi ch i s desi gned as a compani on vol ume to thi s gui de. The ReferenceManual provi des a techni cal
vi ew of how OpenGL operates on data that descri bes a geometri c object or an i mage to produce an
i mage on the screen. I t al so contai ns ful l descri pti ons of each set of rel ated OpenGL commandsthe
parameters used by the commands, the defaul t val ues for those parameters, and what the commands
accompl i sh.
"OpenGL" i s real l y a hardware−i ndependent speci fi cati on of a programmi ng i nterface. You use a
parti cul ar i mpl ementati on of i t on a parti cul ar ki nd of hardware. Thi s gui de expl ai ns how to program
wi th anyOpenGL i mpl ementati on. However, si nce i mpl ementati ons may vary sl i ghtl yi n performance
and i n provi di ng addi ti onal , opti onal features, for exampl eyou mi ght want to i nvesti gate whether
suppl ementary documentati on i s avai l abl e for the parti cul ar i mpl ementati on you’re usi ng. I n addi ti on,
you mi ght have OpenGL−rel ated uti l i ti es, tool ki ts, programmi ng and debuggi ng support, wi dgets,
sampl e programs, and demos avai l abl e to you wi th your system.
Style Conventions
These styl e conventi ons are used i n thi s gui de:
• BoldCommand and routi ne names, and matri ces
• I talicsVari abl es, arguments, parameter names, spati al di mensi ons, and matri x components
• Regul arEnumerated types and defi ned constants
Code exampl es are set off from the text i n a monospace font, and command summari es are shaded wi th
gray boxes.
Topi cs that are parti cul arl y compl i catedand that you can ski p i f you’re new to OpenGL or computer
graphi csare marked wi th the Advanced i con. Thi s i con can appl y to a si ngl e paragraph or to an enti re
secti on or chapter.
Advanced
Exerci ses that are l eft for the reader are marked wi th the Try Thi s i con.
Try This
Acknowledgments
No book comes i nto bei ng wi thout the hel p of many peopl e. Probabl y the l argest debt the authors owe i s
to the creators of OpenGL i tsel f. The OpenGL team at Si l i con Graphi cs has been l ed by Kurt Akel ey,
3
Bi l l Gl azi er, Ki pp Hi ckman, Phi l Karl ton, Mark Segal , Kevi n P. Smi th, and Wei Yen. The members of
the OpenGL Archi tecture Revi ew Board natural l y need to be counted among the desi gners of OpenGL:
Di ck Coul ter and John Denni s of Di gi tal Equi pment Corporati on; Ji m Bushnel l and Li nas Vepstas of
I nternati onal Busi ness Machi nes, Corp.; Mural i Sundaresan and Ri ck Hodgson of I ntel ; and On Lee
and Chuck Whi tmore of Mi crosoft. Other earl y contri butors to the desi gn of OpenGL i ncl ude Raymond
Drewry of Gai n Technol ogy, I nc., Fred Fi sher of Di gi tal Equi pment Corporati on, and Randi Rost of
Kubota Paci fi c Computer, I nc. Many other Si l i con Graphi cs empl oyees hel ped refi ne the defi ni ti on and
functi onal i ty of OpenGL, i ncl udi ng Momi Akel ey, Al l en Aki n, Chri s Frazi er, Paul Ho, Si mon Hui ,
Lesl ey Kal mi n, Pi erre Tardi ff, and Ji m Wi nget.
Many brave soul s vol unteered to revi ew thi s book: Kurt Akel ey, Gavi n Bel l , Sam Chen, Andrew
Cherenson, Dan Fi nk, Beth Fryer, Gretchen Hel ms, Davi d Marsl and, Jeanne Ri ch, Mark Segal , Kevi n
P. Smi th, and Josi e Wernecke from Si l i con Graphi cs; Davi d Ni gui dul a, Coal i ti on of Essenti al School s,
Brown Uni versi ty; John Denni s and Andy Vesper, Di gi tal Equi pment Corporati on; Chandrasekhar
Narayanaswami and Li nas Vepstas, I nternati onal Busi ness Machi nes, Corp.; Randi Rost, Kubota
Paci fi c; On Lee, Mi crosoft Corp.; Dan Sears; Henry McGi l ton, Tri l i thon Software; and Paul a Womak.
Assembl i ng the set of col orpl ates was no mean feat. The sequence of pl ates based on the cover i mage (
Figure J −1 through Figure J −9) was created by Thad Bei er of Paci fi c Data I mages, Seth Katz of
Xaos Tool s, I nc., and Mason Woo of Si l i con Graphi cs. Figure J −10 through Figure J −32 are
snapshots of programs created by Mason. Gavi n Bel l , Kevi n Gol dsmi th, Li nda Roy, and Mark Dal y (al l
of Si l i con Graphi cs) created the fl y−through program used for Figure J −34. The model for Figure
J −35 was created by Barry Broui l l ette of Si l i con Graphi cs; Doug Voorhi es, al so of Si l i con Graphi cs,
performed some i mage processi ng for the fi nal i mage. Figure J −36 was created by John Rohl f and
Mi chael Jones, both of Si l i con Graphi cs. Figure J −37 was created by Carl Korobki n of Si l i con
Graphi cs. Figure J −38 i s a snapshot from a program wri tten by Gavi n Bel l wi th contri buti ons from
the I nventor team at Si l i con Graphi csAl ai n Dumesny, Dave I mmel , Davi d Mott, Howard Look, Paul
I saacs, Paul Strauss, and Ri kk Carey. Figure J −39 and Figure J −40 are snapshots from a vi sual
si mul ati on program created by the Si l i con Graphi cs I RI S Performer teamCrai g Phi l l i ps, John Rohl f,
Sharon Fi schl er, Ji m Hel man, and Mi chael Jonesfrom a database produced for Si l i con Graphi cs by
Paradi gm Si mul ati on, I nc. Figure J −41 i s a snapshot from skyfl y, the precursor to Performer, whi ch
was created by John Rohl f, Sharon Fi schl er, and Ben Garl i ck, al l of Si l i con Graphi cs.
Several other peopl e pl ayed speci al rol es i n creati ng thi s book. I f we were to l i st other names as authors
on the front of thi s book, Kurt Akel ey and Mark Segal woul d be there, as honorary yeoman. They
hel ped defi ne the structure and goal s of the book, provi ded key secti ons of materi al for i t, revi ewed i t
when everybody el se was too ti red of i t to do so, and suppl i ed that al l −i mportant humor and support
throughout the process. Kay Mai tz provi ded i nval uabl e producti on and desi gn assi stance. Kathy
Gochenour very generousl y created many of the i l l ustrati ons for thi s book. Tanya Kucak copyedi ted the
manuscri pt, i n her usual thorough and professi onal styl e.
And now, each of the authors woul d l i ke to take the 15 mi nutes that have been al l otted to them by
Andy Warhol to say thank you.
I ’d l i ke to thank my managers at Si l i con Graphi csDave Larson and Way Ti ngand the members of
my groupPatri ci a Creek, Arthur Evans, Beth Fryer, Jed Hartman, Ken Jones, Robert Rei mann, Eve
Stratton (aka Margaret−Anne Hal se), John Stearns, and Josi e Werneckefor thei r support duri ng thi s
l engthy process. Last but surel y not l east, I want to thank those whose contri buti ons toward thi s
project are too deep and mysteri ous to el uci date: Yvonne Leach, Kathl een Lancaster, Carol i ne Rose,
Ci ndy Kl ei nfel d, and my parents, Fl orence and Ferdi nand Nei der.
JLN
I n addi ti on to my parents, Edward and I rene Davi s, I ’d l i ke to thank the peopl e who taught me most of
what I know about computers and computer graphi csDoug Engel bart and Ji m Cl ark.
TRD
I ’d l i ke to thank the many past and current members of Si l i con Graphi cs whose accommodati on and
4
enl i ghtenment were essenti al to my contri buti on to thi s book: Geral d Anderson, Wendy Chi n, Bert
Fornaci ari , Bi l l Gl azi er, Ji l l Huchi tal , Howard Look, Bi l l Mannel , Davi d Marsl and, Dave Orton, Li nda
Roy, Kei th Seto, and Dave Shrei ner. Very speci al thanks to Karri n Ni col and Lei l ani Gayl es of SGI for
thei r gui dance throughout my career. I al so bestow much grati tude to my teammates on the Stanford B
i ce hockey team for peri ods of gl ori ous di stracti on throughout the wri ti ng of thi s book. Fi nal l y, I ’d l i ke
to thank my fami l y, especi al l y my mother, Bo, and my l ate father, Henry.
MW
Chapter 1
Introduction to OpenGL
Chapter Objectives
After readi ng thi s chapter, you’l l be abl e to do the fol l owi ng:
• Appreci ate i n general terms what OpenGL offers
• I denti fy di fferent l evel s of renderi ng compl exi ty
• Understand the basi c structure of an OpenGL program
• Recogni ze OpenGL command syntax
• Understand i n general terms how to ani mate an OpenGL program
Thi s chapter i ntroduces OpenGL. I t has the fol l owi ng major secti ons:
• "What Is OpenGL?"expl ai ns what OpenGL i s, what i t does and doesn’t do, and how i t works.
• "A Very Simple OpenGL Program"presents a smal l OpenGL program and bri efl y di scusses i t.
Thi s secti on al so defi nes a few basi c computer−graphi cs terms.
• "OpenGL Command Syntax"expl ai ns some of the conventi ons and notati ons used by OpenGL
commands.
• "OpenGL as a State Machine"descri bes the use of state vari abl es i n OpenGL and the commands
for queryi ng, enabl i ng, and di sabl i ng states.
• "OpenGL−related Libraries"descri bes sets of OpenGL−rel ated routi nes, i ncl udi ng an auxi l i ary
l i brary speci fi cal l y wri tten for thi s book to si mpl i fy programmi ng exampl es.
• "Animation"expl ai ns i n general terms how to create pi ctures on the screen that move, or ani mate.
What Is OpenGL?
OpenGL i s a software i nterface to graphi cs hardware. Thi s i nterface consi sts of about 120 di sti nct
commands, whi ch you use to speci fy the objects and operati ons needed to produce i nteracti ve
three−di mensi onal appl i cati ons.
OpenGL i s desi gned to work effi ci entl y even i f the computer that di spl ays the graphi cs you create i sn’t
the computer that runs your graphi cs program. Thi s mi ght be the case i f you work i n a networked
computer envi ronment where many computers are connected to one another by wi res capabl e of
carryi ng di gi tal data. I n thi s si tuati on, the computer on whi ch your program runs and i ssues OpenGL
drawi ng commands i s cal l ed the cl i ent, and the computer that recei ves those commands and performs
the drawi ng i s cal l ed the server. The format for transmi tti ng OpenGL commands (cal l ed the protocol)
from the cl i ent to the server i s al ways the same, so OpenGL programs can work across a network even
i f the cl i ent and server are di fferent ki nds of computers. I f an OpenGL program i sn’t runni ng across a
network, then there’s onl y one computer, and i t i s both the cl i ent and the server.
OpenGL i s desi gned as a streaml i ned, hardware−i ndependent i nterface to be i mpl emented on many
di fferent hardware pl atforms. To achi eve these qual i ti es, no commands for performi ng wi ndowi ng tasks
or obtai ni ng user i nput are i ncl uded i n OpenGL; i nstead, you must work through whatever wi ndowi ng
system control s the parti cul ar hardware you’re usi ng. Si mi l arl y, OpenGL doesn’t provi de hi gh−l evel
commands for descri bi ng model s of three−di mensi onal objects. Such commands mi ght al l ow you to
speci fy rel ati vel y compl i cated shapes such as automobi l es, parts of the body, ai rpl anes, or mol ecul es.
5
Wi th OpenGL, you must bui l d up your desi red model from a smal l set of geometri c pri mi ti vepoi nts,
l i nes, and pol ygons. (A sophi sti cated l i brary that provi des these features coul d certai nl y be bui l t on top
of OpenGLi n fact, that’s what Open I nventor i s. See "OpenGL−related Libraries" for more
i nformati on about Open I nventor.)
Now that you know what OpenGL doesn’t do, here’s what i t doesdo. Take a l ook at the col or pl ates
they i l l ustrate typi cal uses of OpenGL. They show the scene on the cover of thi s book, drawn by a
computer (whi ch i s to say, rendered) i n successi vel y more compl i cated ways. The fol l owi ng paragraphs
descri be i n general terms how these pi ctures were made.
• Figure J −1shows the enti re scene di spl ayed as a wi reframe modelthat i s, as i f al l the objects i n
the scene were made of wi re. Each l i ne of wi re corresponds to an edge of a pri mi ti ve (typi cal l y a
pol ygon). For exampl e, the surface of the tabl e i s constructed from tri angul ar pol ygons that are
posi ti oned l i ke sl i ces of pi e.
Note that you can see porti ons of objects that woul d be obscured i f the objects were sol i d rather
than wi reframe. For exampl e, you can see the enti re model of the hi l l s outsi de the wi ndow even
though most of thi s model i s normal l y hi dden by the wal l of the room. The gl obe appears to be
nearl y sol i d because i t’s composed of hundreds of col ored bl ocks, and you see the wi reframe l i nes for
al l the edges of al l the bl ocks, even those formi ng the back si de of the gl obe. The way the gl obe i s
constructed gi ves you an i dea of how compl ex objects can be created by assembl i ng l ower−l evel
objects.
• Figure J −2shows a depth−cued versi on of the same wi reframe scene. Note that the l i nes farther
from the eye are di mmer, just as they woul d be i n real l i fe, thereby gi vi ng a vi sual cue of depth.
• Figure J −3shows an antialiased versi on of the wi reframe scene. Anti al i asi ng i s a techni que for
reduci ng the jagged effect created when onl y porti ons of nei ghbori ng pi xel s properl y bel ong to the
i mage bei ng drawn. Such jaggi es are usual l y the most vi si bl e wi th near−hori zontal or near−verti cal
l i nes.
• Figure J −4shows a flat−shaded versi on of the scene. The objects i n the scene are now shown as
sol i d objects of a si ngl e col or. They appear "fl at" i n the sense that they don’t seem to respond to the
l i ghti ng condi ti ons i n the room, so they don’t appear smoothl y rounded.
• Figure J −5shows a lit, smooth−shaded versi on of the scene. Note how the scene l ooks much more
real i sti c and three−di mensi onal when the objects are shaded to respond to the l i ght sources i n the
room; the surfaces of the objects now l ook smoothl y rounded.
• Figure J −6adds shadows and textures to the previ ous versi on of the scene. Shadows aren’t an
expl i ci tl y defi ned feature of OpenGL (there i s no "shadow command"), but you can create them
yoursel f usi ng the techni ques descri bed i n Chapter 13. Texture mappi ng al l ows you to appl y a
two−di mensi onal texture to a three−di mensi onal object. I n thi s scene, the top on the tabl e surface i s
the most vi brant exampl e of texture mappi ng. The wal l s, fl oor, tabl e surface, and top (on top of the
tabl e) are al l texture mapped.
• Figure J −7shows a motion−blurred object i n the scene. The sphi nx (or dog, dependi ng on your
Rorschach tendenci es) appears to be captured as i t’s movi ng forward, l eavi ng a bl urred trace of i ts
path of moti on.
• Figure J −8shows the scene as i t’s drawn for the cover of the book from a di fferent vi ewpoi nt. Thi s
pl ate i l l ustrates that the i mage real l y i s a snapshot of model s of three−di mensi onal objects.
The next two col or i mages i l l ustrate yet more compl i cated vi sual effects that can be achi eved wi th
OpenGL:
• Figure J −9i l l ustrates the use of atmospheri c effects (col l ecti vel y referred to as fog) to show the
presence of parti cl es i n the ai r.
• Figure J −10shows the depth−of−field effect, whi ch si mul ates the i nabi l i ty of a camera l ens to
mai ntai n al l objects i n a photographed scene i n focus. The camera focuses on a parti cul ar spot i n
the scene, and objects that are si gni fi cantl y cl oser or farther than that spot are somewhat bl urred.
The col or pl ates gi ve you an i dea of the ki nds of thi ngs you can do wi th the OpenGL graphi cs system.
The next several paragraphs bri efl y descri be the order i n whi ch OpenGL performs the major graphi cs
operati ons necessary to render an i mage on the screen. Appendix A, "Order of Operations"
descri bes thi s order of operati ons i n more detai l .
6
1. Construct shapes from geometri c pri mi ti ves, thereby creati ng mathemati cal descri pti ons of objects.
(OpenGL consi ders poi nts, l i nes, pol ygons, i mages, and bi tmaps to be pri mi ti ves.)
2. Arrange the objects i n three−di mensi onal space and sel ect the desi red vantage poi nt for vi ewi ng the
composed scene.
3. Cal cul ate the col or of al l the objects. The col or mi ght be expl i ci tl y assi gned by the appl i cati on,
determi ned from speci fi ed l i ghti ng condi ti ons, or obtai ned by pasti ng a texture onto the objects.
4. Convert the mathemati cal descri pti on of objects and thei r associ ated col or i nformati on to pi xel s on
the screen. Thi s process i s cal l ed rasterization.
Duri ng these stages, OpenGL mi ght perform other operati ons, such as el i mi nati ng parts of objects that
are hi dden by other objects (the hi dden parts won’t be drawn, whi ch mi ght i ncrease performance). I n
addi ti on, after the scene i s rasteri zed but just before i t’s drawn on the screen, you can mani pul ate the
pi xel data i f you want.
A Very Simple OpenGL Program
Because you can do so many thi ngs wi th the OpenGL graphi cs system, an OpenGL program can be
compl i cated. However, the basi c structure of a useful program can be si mpl e: I ts tasks are to i ni ti al i ze
certai n states that control how OpenGL renders and to speci fy objects to be rendered.
Before you l ook at an OpenGL program, l et’s go over a few terms. Renderi ng, whi ch you’ve al ready seen
used, i s the process by whi ch a computer creates i mages from model s. These models, or objects, are
constructed from geometri c pri mi ti vespoi nts, l i nes, and pol ygonsthat are speci fi ed by thei r verti ces.
The fi nal rendered i mage consi sts of pi xel s drawn on the screen; a pi xelshort for pi cture el ementi s
the smal l est vi si bl e el ement the di spl ay hardware can put on the screen. I nformati on about the pi xel s
(for i nstance, what col or they’re supposed to be) i s organi zed i n system memory i nto bi tpl anes. A
bi tpl ane i s an area of memory that hol ds one bi t of i nformati on for every pi xel on the screen; the bi t
mi ght i ndi cate how red a parti cul ar pi xel i s supposed to be, for exampl e. The bi tpl anes are themsel ves
organi zed i nto a framebuffer, whi ch hol ds al l the i nformati on that the graphi cs di spl ay needs to control
the i ntensi ty of al l the pi xel s on the screen.
Now l ook at an OpenGL program. Example 1−1 renders a whi te rectangl e on a bl ack background, as
shown i n Figure 1−1 .
7
Figure 1−1 A Whi te Rectangl e on a Bl ack Background
Example 1−1 A Si mpl e OpenGL Program
#include <whateverYouNeed.h>
main() {
OpenAWindowPlease();
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
glOrtho(−1.0, 1.0, −1.0, 1.0, −1.0, 1.0);
glBegin(GL_POLYGON);
glVertex2f(−0.5, −0.5);
glVertex2f(−0.5, 0.5);
glVertex2f(0.5, 0.5);
glVertex2f(0.5, −0.5);
glEnd();
glFlush();
KeepTheWindowOnTheScreenForAWhile();
}
The fi rst l i ne of the main() routi ne opens a wi ndow on the screen: The OpenAWindowPlease() routi ne i s
meant as a pl acehol der for a wi ndow system−speci fi c routi ne. The next two l i nes are OpenGL
commands that cl ear the wi ndow to bl ack: glClearColor() establ i shes what col or the wi ndow wi l l be
cl eared to, and glClear() actual l y cl ears the wi ndow. Once the col or to cl ear to i s set, the wi ndow i s
8
cl eared to, and glClear() actual l y cl ears the wi ndow. Once the col or to cl ear to i s set, the wi ndow i s
cl eared to that col or whenever glClear() i s cal l ed. The cl eari ng col or can be changed wi th another cal l to
glClearColor(). Si mi l arl y, the glColor3f() command establ i shes what col or to use for drawi ng objects
i n thi s case, the col or i s whi te. Al l objects drawn after thi s poi nt use thi s col or, unti l i t’s changed wi th
another cal l to set the col or.
The next OpenGL command used i n the program, glOrtho(), speci fi es the coordi nate system OpenGL
assumes as i t draws the fi nal i mage and how the i mage gets mapped to the screen. The next cal l s,
whi ch are bracketed by glBegin() and glEnd(), defi ne the object to be drawni n thi s exampl e, a pol ygon
wi th four verti ces. The pol ygon’s "corners" are defi ned by the glVertex2f() commands. As you mi ght be
abl e to guess from the arguments, whi ch are (x, y) coordi nate pai rs, the pol ygon i s a rectangl e.
Fi nal l y, glFlush() ensures that the drawi ng commands are actual l y executed, rather than stored i n a
buffer awai ti ng addi ti onal OpenGL commands. The KeepTheWindowOnTheScreenForAWhile()
pl acehol der routi ne forces the pi cture to remai n on the screen i nstead of i mmedi atel y di sappeari ng.
OpenGL Command Syntax
As you mi ght have observed from the si mpl e program i n the previ ous secti on, OpenGL commands use
the prefi x gl and i ni ti al capi tal l etters for each word maki ng up the command name (recal l
glClearColor(), for exampl e). Si mi l arl y, OpenGL defi ned constants begi n wi th GL_, use al l capi tal
l etters, and use underscores to separate words (l i ke GL_COLOR_BUFFER_BI T).
You mi ght al so have noti ced some seemi ngl y extraneous l etters appended to some command names
(the 3f i n glColor3f(), for exampl e). I t’s true that the Color part of the command name i s enough to
defi ne the command as one that sets the current col or. However, more than one such command has
been defi ned so that you can use di fferent types of arguments. I n parti cul ar, the 3 part of the suffi x
i ndi cates that three arguments are gi ven; another versi on of the Color command takes four arguments.
The f part of the suffi x i ndi cates that the arguments are fl oati ng−poi nt numbers. Some OpenGL
commands accept as many as ei ght di fferent data types for thei r arguments. The l etters used as
suffi xes to speci fy these data types for ANSI C i mpl ementati ons of OpenGL are shown i n Table 1−1 ,
al ong wi th the correspondi ng OpenGL type defi ni ti ons. The parti cul ar i mpl ementati on of OpenGL that
you’re usi ng mi ght not fol l ow thi s scheme exactl y; an i mpl ementati on i n C++ or Ada, for exampl e,
woul dn’t need to.
SuffixData Type Typical Corresponding
C−Language Type
OpenGL Type Definition
b 8−bit integer signed char GLbyte
s 16−bit integer short GLshort
i 32−bit integer long GLint, GLsizei
f 32−bit floating−point float GLfloat, GLclampf
d 64−bit floating−point double GLdouble, GLclampd
ub 8−bit unsigned integer unsigned char GLubyte, GLboolean
us 16−bit unsigned integer unsigned short GLushort
ui 32−bit unsigned integer unsigned long GLuint, GLenum, GLbitfield
Table 1−1 Command Suffi xes and Argument Data Types
Thus, the two commands
glVertex2i(1, 3);
glVertex2f(1.0, 3.0);
are equi val ent, except that the fi rst speci fi es the vertex’s coordi nates as 32−bi t i ntegers and the second
speci fi es them as si ngl e−preci si on fl oati ng−poi nt numbers.
Some OpenGL commands can take a fi nal l etter v, whi ch i ndi cates that the command takes a poi nter to
a vector (or array) of val ues rather than a seri es of i ndi vi dual arguments. Many commands have both
vector and nonvector versi ons, but some commands accept onl y i ndi vi dual arguments and others
9
vector and nonvector versi ons, but some commands accept onl y i ndi vi dual arguments and others
requi re that at l east some of the arguments be speci fi ed as a vector. The fol l owi ng l i nes show how you
mi ght use a vector and a nonvector versi on of the command that sets the current col or:
glColor3f(1.0, 0.0, 0.0);
float color_array[] = {1.0, 0.0, 0.0};
glColor3fv(color_array);
I n the rest of thi s gui de (except i n actual code exampl es), OpenGL commands are referred to by thei r
base names onl y, and an asteri sk i s i ncl uded to i ndi cate that there may be more to the command name.
For exampl e, glColor*() stands for al l vari ati ons of the command you use to set the current col or. I f we
want to make a speci fi c poi nt about one versi on of a parti cul ar command, we i ncl ude the suffi x
necessary to defi ne that versi on. For exampl e, glVertex*v() refers to al l the vector versi ons of the
command you use to speci fy verti ces.
Fi nal l y, OpenGL defi nes the constant GLvoi d; i f you’re programmi ng i n C, you can use thi s i nstead of
voi d.
OpenGL as a State Machine
OpenGL i s a state machi ne. You put i t i nto vari ous states (or modes) that then remai n i n effect unti l
you change them. As you’ve al ready seen, the current col or i s a state vari abl e. You can set the current
col or to whi te, red, or any other col or, and thereafter every object i s drawn wi th that col or unti l you set
the current col or to somethi ng el se. The current col or i s onl y one of many state vari abl es that OpenGL
preserves. Others control such thi ngs as the current vi ewi ng and projecti on transformati ons, l i ne and
pol ygon sti ppl e patterns, pol ygon drawi ng modes, pi xel −packi ng conventi ons, posi ti ons and
characteri sti cs of l i ghts, and materi al properti es of the objects bei ng drawn. Many state vari abl es refer
to modes that are enabl ed or di sabl ed wi th the command glEnable() or glDisable().
Each state vari abl e or mode has a defaul t val ue, and at any poi nt you can query the system for each
vari abl e’s current val ue. Typi cal l y, you use one of the four fol l owi ng commands to do thi s:
glGetBooleanv(), glGetDoublev(), glGetFloatv(), or glGetI ntegerv(). Whi ch of these commands you sel ect
depends on what data type you want the answer to be gi ven i n. Some state vari abl es have a more
speci fi c query command (such as glGetLight*(), glGetError(), or glGetPolygonStipple()). I n addi ti on, you
can save and l ater restore the val ues of a col l ecti on of state vari abl es on an attri bute stack wi th the
glPushAttrib() and glPopAttrib() commands. Whenever possi bl e, you shoul d use these commands rather
than any of the query commands, si nce they’re l i kel y to be more effi ci ent.
The compl ete l i st of state vari abl es you can query i s found i n Appendix B . For each vari abl e, the
appendi x al so l i sts the glGet*() command that returns the vari abl e’s val ue, the attri bute cl ass to whi ch
i t bel ongs, and the vari abl e’s defaul t val ue.
OpenGL−related Libraries
OpenGL provi des a powerful but pri mi ti ve set of renderi ng commands, and al l hi gher−l evel drawi ng
must be done i n terms of these commands. Therefore, you mi ght want to wri te your own l i brary on top
of OpenGL to si mpl i fy your programmi ng tasks. Al so, you mi ght want to wri te some routi nes that al l ow
an OpenGL program to work easi l y wi th your wi ndowi ng system. I n fact, several such l i brari es and
routi nes have al ready been wri tten to provi de speci al i zed features, as fol l ows. Note that the fi rst two
l i brari es are provi ded wi th every OpenGL i mpl ementati on, the thi rd was wri tten for thi s book and i s
avai l abl e usi ng ftp, and the fourth i s a separate product that’s based on OpenGL.
• The OpenGL Uti l i ty Li brary (GLU) contai ns several routi nes that use l ower−l evel OpenGL
commands to perform such tasks as setti ng up matri ces for speci fi c vi ewi ng ori entati ons and
projecti ons, performi ng pol ygon tessel l ati on, and renderi ng surfaces. Thi s l i brary i s provi ded as
10
part of your OpenGL i mpl ementati on. I t’s descri bed i n more detai l i n Appendix C and i n the
OpenGL ReferenceManual. The more useful GLU routi nes are descri bed i n the chapters i n thi s
gui de, where they’re rel evant to the topi c bei ng di scussed. GLU routi nes use the prefi x glu.
• The OpenGL Extensi on to the X Wi ndow System (GLX) provi des a means of creati ng an OpenGL
context and associ ati ng i t wi th a drawabl e wi ndow on a machi ne that uses the X Wi ndow System.
GLX i s provi ded as an adjunct to OpenGL. I t’s descri bed i n more detai l i n both Appendix D and
the OpenGL ReferenceManual. One of the GLX routi nes (for swappi ng framebuffers) i s descri bed i n
"Animation." GLX routi nes use the prefi x glX.
• The OpenGL Programming GuideAuxi l i ary Li brary was wri tten speci fi cal l y for thi s book to make
programmi ng exampl es si mpl er and yet more compl ete. I t’s the subject of the next secti on, and i t’s
descri bed i n more detai l i n Appendix E . Auxi l i ary l i brary routi nes use the prefi x aux. "How to
Obtain the Sample Code" descri bes how to obtai n the source code for the auxi l i ary l i brary.
• Open I nventor i s an object−ori ented tool ki t based on OpenGL that provi des objects and methods for
creati ng i nteracti ve three−di mensi onal graphi cs appl i cati ons. Avai l abl e from Si l i con Graphi cs and
wri tten i n C++, Open I nventor provi des pre−bui l t objects and a bui l t−i n event model for user
i nteracti on, hi gh−l evel appl i cati on components for creati ng and edi ti ng three−di mensi onal scenes,
and the abi l i ty to pri nt objects and exchange data i n other graphi cs formats.
The OpenGL Programming Guide Auxiliary Library
As you know, OpenGL contai ns renderi ng commands but i s desi gned to be i ndependent of any wi ndow
system or operati ng system. Consequentl y, i t contai ns no commands for openi ng wi ndows or readi ng
events from the keyboard or mouse. Unfortunatel y, i t’s i mpossi bl e to wri te a compl ete graphi cs
program wi thout at l east openi ng a wi ndow, and most i nteresti ng programs requi re a bi t of user i nput
or other servi ces from the operati ng system or wi ndow system. I n many cases, compl ete programs
make the most i nteresti ng exampl es, so thi s book uses a smal l auxi l i ary l i brary to si mpl i fy openi ng
wi ndows, detecti ng i nput, and so on.
I n addi ti on, si nce OpenGL’s drawi ng commands are l i mi ted to those that generate si mpl e geometri c
pri mi ti ves (poi nts, l i nes, and pol ygons), the auxi l i ary l i brary i ncl udes several routi nes that create more
compl i cated three−di mensi onal objects such as a sphere, a torus, and a teapot. Thi s way, snapshots of
program output can be i nteresti ng to l ook at. I f you have an i mpl ementati on of OpenGL and thi s
auxi l i ary l i brary on your system, the exampl es i n thi s book shoul d run wi thout change when l i nked
wi th them.
The auxi l i ary l i brary i s i ntenti onal l y si mpl e, and i t woul d be di ffi cul t to bui l d a l arge appl i cati on on top
of i t. I t’s i ntended sol el y to support the exampl es i n thi s book, but you may fi nd i t a useful starti ng
poi nt to begi n bui l di ng real appl i cati ons. The rest of thi s secti on bri efl y descri bes the auxi l i ary l i brary
routi nes so that you can fol l ow the programmi ng exampl es i n the rest of thi s book. Turn to Appendix
E for more detai l s about these routi nes.
Window Management
Three routi nes perform tasks necessary to i ni ti al i ze and open a wi ndow:
• auxI nitWindow() opens a wi ndow on the screen. I t enabl es the Escape key to be used to exi t the
program, and i t sets the background col or for the wi ndow to bl ack.
• auxI nitPosition() tel l s auxI nitWindow() where to posi ti on a wi ndow on the screen.
• auxI nitDisplayMode() tel l s auxI nitWindow() whether to create an RGBA or col or−i ndex wi ndow.
You can al so speci fy a si ngl e− or doubl e−buffered wi ndow. (I f you’re worki ng i n col or−i ndex mode,
you’l l want to l oad certai n col ors i nto the col or map; use auxSetOneColor() to do thi s.) Fi nal l y, you
can use thi s routi ne to i ndi cate that you want the wi ndow to have an associ ated depth, stenci l ,
and/or accumul ati on buffer.
Handling Input Events
You can use these routi nes to regi ster cal l back commands that are i nvoked when speci fi ed events occur.
11
• auxReshapeFunc() i ndi cates what acti on shoul d be taken when the wi ndow i s resi zed, moved, or
exposed.
• auxKeyFunc() and auxMouseFunc() al l ow you to l i nk a keyboard key or a mouse button wi th a
routi ne that’s i nvoked when the key or mouse button i s pressed or rel eased.
Drawing 3−D Objects
The auxi l i ary l i brary i ncl udes several routi nes for drawi ng these three−di mensi onal objects:
sphere octahedron
cube dodecahedron
torus i cosahedron
cyl i nder teapot
cone
You can draw these objects as wi reframes or as sol i d shaded objects wi th surface normal s defi ned. For
exampl e, the routi nes for a sphere and a torus are as fol l ows:
voi d auxWireSphere(GLdoubl e radius);
voi d auxSolidSphere(GLdoubl e radius);
voi d auxWireTorus(GLdoubl e innerRadius, GLdoubl e outerRadius);
voi d auxSolidTorus(GLdoubl e innerRadius, GLdoubl e outerRadius);
Al l these model s are drawn centered at the ori gi n. When drawn wi th uni t scal e factors, these model s fi t
i nto a box wi th al l coordi nates from −1 to 1. Use the arguments for these routi nes to scal e the objects.
Managing a Background Process
You can speci fy a functi on that’s to be executed i f no other events are pendi ngfor exampl e, when the
event l oop woul d otherwi se be i dl ewi th auxI dleFunc(). Thi s routi ne takes a poi nter to the functi on as
i ts onl y argument. Pass i n zero to di sabl e the executi on of the functi on.
Running the Program
Wi thi n your main() routi ne, cal l auxMainLoop() and pass i t the name of the routi ne that redraws the
objects i n your scene. Example 1−2 shows how you mi ght use the auxi l i ary l i brary to create the
si mpl e program shown i n Example 1−1.
Example 1−2 A Si mpl e OpenGL Program Usi ng the Auxi l i ary Li brary: si mpl e.c
#include <GL/gl.h>
#include "aux.h"
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
auxInitPosition (0, 0, 500, 500);
auxInitWindow (argv[0]);
glClearColor (0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(−1.0, 1.0, −1.0, 1.0, −1.0, 1.0);
glBegin(GL_POLYGON);
12
glBegin(GL_POLYGON);
glVertex2f(−0.5, −0.5);
glVertex2f(−0.5, 0.5);
glVertex2f(0.5, 0.5);
glVertex2f(0.5, −0.5);
glEnd();
glFlush();
sleep(10);
}
Animation
One of the most exci ti ng thi ngs you can do on a graphi cs computer i s draw pi ctures that move. Whether
you’re an engi neer tryi ng to see al l si des of a mechani cal part you’re desi gni ng, a pi l ot l earni ng to fl y an
ai rpl ane usi ng a si mul ati on, or merel y a computer−game afi ci onado, i t’s cl ear that ani mati on i s an
i mportant part of computer graphi cs.
I n a movi e theater, moti on i s achi eved by taki ng a sequence of pi ctures (24 per second), and then
projecti ng them at 24 per second on the screen. Each frame i s moved i nto posi ti on behi nd the l ens, the
shutter i s opened, and the frame i s di spl ayed. The shutter i s momentari l y cl osed whi l e the fi l m i s
advanced to the next frame, then that frame i s di spl ayed, and so on. Al though you’re watchi ng 24
di fferent frames each second, your brai n bl ends them al l i nto a smooth ani mati on. (The ol d Charl i e
Chapl i n movi es were shot at 16 frames per second and are noti ceabl y jerky.) I n fact, most modern
projectors di spl ay each pi cture twi ce at a rate of 48 per second to reduce fl i ckeri ng. Computer−graphi cs
screens typi cal l y refresh (redraw the pi cture) approxi matel y 60 to 76 ti mes per second, and some even
run at about 120 refreshes per second. Cl earl y, 60 per second i s smoother than 30, and 120 i s
margi nal l y better than 60. Refresh rates faster than 120, however, are beyond the poi nt of di mi ni shi ng
returns, si nce the human eye i s onl y so good.
The key i dea that makes moti on pi cture projecti on work i s that when i t i s di spl ayed, each frame i s
compl ete. Suppose you try to do computer ani mati on of your mi l l i on−frame movi e wi th a program l i ke
thi s:
open_window();
for (i = 0; i < 1000000; i++) {
clear_the_window();
draw_frame(i);
wait_until_a_24th_of_a_second_is_over();
}
I f you add the ti me i t takes for your system to cl ear the screen and to draw a typi cal frame, thi s
program gi ves more and more di sturbi ng resul ts dependi ng on how cl ose to 1/24 second i t takes to cl ear
and draw. Suppose the drawi ng takes nearl y a ful l 1/24 second. I tems drawn fi rst are vi si bl e for the ful l
1/24 second and present a sol i d i mage on the screen; i tems drawn toward the end are i nstantl y cl eared
as the program starts on the next frame, so they present at best a ghostl i ke i mage, si nce for most of the
1/24 second your eye i s vi ewi ng the cl eared background i nstead of the i tems that were unl ucky enough
to be drawn l ast. The probl em i s that thi s program doesn’t di spl ay compl etel y drawn frames; i nstead,
you watch the drawi ng as i t happens.
An easy sol uti on i s to provi de doubl e−bufferi nghardware or software that suppl i es two compl ete col or
buffers. One i s di spl ayed whi l e the other i s bei ng drawn. When the drawi ng of a frame i s compl ete, the
two buffers are swapped, so the one that was bei ng vi ewed i s now used for drawi ng, and vi ce versa. I t’s
l i ke a movi e projector wi th onl y two frames i n a l oop; whi l e one i s bei ng projected on the screen, an
arti st i s desperatel y erasi ng and redrawi ng the frame that’s not vi si bl e. As l ong as the arti st i s qui ck
enough, the vi ewer noti ces no di fference between thi s setup and one where al l the frames are al ready
13
drawn and the projector i s si mpl y di spl ayi ng them one after the other. Wi th doubl e−bufferi ng, every
frame i s shown onl y when the drawi ng i s compl ete; the vi ewer never sees a parti al l y drawn frame.
A modi fi ed versi on of the precedi ng program that does di spl ay smoothl y ani mated graphi cs mi ght l ook
l i ke thi s:
open_window_in_double_buffer_mode();
for (i = 0; i < 1000000; i++) {
clear_the_window();
draw_frame(i);
swap_the_buffers();
}
I n addi ti on to si mpl y swappi ng the vi ewabl e and drawabl e buffers, the swap_the_buffers() routi ne
wai ts unti l the current screen refresh peri od i s over so that the previ ous buffer i s compl etel y di spl ayed.
Thi s routi ne al so al l ows the new buffer to be compl etel y di spl ayed, starti ng from the begi nni ng.
Assumi ng that your system refreshes the di spl ay 60 ti mes per second, thi s means that the fastest
frame rate you can achi eve i s 60 frames per second, and i f al l your frames can be cl eared and drawn i n
under 1/60 second, your ani mati on wi l l run smoothl y at that rate.
What often happens on such a system i s that the frame i s too compl i cated to draw i n 1/60 second, so
each frame i s di spl ayed more than once. I f, for exampl e, i t takes 1/45 second to draw a frame, you get
30 frames per second, and the graphi cs are i dl e for 1/30−1/45=1/90 second per frame. Al though 1/90
second of wasted ti me mi ght not sound bad, i t’s wasted each 1/30 second, so actual l y one−thi rd of the
ti me i s wasted.
I n addi ti on, the vi deo refresh rate i s constant, whi ch can have some unexpected performance
consequences. For exampl e, wi th the 1/60 second per refresh moni tor and a constant frame rate, you
can run at 60 frames per second, 30 frames per second, 20 per second, 15 per second, 12 per second, and
so on (60/1, 60/2, 60/3, 60/4, 60/5, ...). That means that i f you’re wri ti ng an appl i cati on and gradual l y
addi ng features (say i t’s a fl i ght si mul ator, and you’re addi ng ground scenery), at fi rst each feature you
add has no effect on the overal l performanceyou sti l l get 60 frames per second. Then, al l of a sudden,
you add one new feature, and your performance i s cut i n hal f because the system can’t qui te draw the
whol e thi ng i n 1/60 of a second, so i t mi sses the fi rst possi bl e buffer−swappi ng ti me. A si mi l ar thi ng
happens when the drawi ng ti me per frame i s more than 1/30 secondthe performance drops from 30 to
20 frames per second, gi vi ng a 33 percent performance hi t.
Another probl em i s that i f the scene’s compl exi ty i s cl ose to any of the magi c ti mes (1/60 second, 2/60
second, 3/60 second, and so on i n thi s exampl e), then because of random vari ati on, some frames go
sl i ghtl y over the ti me and some sl i ghtl y under, and the frame rate i s i rregul ar, whi ch can be vi sual l y
di sturbi ng. I n thi s case, i f you can’t si mpl i fy the scene so that al l the frames are fast enough, i t mi ght
be better to add an i ntenti onal ti ny del ay to make sure they al l mi ss, gi vi ng a constant, sl ower, frame
rate. I f your frames have drasti cal l y di fferent compl exi ti es, a more sophi sti cated approach mi ght be
necessary.
I nteresti ngl y, the structure of real ani mati on programs does not di ffer too much from thi s descri pti on.
Usual l y, the enti re buffer i s redrawn from scratch for each frame, as i t i s easi er to do thi s than to fi gure
out what parts requi re redrawi ng. Thi s i s especi al l y true wi th appl i cati ons such as three−di mensi onal
fl i ght si mul ators where a ti ny change i n the pl ane’s ori entati on changes the posi ti on of everythi ng
outsi de the wi ndow.
I n most ani mati ons, the objects i n a scene are si mpl y redrawn wi th di fferent transformati onsthe
vi ewpoi nt of the vi ewer moves, or a car moves down the road a bi t, or an object i s rotated sl i ghtl y. I f
si gni fi cant modi fi cati ons to a structure are bei ng made for each frame where there’s si gni fi cant
recomputati on, the attai nabl e frame rate often sl ows down. Keep i n mi nd, however, that the i dl e ti me
after the swap_the_buffers() routi ne can often be used for such cal cul ati ons.
OpenGL doesn’t have a swap_the_buffers() command because the feature mi ght not be avai l abl e on al l
hardware and, i n any case, i t’s hi ghl y dependent on the wi ndow system. However, GLX provi des such a
14
command, for use on machi nes that use the X Wi ndow System:
void glXSwapBuffers(Display *dpy, Window window);
Example 1−3i l l ustrates the use of glXSwapBuffers() i n an exampl e that draws a square that rotates
constantl y, as shown i n Figure 1−2 .
Figure 1−2 A Doubl e−Buffered Rotati ng Square
Example 1−3 A Doubl e−Buffered Program: doubl e.c
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glx.h>
#include "aux.h"
static GLfloat spin = 0.0;
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
glRotatef(spin, 0.0, 0.0, 1.0);
glRectf(−25.0, −25.0, 25.0, 25.0);
glPopMatrix();
glFlush();
glXSwapBuffers(auxXDisplay(), auxXWindow());
}
void spinDisplay(void)
{
spin = spin + 2.0;
if (spin > 360.0)
spin = spin − 360.0;
display();
}
void startIdleFunc(AUX_EVENTREC *event)
{
15
auxIdleFunc(spinDisplay);
}
void stopIdleFunc(AUX_EVENTREC *event)
{
auxIdleFunc(0);
}
void myinit(void)
{
glClearColor(0.0, 0.0, 0.0, 1.0);
glColor3f(1.0, 1.0, 1.0);
glShadeModel(GL_FLAT);
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho (−50.0, 50.0, −50.0*(GLfloat)h/(GLfloat)w,
50.0*(GLfloat)h/(GLfloat)w, −1.0, 1.0);
else
glOrtho (−50.0*(GLfloat)w/(GLfloat)h,
50.0*(GLfloat)w/(GLfloat)h, −50.0, 50.0, −1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity ();
}
int main(int argc, char** argv)
{
auxInitDisplayMode(AUX_DOUBLE | AUX_RGBA);
auxInitPosition(0, 0, 500, 500);
auxInitWindow(argv[0]);
myinit();
auxReshapeFunc(myReshape);
auxIdleFunc(spinDisplay);
auxMouseFunc(AUX_LEFTBUTTON, AUX_MOUSEDOWN, startIdleFunc);
auxMouseFunc(AUX_MIDDLEBUTTON, AUX_MOUSEDOWN, stopIdleFunc);
auxMainLoop(display);
}
Chapter 2
Drawing Geometric Objects
Chapter Objectives
After readi ng thi s chapter, you’l l be abl e to do the fol l owi ng:
• Cl ear the wi ndow to an arbi trary col or
• Draw wi th any geometri c pri mi ti vepoi nts, l i nes, and pol ygonsi n two or three di mensi ons
• Control the di spl ay of those pri mi ti vesfor exampl e, draw dashed l i nes or outl i ned pol ygons
16
• Speci fy normal vectors at appropri ate poi nts on the surface of sol i d objects
• Force any pendi ng drawi ng to compl ete
Al though you can draw compl ex and i nteresti ng pi ctures usi ng OpenGL, they’re al l constructed from a
smal l number of pri mi ti ve graphi cal i tems. Thi s shoul dn’t be too surpri si ngl ook at what Leonardo da
Vi nci accompl i shed wi th just penci l s and pai ntbrushes.
At the hi ghest l evel of abstracti on, there are three basi c drawi ng operati ons: cl eari ng the wi ndow,
drawi ng a geometri c object, and drawi ng a raster object. Raster objects, whi ch i ncl ude such thi ngs as
two−di mensi onal i mages, bi tmaps, and character fonts, are covered i n Chapter 8 . I n thi s chapter, you
l earn how to cl ear the screen and to draw geometri c objects, i ncl udi ng poi nts, strai ght l i nes, and fl at
pol ygons.
You mi ght thi nk to yoursel f, "Wai t a mi nute. I ’ve seen l ots of computer graphi cs i n movi es and on
tel evi si on, and there are pl enty of beauti ful l y shaded curved l i nes and surfaces. How are those drawn, i f
al l OpenGL can draw are strai ght l i nes and fl at pol ygons?" Even the i mage on the cover of thi s book
i ncl udes a round tabl e and objects on the tabl e that have curved surfaces. I t turns out that al l the
curved l i nes and surfaces you’ve seen are approxi mated by l arge numbers of l i ttl e fl at pol ygons or
strai ght l i nes, i n much the same way that the gl obe on the cover i s constructed from a l arge set of
rectangul ar bl ocks. The gl obe doesn’t appear to have a smooth surface because the bl ocks are rel ati vel y
l arge compared to the gl obe. Later i n thi s chapter, we show you how to construct curved l i nes and
surfaces from l ots of smal l geometri c pri mi ti ves.
Thi s chapter has the fol l owi ng major secti ons:
• "A Drawing Survival Kit"expl ai ns how to cl ear the wi ndow and force drawi ng to be compl eted. I t
al so gi ves you basi c i nformati on about control l i ng the col or of geometri c objects and about
hi dden−surface removal .
• "Describing Points, Lines, and Polygons"shows you what the set of pri mi ti ve geometri c objects
i s and how to draw them.
• "Displaying Points, Lines, and Polygons"expl ai ns what control you have over the detai l s of how
pri mi ti ves are drawnfor exampl e, what di ameter poi nts have, whether l i nes are sol i d or dashed,
and whether pol ygons are outl i ned or fi l l ed.
• "Normal Vectors"di scusses how to speci fy normal vectors for geometri c objects and (bri efl y) what
these vectors are for.
• "Some Hints for Building Polygonal Models of Surfaces"expl ores the i ssues and techni ques
i nvol ved i n constructi ng pol ygonal approxi mati ons to surfaces.
One thi ng to keep i n mi nd as you read the rest of thi s chapter i s that wi th OpenGL, unl ess you speci fy
otherwi se, every ti me you i ssue a drawi ng command, the speci fi ed object i s drawn. Thi s mi ght seem
obvi ous, but i n some systems, you fi rst make a l i st of thi ngs to draw, and when i t’s compl ete, you tel l
the graphi cs hardware to draw the i tems i n the l i st. The fi rst styl e i s cal l ed i mmedi ate−mode graphi cs
and i s OpenGL’s defaul t styl e. I n addi ti on to usi ng i mmedi ate mode, you can choose to save some
commands i n a l i st (cal l ed a di spl ay l i st) for l ater drawi ng. I mmedi ate−mode graphi cs i s typi cal l y easi er
to program, but di spl ay l i sts are often more effi ci ent. Chapter 4 tel l s you how to use di spl ay l i sts and
why you mi ght want to use them.
A Drawing Survival Kit
Thi s secti on expl ai ns how to cl ear the wi ndow i n preparati on for drawi ng, set the col or of objects that
are to be drawn, and force drawi ng to be compl eted. None of these subjects has anythi ng to do wi th
geometri c objects i n a di rect way, but any program that draws geometri c objects has to deal wi th these
i ssues. Thi s secti on al so i ntroduces the concept of hi dden−surface removal , a techni que that can be
used to draw geometri c objects easi l y.
Clearing the Window
Drawi ng on a computer screen i s di fferent from drawi ng on paper i n that the paper starts out whi te,
17
and al l you have to do i s draw the pi cture. On a computer, the memory hol di ng the pi cture i s usual l y
fi l l ed wi th the l ast pi cture you drew, so you typi cal l y need to cl ear i t to some background col or before
you start to draw the new scene. The col or you use for the background depends on the appl i cati on. For a
word processor, you mi ght cl ear to whi te (the col or of the paper) before you begi n to draw the text. I f
you’re drawi ng a vi ew from a spaceshi p, you cl ear to the bl ack of space before begi nni ng to draw the
stars, pl anets, and al i en spaceshi ps. Someti mes you mi ght not need to cl ear the screen at al l ; for
exampl e, i f the i mage i s the i nsi de of a room, the enti re graphi cs wi ndow gets covered as you draw al l
the wal l s.
At thi s poi nt, you mi ght be wonderi ng why we keep tal ki ng about clearing the wi ndowwhy not just
draw a rectangl e of the appropri ate col or that’s l arge enough to cover the enti re wi ndow? Fi rst, a
speci al command to cl ear a wi ndow can be much more effi ci ent than a general −purpose drawi ng
command. I n addi ti on, as you’l l see i n Chapter 3 , OpenGL al l ows you to set the coordi nate system,
vi ewi ng posi ti on, and vi ewi ng di recti on arbi trari l y, so i t mi ght be di ffi cul t to fi gure out an appropri ate
si ze and l ocati on for a wi ndow−cl eari ng rectangl e. Al so, you can have OpenGL use hi dden−surface
removal techni ques that el i mi nate objects obscured by others nearer to the eye; thus, i f the
wi ndow−cl eari ng rectangl e i s to be a background, you must make sure that i t’s behi nd al l the other
objects of i nterest. Wi th an arbi trary coordi nate system and poi nt of vi ew, thi s mi ght be di ffi cul t.
Fi nal l y, on many machi nes, the graphi cs hardware consi sts of mul ti pl e buffers i n addi ti on to the buffer
contai ni ng col ors of the pi xel s that are di spl ayed. These other buffers must be cl eared from ti me to
ti me, and i t’s conveni ent to have a si ngl e command that can cl ear any combi nati on of them. (Al l the
possi bl e buffers are di scussed i n Chapter 10.)
As an exampl e, these l i nes of code cl ear the wi ndow to bl ack:
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
The fi rst l i ne sets the cl eari ng col or to bl ack, and the next command cl ears the enti re wi ndow to the
current cl eari ng col or. The si ngl e parameter to glClear() i ndi cates whi ch buffers are to be cl eared. I n
thi s case, the program cl ears onl y the col or buffer, where the i mage di spl ayed on the screen i s kept.
Typi cal l y, you set the cl eari ng col or once, earl y i n your appl i cati on, and then you cl ear the buffers as
often as necessary. OpenGL keeps track of the current cl eari ng col or as a state vari abl e rather than
requi ri ng you to speci fy i t each ti me a buffer i s cl eared.
Chapter 5 and Chapter 10 tal k about how other buffers are used. For now, al l you need to know i s
that cl eari ng them i s si mpl e. For exampl e, to cl ear both the col or buffer and the depth buffer, you
woul d use the fol l owi ng sequence of commands:
glClearColor(0.0, 0.0, 0.0, 0.0);
glClearDepth(0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
I n thi s case, the cal l to glClearColor() i s the same as before, the glClearDepth() command speci fi es the
val ue to whi ch every pi xel of the depth buffer i s to be set, and the parameter to the glClear() command
now consi sts of the l ogi cal OR of al l the buffers to be cl eared. The fol l owi ng summary of glClear()
i ncl udes a tabl e that l i sts the buffers that can be cl eared, thei r names, and the chapter where each type
of buffer i s di scussed.
voi d glClearColor(GLcl ampf red, GLcl ampf green, GLcl ampf blue, GLcl ampf alpha);
Sets the current cl eari ng col or for use i n cl eari ng col or buffers i n RGBA mode. For more i nformati on on
RGBA mode, see Chapter 5 . The red, green, blue, and alpha val ues are cl amped i f necessary to the
range [0,1]. The defaul t cl eari ng col or i s (0, 0, 0, 0), whi ch i s bl ack.
voi d glClear(GLbi tfi el d mask);
Cl ears the speci fi ed buffers to thei r current cl eari ng val ues. The mask argument i s a bi twi se−ORed
18
combi nati on of the val ues l i sted i n Table 2−1 .
Buffer Name Reference
Color buffer GL_COLOR_BUFFER_BIT Chapter 5
Depth buffer GL_DEPTH_BUFFER_BIT Chapter 10
Accumulation buffer GL_ACCUM_BUFFER_BIT Chapter 10
Stencil buffer GL_STENCIL_BUFFER_BIT Chapter 10
Table 2−1 Cl eari ng Buffers
Before i ssui ng a command to cl ear mul ti pl e buffers, you have to set the val ues to whi ch each buffer i s to
be cl eared i f you want somethi ng other than the defaul t col or, depth val ue, accumul ati on col or, and
stenci l i ndex. I n addi ti on to the glClearColor() and glClearDepth() commands that set the current
val ues for cl eari ng the col or and depth buffers, glClearI ndex(), glClearAccum(), and glClearStencil()
speci fy the col or i ndex, accumul ati on col or, and stenci l i ndex used to cl ear the correspondi ng buffers.
See Chapter 5 and Chapter 10 for descri pti ons of these buffers and thei r uses.
OpenGL al l ows you to speci fy mul ti pl e buffers because cl eari ng i s general l y a sl ow operati on, si nce
every pi xel i n the wi ndow (possi bl y mi l l i ons) i s touched, and some graphi cs hardware al l ows sets of
buffers to be cl eared si mul taneousl y. Hardware that doesn’t support si mul taneous cl ears performs
them sequenti al l y. The di fference between
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
and
glClear(GL_COLOR_BUFFER_BIT);
glClear(GL_DEPTH_BUFFER_BIT);
i s that al though both have the same fi nal effect, the fi rst exampl e mi ght run faster on many machi nes.
I t certai nl y won’t run more sl owl y.
Specifying a Color
Wi th OpenGL, the descri pti on of the shape of an object bei ng drawn i s i ndependent of the descri pti on of
i ts col or. Whenever a parti cul ar geometri c object i s drawn, i t’s drawn usi ng the currentl y speci fi ed
col ori ng scheme. The col ori ng scheme mi ght be as si mpl e as "draw everythi ng i n fi re−engi ne red," or
mi ght be as compl i cated as "assume the object i s made out of bl ue pl asti c, that there’s a yel l ow spotl i ght
poi nted i n such and such a di recti on, and that there’s a general l ow−l evel reddi sh−brown l i ght
everywhere el se." I n general , an OpenGL programmer fi rst sets the col or or col ori ng scheme, and then
draws the objects. Unti l the col or or col ori ng scheme i s changed, al l objects are drawn i n that col or or
usi ng that col ori ng scheme. Thi s method hel ps OpenGL achi eve hi gher drawi ng performance than
woul d resul t i f i t di dn’t keep track of the current col or.
For exampl e, the pseudocode
set_current_color(red);
draw_object(A);
draw_object(B);
set_current_color(green);
set_current_color(blue);
draw_object(C);
draws objects A and B i n red, and object C i n bl ue. The command on the fourth l i ne that sets the
current col or to green i s wasted.
Col ori ng, l i ghti ng, and shadi ng are al l l arge topi cs wi th enti re chapters or l arge secti ons devoted to
them. To draw geometri c pri mi ti ves that can be seen, however, you need some basi c knowl edge of how
to set the current col or; thi s i nformati on i s provi ded i n the next paragraphs. For detai l s on these topi cs,
see Chapter 5 and Chapter 6 .
19
To set a col or, use the command glColor3f(). I t takes three parameters, al l of whi ch are fl oati ng−poi nt
numbers between 0.0 and 1.0. The parameters are, i n order, the red, green, and bl ue components of the
col or. You can thi nk of these three val ues as speci fyi ng a "mi x" of col ors: 0.0 means don’t use any of that
component, and 1.0 means use al l you can of that component. Thus, the code
glColor3f(1.0, 0.0, 0.0);
makes the bri ghtest red the system can draw, wi th no green or bl ue components. Al l zeros makes bl ack;
i n contrast, al l ones makes whi te. Setti ng al l three components to 0.5 yi el ds gray (hal fway between
bl ack and whi te). Here are ei ght commands and the col ors they woul d set:
glColor3f(0.0, 0.0, 0.0); black
glColor3f(1.0, 0.0, 0.0); red
glColor3f(0.0, 1.0, 0.0); green
glColor3f(1.0, 1.0, 0.0); yellow
glColor3f(0.0, 0.0, 1.0); blue
glColor3f(1.0, 0.0, 1.0); magenta
glColor3f(0.0, 1.0, 1.0); cyan
glColor3f(1.0, 1.0, 1.0); white
You mi ght have noti ced earl i er that when you’re setti ng the col or to cl ear the col or buffer,
glClearColor() takes four parameters, the fi rst three of whi ch match the parameters for glColor3f(). The
fourth parameter i s the al pha val ue; i t’s covered i n detai l i n "Blending." For now, al ways set the
fourth parameter to 0.0.
Forcing Completion of Drawing
Most modern graphi cs systems can be thought of as an assembl y l i ne, someti mes cal l ed a graphi cs
pipeline. The mai n central processi ng uni t (CPU) i ssues a drawi ng command, perhaps other hardware
does geometri c transformati ons, cl i ppi ng occurs, then shadi ng or texturi ng i s performed, and fi nal l y,
the val ues are wri tten i nto the bi tpl anes for di spl ay (see Appendix A for detai l s on the order of
operati ons). I n hi gh−end archi tectures, each of these operati ons i s performed by a di fferent pi ece of
hardware that’s been desi gned to perform i ts parti cul ar task qui ckl y. I n such an archi tecture, there’s
no need for the CPU to wai t for each drawi ng command to compl ete before i ssui ng the next one. Whi l e
the CPU i s sendi ng a vertex down the pi pel i ne, the transformati on hardware i s worki ng on
transformi ng the l ast one sent, the one before that i s bei ng cl i pped, and so on. I n such a system, i f the
CPU wai ted for each command to compl ete before i ssui ng the next, there coul d be a huge performance
penal ty.
I n addi ti on, the appl i cati on mi ght be runni ng on more than one machi ne. For exampl e, suppose that
the mai n program i s runni ng el sewhere (on a machi ne cal l ed the cl i ent), and that you’re vi ewi ng the
resul ts of the drawi ng on your workstati on or termi nal (the server), whi ch i s connected by a network to
the cl i ent. I n that case, i t mi ght be horri bl y i neffi ci ent to send each command over the network one at a
ti me, si nce consi derabl e overhead i s often associ ated wi th each network transmi ssi on. Usual l y, the
cl i ent gathers a col l ecti on of commands i nto a si ngl e network packet before sendi ng i t. Unfortunatel y,
the network code on the cl i ent typi cal l y has no way of knowi ng that the graphi cs program i s fi ni shed
drawi ng a frame or scene. I n the worst case, i t wai ts forever for enough addi ti onal drawi ng commands
to fi l l a packet, and you never see the compl eted drawi ng.
For thi s reason, OpenGL provi des the command glFlush(), whi ch forces the cl i ent to send the network
packet even though i t mi ght not be ful l . Where there i s no network and al l commands are trul y
executed i mmedi atel y on the server, glFlush() mi ght have no effect. However, i f you’re wri ti ng a
program that you want to work properl y both wi th and wi thout a network, i ncl ude a cal l to glFlush() at
the end of each frame or scene. Note that glFlush() doesn’t wai t for the drawi ng to compl etei t just
forces the drawi ng to begi n executi on, thereby guaranteei ng that al l previ ous commands execute i n
fi ni te ti me even i f no further renderi ng commands are executed.
20
A few commandsfor exampl e, commands that swap buffers i n doubl e−buffer modeautomati cal l y
fl ush pendi ng commands onto the network before they can occur.
voi d glFlush(voi d);
Forces previ ousl y i ssued OpenGL commands to begi n executi on, thus guaranteei ng that they compl ete
i n fi ni te ti me.
I f glFlush() i sn’t suffi ci ent for you, try glFinish(). Thi s command fl ushes the network as glFlush() does
and then wai ts for noti fi cati on from the graphi cs hardware or network i ndi cati ng that the drawi ng i s
compl ete i n the framebuffer. You mi ght need to use glFinish() i f you want to synchroni ze tasksfor
exampl e, to make sure that your three−di mensi onal renderi ng i s on the screen before you use Di spl ay
PostScri pt to draw l abel s on top of the renderi ng. Another exampl e woul d be to ensure that the drawi ng
i s compl ete before i t begi ns to accept user i nput. After you i ssue a glFinish() command, your graphi cs
process i s bl ocked unti l i t recei ves noti fi cati on from the graphi cs hardware (or cl i ent, i f you’re runni ng
over a network) that the drawi ng i s compl ete. Keep i n mi nd that excessi ve use of glFinish() can reduce
the performance of your appl i cati on, especi al l y i f you’re runni ng over a network, because i t requi res
round−tri p communi cati on. I f glFlush() i s suffi ci ent for your needs, use i t i nstead of glFinish().
voi d glFinish(voi d);
Forces al l previ ousl y i ssued OpenGL commands to compl ete. Thi s command doesn’t return unti l al l
effects from previ ous commands are ful l y real i zed.
Hidden−Surface Removal Survival Kit
When you draw a scene composed of three−di mensi onal objects, some of them mi ght obscure al l or
parts of others. Changi ng your vi ewpoi nt can change the obscuri ng rel ati onshi p. For exampl e, i f you
vi ew the scene from the opposi te di recti on, any object that was previ ousl y i n front of another i s now
behi nd i t. To draw a real i sti c scene, these obscuri ng rel ati onshi ps must be mai ntai ned. I f your code
works somethi ng l i ke thi s
while (1) {
get_viewing_point_from_mouse_position();
glClear(GL_COLOR_BUFFER_BIT);
draw_3d_object_A();
draw_3d_object_B();
}
i t mi ght be that for some mouse posi ti ons, object A obscures object B, and for others, the opposi te
rel ati onshi p mi ght hol d. I f nothi ng speci al i s done, the precedi ng code al ways draws object B second,
and thus on top of object A, no matter what vi ewi ng posi ti on i s sel ected.
The el i mi nati on of parts of sol i d objects that are obscured by others i s cal l ed hidden−surfaceremoval.
(Hi dden−l i ne removal , whi ch does the same job for objects represented as wi reframe skel etons, i s a bi t
tri cki er, and i t i sn’t di scussed here. See "Hidden−Line Removal," for detai l s.) The easi est way to
achi eve hi dden−surface removal i s to use the depth buffer (someti mes cal l ed a z−buffer). (Al so see
Chapter 10.)
A depth buffer works by associ ati ng a depth, or di stance from the vi ewpoi nt, wi th each pi xel on the
wi ndow. I ni ti al l y, the depth val ues for al l pi xel s are set to the l argest possi bl e di stance usi ng the
glClear() command wi th GL_DEPTH_BUFFER_BI T, and then the objects i n the scene are drawn i n
any order.
Graphi cal cal cul ati ons i n hardware or software convert each surface that’s drawn to a set of pi xel s on
the wi ndow where the surface wi l l appear i f i t i sn’t obscured by somethi ng el se. I n addi ti on, the
di stance from the eye i s computed. Wi th depth bufferi ng enabl ed, before each pi xel i s drawn, a
compari son i s done wi th the depth val ue al ready stored at the pi xel . I f the new pi xel i s cl oser to the eye
21
than what’s there, the new pi xel ’s col or and depth val ues repl ace those that are currentl y wri tten i nto
the pi xel . I f the new pi xel ’s depth i s greater than what’s currentl y there, the new pi xel woul d be
obscured, and the col or and depth i nformati on for the i ncomi ng pi xel i s di scarded. Si nce i nformati on i s
di scarded rather than used for drawi ng, hi dden−surface removal can i ncrease your performance.
To use depth bufferi ng, you need to enabl e depth bufferi ng. Thi s has to be done onl y once. Each ti me
you draw the scene, before drawi ng you need to cl ear the depth buffer and then draw the objects i n the
scene i n any order.
To convert the precedi ng program fragment so that i t performs hi dden−surface removal , modi fy i t to
the fol l owi ng:
glEnable(GL_DEPTH_TEST);
...
while (1) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
get_viewing_point_from_mouse_position();
draw_3d_object_A();
draw_3d_object_B(); }
The argument to glClear() cl ears both the depth and col or buffers.
Describing Points, Lines, and Polygons
Thi s secti on expl ai ns how to descri be OpenGL geometri c pri mi ti ves. Al l geometri c pri mi ti ves are
eventual l y descri bed i n terms of thei r verticescoordi nates that defi ne the poi nts themsel ves, the
endpoi nts of l i ne segments, or the corners of pol ygons. The next secti on di scusses how these pri mi ti ves
are di spl ayed and what control you have over thei r di spl ay.
What Are Points, Lines, and Polygons?
You probabl y have a fai rl y good i dea of what a mathemati ci an means by the terms poi nt, l i ne, and
pol ygon. The OpenGL meani ngs aren’t qui te the same, however, and i t’s i mportant to understand the
di fferences. The di fferences ari se because mathemati ci ans can thi nk i n a geometri cal l y perfect worl d,
whereas the rest of us have to deal wi th real −worl d l i mi tati ons.
For exampl e, one di fference comes from the l i mi tati ons of computer−based cal cul ati ons. I n any OpenGL
i mpl ementati on, fl oati ng−poi nt cal cul ati ons are of fi ni te preci si on, and they have round−off errors.
Consequentl y, the coordi nates of OpenGL poi nts, l i nes, and pol ygons suffer from the same probl ems.
Another di fference ari ses from the l i mi tati ons of a bi tmapped graphi cs di spl ay. On such a di spl ay, the
smal l est di spl ayabl e uni t i s a pi xel , and al though pi xel s mi ght be l ess than 1/100th of an i nch wi de,
they are sti l l much l arger than the mathemati ci an’s i nfi ni tel y smal l (for poi nts) or i nfi ni tel y thi n (for
l i nes). When OpenGL performs cal cul ati ons, i t assumes poi nts are represented as vectors of
fl oati ng−poi nt numbers. However, a poi nt i s typi cal l y (but not al ways) drawn as a si ngl e pi xel , and
many di fferent poi nts wi th sl i ghtl y di fferent coordi nates coul d be drawn by OpenGL on the same pi xel .
Points
A poi nt i s represented by a set of fl oati ng−poi nt numbers cal l ed a vertex. Al l i nternal cal cul ati ons are
done as i f verti ces are three−di mensi onal . Verti ces speci fi ed by the user as two−di mensi onal (that i s,
wi th onl y x and y coordi nates) are assi gned a z coordi nate equal to zero by OpenGL.
Advanced
OpenGL works i n the homogeneous coordi nates of three−di mensi onal projecti ve geometry, so for
i nternal cal cul ati ons, al l verti ces are represented wi th four fl oati ng−poi nt coordi nates (x, y, z, w). I f w i s
di fferent from zero, these coordi nates correspond to the eucl i dean three−di mensi onal poi nt (x/ w, y/ w,
22
z/ w). You can speci fy the w coordi nate i n OpenGL commands, but that’s rarel y done. I f the w coordi nate
i sn’t speci fi ed, i t’s understood to be 1.0. For more i nformati on about homogeneous coordi nate systems,
see Appendix G .
Lines
I n OpenGL, linemeans linesegment, not the mathemati ci an’s versi on that extends to i nfi ni ty i n both
di recti ons. There are easy ways to speci fy a connected seri es of l i ne segments, or even a cl osed,
connected seri es of segments (see Figure 2−1 ). I n al l cases, though, the l i nes compri si ng the connected
seri es are speci fi ed i n terms of the verti ces at thei r endpoi nts.
Figure 2−1 Two Connected Seri es of Li ne Segments
Polygons
Pol ygons are the areas encl osed by si ngl e cl osed l oops of l i ne segments, where the l i ne segments are
speci fi ed by the verti ces at thei r endpoi nts. Pol ygons are typi cal l y drawn wi th the pi xel s i n the i nteri or
fi l l ed i n, but you can al so draw them as outl i nes or a set of poi nts, as descri bed i n "Polygon Details."
I n general , pol ygons can be compl i cated, so OpenGL makes some strong restri cti ons on what
consti tutes a pri mi ti ve pol ygon. Fi rst, the edges of OpenGL pol ygons can’t i ntersect (a mathemati ci an
woul d cal l thi s a simplepolygon). Second, OpenGL pol ygons must be convex, meani ng that they cannot
have i ndentati ons. Stated preci sel y, a regi on i s convex i f, gi ven any two poi nts i n the i nteri or, the l i ne
segment joi ni ng them i s al so i n the i nteri or. See Figure 2−2 for some exampl es of val i d and i nval i d
pol ygons. OpenGL, however, doesn’t restri ct the number of l i ne segments maki ng up the boundary of a
convex pol ygon. Note that pol ygons wi th hol es can’t be descri bed. They are nonconvex, and they can’t
be drawn wi th a boundary made up of a si ngl e cl osed l oop. Be aware that i f you present OpenGL wi th a
nonconvex fi l l ed pol ygon, i t mi ght not draw i t as you expect. For i nstance, on most systems no more
than the convex hul l of the pol ygon woul d be fi l l ed, but on some systems, l ess than the convex hul l
mi ght be fi l l ed.
23
Figure 2−2 Val i d and I nval i d Pol ygons
For many appl i cati ons, you need nonsi mpl e pol ygons, nonconvex pol ygons, or pol ygons wi th hol es.
Si nce al l such pol ygons can be formed from uni ons of si mpl e convex pol ygons, some routi nes to descri be
more compl ex objects are provi ded i n the GLU. These routi nes take compl ex descri pti ons and tessellate
them, or break them down i nto groups of the si mpl er OpenGL pol ygons that can then be rendered.
(See Appendix C for more i nformati on about the tessel l ati on routi nes.) The reason for OpenGL’s
restri cti ons on val i d pol ygon types i s that i t’s si mpl er to provi de fast pol ygon−renderi ng hardware for
that restri cted cl ass of pol ygons.
Si nce OpenGL verti ces are al ways three−di mensi onal , the poi nts formi ng the boundary of a parti cul ar
pol ygon don’t necessari l y l i e on the same pl ane i n space. (Of course, they do i n many casesi f al l the z
coordi nates are zero, for exampl e, or i f the pol ygon i s a tri angl e.) I f a pol ygon’s verti ces don’t l i e i n the
same pl ane, then after vari ous rotati ons i n space, changes i n the vi ewpoi nt, and projecti on onto the
di spl ay screen, the poi nts mi ght no l onger form a si mpl e convex pol ygon. For exampl e, i magi ne a
four−poi nt quadri l ateral where the poi nts are sl i ghtl y out of pl ane, and l ook at i t al most edge−on. You
can get a nonsi mpl e pol ygon that resembl es a bow ti e, as shown i n Figure 2−3 , whi ch i sn’t
guaranteed to render correctl y. Thi s si tuati on i sn’t al l that unusual i f you approxi mate surfaces by
quadri l ateral s made of poi nts l yi ng on the true surface. You can al ways avoi d the probl em by usi ng
tri angl es, si nce any three poi nts al ways l i e on a pl ane.
Figure 2−3 Nonpl anar Pol ygon Transformed to Nonsi mpl e Pol ygon
Rectangles
Si nce rectangl es are so common i n graphi cs appl i cati ons, OpenGL provi des a fi l l ed−rectangl e drawi ng
pri mi ti ve, glRect*(). You can draw a rectangl e as a pol ygon, as descri bed i n "OpenGL Geometric
Drawing Primitives," but your parti cul ar i mpl ementati on of OpenGL mi ght have opti mi zed glRect*()
24
for rectangl es.
voi d glRect{si fd}(TYPEx1, TYPEy1, TYPEx2, TYPEy2);
voi d glRect{si fd}v(TYPE*v1, TYPE*v2);
Draws the rectangl e defi ned by the corner poi nts (x1, y1) and (x2, y2). The rectangl e l i es i n the pl ane z=0
and has si des paral l el to the x− and y−axes. I f the vector form of the functi on i s used, the corners are
gi ven by two poi nters to arrays, each of whi ch contai ns an (x, y) pai r.
Note that al though the rectangl e begi ns wi th a parti cul ar ori entati on i n three−di mensi onal space (i n
the x−y pl ane and paral l el to the axes), you can change thi s by appl yi ng rotati ons or other
transformati ons. See Chapter 3 for i nformati on about how to do thi s.
Curves
Any smoothl y curved l i ne or surface can be approxi matedto any arbi trary degree of accuracyby
short l i ne segments or smal l pol ygonal regi ons. Thus, subdi vi di ng curved l i nes and surfaces suffi ci entl y
and then approxi mati ng them wi th strai ght l i ne segments or fl at pol ygons makes them appear curved
(see Figure 2−4 ). I f you’re skepti cal that thi s real l y works, i magi ne subdi vi di ng unti l each l i ne
segment or pol ygon i s so ti ny that i t’s smal l er than a pi xel on the screen.
Figure 2−4 Approxi mati ng Curves
Even though curves aren’t geometri c pri mi ti ves, OpenGL does provi de some di rect support for drawi ng
them. See Chapter 11 for i nformati on about how to draw curves and curved surfaces.
Specifying Vertices
Wi th OpenGL, al l geometri c objects are ul ti matel y descri bed as an ordered set of verti ces. You use the
glVertex*() command to speci fy a vertex.
voi d glVertex{234}{si fd}[v](TYPEcoords);
Speci fi es a vertex for use i n descri bi ng a geometri c object. You can suppl y up to four coordi nates (x, y, z,
w) for a parti cul ar vertex or as few as two (x, y) by sel ecti ng the appropri ate versi on of the command. I f
you use a versi on that doesn’t expl i ci tl y speci fy z or w, z i s understood to be 0 and w i s understood to be
1. Cal l s to glVertex*() shoul d be executed between a glBegin() and glEnd() pai r.
Here are some exampl es of usi ng glVertex*():
glVertex2s(2, 3);
glVertex3d(0.0, 0.0, 3.1415926535898);
glVertex4f(2.3, 1.0, −2.2, 2.0);
GLdouble dvect[3] = {5.0, 9.0, 1992.0};
glVertex3dv(dvect);
25
The fi rst exampl e represents a vertex wi th three−di mensi onal coordi nates (2, 3, 0). (Remember that i f
i t i sn’t speci fi ed, the z coordi nate i s understood to be 0.) The coordi nates i n the second exampl e are (0.0,
0.0, 3.1415926535898) (doubl e−preci si on fl oati ng−poi nt numbers). The thi rd exampl e represents the
vertex wi th three−di mensi onal coordi nates (1.15, 0.5, −1.1). (Remember that the x, y, and z coordi nates
are eventual l y di vi ded by the w coordi nate.) I n the fi nal exampl e, dvect i s a poi nter to an array of three
doubl e−preci si on fl oati ng−poi nt numbers.
On some machi nes, the vector form of glVertex*() i s more effi ci ent, si nce onl y a si ngl e parameter needs
to be passed to the graphi cs subsystem, and speci al hardware mi ght be abl e to send a whol e seri es of
coordi nates i n a si ngl e batch. I f your machi ne i s l i ke thi s, i t’s to your advantage to arrange your data so
that the vertex coordi nates are packed sequenti al l y i n memory.
OpenGL Geometric Drawing Primitives
Now that you’ve seen how to speci fy verti ces, you sti l l need to know how to tel l OpenGL to create a set
of poi nts, a l i ne, or a pol ygon from those verti ces. To do thi s, you bracket each set of verti ces between a
cal l to glBegin() and a cal l to glEnd(). The argument passed to glBegin() determi nes what sort of
geometri c pri mi ti ve i s constructed from the verti ces. For exampl e, the fol l owi ng code speci fi es the
verti ces for the pol ygon shown i n Figure 2−5 :
glBegin(GL_POLYGON);
glVertex2f(0.0, 0.0);
glVertex2f(0.0, 3.0);
glVertex2f(3.0, 3.0);
glVertex2f(4.0, 1.5);
glVertex2f(3.0, 0.0);
glEnd();
Figure 2−5 Drawi ng a Pol ygon or a Set of Poi nts
I f you had used GL_POI NTS i nstead of GL_POLYGON, the pri mi ti ve woul d have been si mpl y the fi ve
poi nts shown i n Figure 2−5 . Table 2−2 i n the fol l owi ng functi on summary for glBegin() l i sts the ten
possi bl e arguments and the correspondi ng type of pri mi ti ve.
voi d glBegin(GLenum mode);
Marks the begi nni ng of a vertex l i st that descri bes a geometri c pri mi ti ve. The type of pri mi ti ve i s
i ndi cated by mode, whi ch can be any of the val ues shown i n Table 2−2 .
Value Meaning
GL_POINTS individual points
GL_LINES pairs of vertices interpreted as individual line segments
GL_POLYGON boundary of a simple, convex polygon
GL_TRIANGLES triples of vertices interpreted as triangles
26
GL_QUADS quadruples of vertices interpreted as four−sided polygons
GL_LINE_STRIP series of connected line segments
GL_LINE_LOOP same as above, with a segment added between last and first vertices
GL_TRIANGLE_STRIP linked strip of triangles
GL_TRIANGLE_FAN linked fan of triangles
GL_QUAD_STRIP linked strip of quadrilaterals
Table 2−2 Geometri c Pri mi ti ve Names and Meani ngs
voi d glEnd(voi d);
Marks the end of a vertex l i st.
Figure 2−6 shows exampl es of al l the geometri c pri mi ti ves l i sted i n Table 2−2 . The paragraphs that
fol l ow the fi gure gi ve preci se descri pti ons of the pi xel s that are drawn for each of the objects. Note that
i n addi ti on to poi nts, several types of l i nes and pol ygons are defi ned. Obvi ousl y, you can fi nd many
ways to draw the same pri mi ti ve. The method you choose depends on your vertex data.
Figure 2−6 Geometri c Pri mi ti ve Types
27
As you read the fol l owi ng descri pti ons, assume that n verti ces (v0, v1, v2, ... , vn−1) are descri bed
between a glBegin() and glEnd() pai r.
GL_POI NTS Draws a poi nt at each of the n verti ces.
GL_LI NES Draws a seri es of unconnected l i ne segments. Segments are drawn between v0 and v1,
between v2 and v3, and so on. I f n i s odd, the l ast segment i s drawn between vn−3 and
vn−2, and vn−1 i s i gnored.
GL_POLYGON
Draws a pol ygon usi ng the poi nts v0, ... , vn−1 as verti ces. n must be at l east 3, or
nothi ng i s drawn. I n addi ti on, the pol ygon speci fi ed must not i ntersect i tsel f and must
be convex. I f the verti ces don’t sati sfy these condi ti ons, the resul ts are unpredi ctabl e.
GL_TRI ANGLES
Draws a seri es of tri angl es (three−si ded pol ygons) usi ng verti ces v0, v1, v2, then v3,
v4, v5, and so on. I f n i sn’t an exact mul ti pl e of 3, the fi nal one or two verti ces are
i gnored.
GL_LI NE_STRI P
Draws a l i ne segment from v0 to v1, then from v1 to v2, and so on, fi nal l y drawi ng the
segment from vn−2 to vn−1. Thus, a total of n−1 l i ne segments are drawn. Nothi ng i s
drawn unl ess n i s l arger than 1. There are no restri cti ons on the verti ces descri bi ng a
l i ne stri p (or a l i ne l oop); the l i nes can i ntersect arbi trari l y.
GL_LI NE_LOOP
Same as GL_LI NE_STRI P, except that a fi nal l i ne segment i s drawn from vn−1 to v0,
compl eti ng a l oop.
GL_QUADS Draws a seri es of quadri l ateral s (four−si ded pol ygons) usi ng verti ces v0, v1, v2, v3,
then v4, v5, v6, v7, and so on. I f n i sn’t a mul ti pl e of 4, the fi nal one, two, or three
verti ces are i gnored.
GL_QUAD_STRI P
Draws a seri es of quadri l ateral s (four−si ded pol ygons) begi nni ng wi th v0, v1, v3, v2,
then v2, v3, v5, v4, then v4, v5, v7, v6, and so on. See Figure 2−6 . n must be at l east
4 before anythi ng i s drawn, and i f n i s odd, the fi nal vertex i s i gnored.
GL_TRI ANGLE_STRI P
Draws a seri es of tri angl es (three−si ded pol ygons) usi ng verti ces v0, v1, v2, then v2,
v1, v3 (note the order), then v2, v3, v4, and so on. The orderi ng i s to ensure that the
tri angl es are al l drawn wi th the same ori entati on so that the stri p can correctl y form
part of a surface. Figure 2−6 shoul d make the reason for the orderi ng obvi ous. n
must be at l east 3 for anythi ng to be drawn.
GL_TRI ANGLE_FAN
Same as GL_TRI ANGLE_STRI P, except that the verti ces are v0, v1, v2, then v0, v2,
v3, then v0, v3, v4, and so on. Look at Figure 2−6 .
Restrictions on Using glBegin() and glEnd()
The most i mportant i nformati on about verti ces i s thei r coordi nates, whi ch are speci fi ed by the
glVertex*() command. You can al so suppl y addi ti onal vertex−speci fi c data for each vertexa col or, a
normal vector, texture coordi nates, or any combi nati on of theseusi ng speci al commands. I n addi ti on,
a few other commands are val i d between a glBegin() and glEnd() pai r. Table 2−3 contai ns a compl ete
l i st of such val i d commands.
Command Purpose of Command Reference
glVertex*() set vertex coordinates Chapter 2
glColor*() set current color Chapter 5
glIndex*() set current color index Chapter 5
glNormal*() set normal vector coordinates Chapter 2
glEvalCoord*() generate coordinates Chapter 11
glCallList(), glCallLists() execute display list(s) Chapter 4
glTexCoord*() set texture coordinates Chapter 9
28
glEdgeFlag*() control drawing of edges Chapter 2
glMaterial*() set material properties Chapter 6
Table 2−3 Val i d Commands between gl Begi n() and gl End()
No other OpenGL commands are val i d between a glBegin() and glEnd() pai r, and maki ng any other
OpenGL cal l generates an error. Note, however, that onl y OpenGL commands are restri cted; you can
certai nl y i ncl ude other programmi ng−l anguage constructs. For exampl e, the fol l owi ng code draws an
outl i ned ci rcl e:
#define PI 3.1415926535897;
GLint circle_points = 100;
glBegin(GL_LINE_LOOP);
for (i = 0; i < circle_points; i++) {
angle = 2*PI*i/circle_points;
glVertex2f(cos(angle), sin(angle));
}
glEnd();
Note: Thi s exampl e i sn’t the most effi ci ent way to draw a ci rcl e, especi al l y i f you i ntend to do i t
repeatedl y. The graphi cs commands used are typi cal l y very fast, but thi s code cal cul ates an
angl e and cal l s the sin() and cos() routi nes for each vertex; i n addi ti on, there’s the l oop
overhead. I f you need to draw l ots of ci rcl es, cal cul ate the coordi nates of the verti ces once and
save them i n an array, create a di spl ay l i st (see Chapter 4 ,) or use a GLU routi ne (see
Appendix C .)
Unl ess they are bei ng compi l ed i nto a di spl ay l i st, al l glVertex*() commands shoul d appear between
some glBegin() and glEnd() combi nati on. (I f they appear el sewhere, they don’t accompl i sh anythi ng.) I f
they appear i n a di spl ay l i st, they are executed onl y i f they appear between a glBegin() and a glEnd().
Al though many commands are al l owed between glBegin() and glEnd(), verti ces are generated onl y when
a glVertex*() command i s i ssued. At the moment glVertex*() i s cal l ed, OpenGL assi gns the resul ti ng
vertex the current col or, texture coordi nates, normal vector i nformati on, and so on. To see thi s, l ook at
the fol l owi ng code sequence. The fi rst poi nt i s drawn i n red, and the second and thi rd ones i n bl ue,
despi te the extra col or commands:
glBegin(GL_POINTS);
glColor3f(0.0, 1.0, 0.0); /* green */
glColor3f(1.0, 0.0, 0.0); /* red */
glVertex(...);
glColor3f(1.0, 1.0, 0.0); /* yellow */
glColor3f(0.0, 0.0, 1.0); /* blue */
glVertex(...);
glVertex(...);
glEnd();
You can use any combi nati on of the twenty−four versi ons of the glVertex*() command between glBegin()
and glEnd(), al though i n real appl i cati ons al l the cal l s i n any parti cul ar i nstance tend to be of the same
form.
Displaying Points, Lines, and Polygons
By defaul t, a poi nt i s drawn as a si ngl e pi xel on the screen, a l i ne i s drawn sol i d and one pi xel wi de,
and pol ygons are drawn sol i dl y fi l l ed i n. The fol l owi ng paragraphs di scuss the detai l s of how to change
these defaul t di spl ay modes.
29
Point Details
To control the si ze of a rendered poi nt, use glPointSize() and suppl y the desi red si ze i n pi xel s as the
argument.
voi d glPointSize(GLfl oat size);
Sets the wi dth i n pi xel s for rendered poi nts; sizemust be greater than 0.0 and by defaul t i s 1.0.
The actual col l ecti on of pi xel s on the screen that are drawn for vari ous poi nt wi dths depends on
whether anti al i asi ng i s enabl ed. (Anti al i asi ng i s a techni que for smoothi ng poi nts and l i nes as they’re
rendered. Thi s topi c i s covered i n detai l i n "Antialiasing.") I f anti al i asi ng i s di sabl ed (the defaul t),
fracti onal wi dths are rounded to i nteger wi dths, and a screen−al i gned square regi on of pi xel s i s drawn.
Thus, i f the wi dth i s 1.0, the square i s one pi xel by one pi xel ; i f the wi dth i s 2.0, the square i s two pi xel s
by two pi xel s, and so on.
Wi th anti al i asi ng enabl ed, a ci rcul ar group of pi xel s i s drawn, and the pi xel s on the boundari es are
typi cal l y drawn at l ess than ful l i ntensi ty to gi ve the edge a smoother appearance. I n thi s mode,
noni ntegral wi dths aren’t rounded.
Most OpenGL i mpl ementati ons support very l arge poi nt si zes. A parti cul ar i mpl ementati on, however,
mi ght l i mi t the si ze of nonanti al i ased poi nts to i ts maxi mum anti al i ased poi nt si ze, rounded to the
nearest i nteger val ue. You can obtai n thi s fl oati ng−poi nt val ue by usi ng GL_POI NT_SI ZE_RANGE
wi th glGetFloatv().
Line Details
Wi th OpenGL, you can speci fy l i nes wi th di fferent wi dths and l i nes that are stippled i n vari ous ways
dotted, dashed, drawn wi th al ternati ng dots and dashes, and so on.
Wide Lines
voi d glLineWidth(GLfl oat width);
Sets the wi dth i n pi xel s for rendered l i nes; width must be greater than 0.0 and by defaul t i s 1.0.
The actual renderi ng of l i nes i s affected by the anti al i asi ng mode, i n the same way as for poi nts. (See
"Antialiasing.") Wi thout anti al i asi ng, wi dths of 1, 2, and 3 draw l i nes one, two, and three pi xel s wi de.
Wi th anti al i asi ng enabl ed, noni ntegral l i ne wi dths are possi bl e, and pi xel s on the boundari es are
typi cal l y parti al l y fi l l ed. As wi th poi nt si zes, a parti cul ar OpenGL i mpl ementati on mi ght l i mi t the
wi dth of nonanti al i ased l i nes to i ts maxi mum anti al i ased l i ne wi dth, rounded to the nearest i nteger
val ue. You can obtai n thi s fl oati ng−poi nt val ue by usi ng GL_LI NE_WI DTH_RANGE wi th glGetFloatv()
.
Note: Keep i n mi nd that by defaul t l i nes are one pi xel wi de, so they appear wi der on l ower−resol uti on
screens. For computer di spl ays, thi s i sn’t typi cal l y an i ssue, but i f you’re usi ng OpenGL to
render to a hi gh−resol uti on pl otter, one−pi xel l i nes mi ght be nearl y i nvi si bl e. To obtai n
resol uti on−i ndependent l i ne wi dths, you need to take i nto account the physi cal di mensi ons of
pi xel s.
Advanced
Wi th nonanti al i ased wi de l i nes, the l i ne wi dth i sn’t measured perpendi cul ar to the l i ne. I nstead, i t’s
measured i n the y di recti on i f the absol ute val ue of the sl ope i s l ess than 1.0; otherwi se, i t’s measured
i n the x di recti on. The renderi ng of an anti al i ased l i ne i s exactl y equi val ent to the renderi ng of a fi l l ed
rectangl e of the gi ven wi dth, centered on the exact l i ne. See "Polygon Details," for a di scussi on of the
renderi ng of fi l l ed pol ygonal regi ons.
30
Stippled Lines
To make sti ppl ed (dotted or dashed) l i nes, you use the command glLineStipple() to defi ne the sti ppl e
pattern, and then you enabl e l i ne sti ppl i ng wi th glEnable():
glLineStipple(1, 0x3F07);
glEnable(GL_LINE_STIPPLE);
voi d glLineStipple(GLi nt factor, GLushort pattern);
Sets the current sti ppl i ng pattern for l i nes. The pattern argument i s a 16−bi t seri es of 0s and 1s, and
i t’s repeated as necessary to sti ppl e a gi ven l i ne. A 1 i ndi cates that drawi ng occurs, and 0 that i t does
not, on a pi xel −by−pi xel basi s, begi nni ng wi th the l ow−order bi ts of the pattern. The pattern can be
stretched out by usi ng factor, whi ch mul ti pl i es each subseri es of consecuti ve 1s and 0s. Thus, i f three
consecuti ve 1s appear i n the pattern, they’re stretched to si x i f factor i s 2. factor i s cl amped to l i e
between 1 and 255. Li ne sti ppl i ng must be enabl ed by passi ng GL_LI NE_STI PPLE to glEnable(); i t’s
di sabl ed by passi ng the same argument to glDisable().
Wi th the precedi ng exampl e and the pattern 0x3F07 (whi ch transl ates to 0011111100000111 i n
bi nary), a l i ne woul d be drawn wi th 3 pi xel s on, then 5 off, 6 on, and 2 off. (I f thi s seems backward,
remember that the l ow−order bi ts are used fi rst.) I f factor had been 2, the pattern woul d have been
el ongated: 6 pi xel s on, 10 off, 12 on, and 4 off. Figure 2−7 shows l i nes drawn wi th di fferent patterns
and repeat factors. I f you don’t enabl e l i ne sti ppl i ng, drawi ng proceeds as i f pattern were 0xFFFF and
factor 1. (Use glDisable() wi th GL_LI NE_STI PPLE to di sabl e sti ppl i ng.) Note that sti ppl i ng can be used
i n combi nati on wi th wi de l i nes to produce wi de sti ppl ed l i nes.
Figure 2−7 Sti ppl ed Li nes
One way to thi nk of the sti ppl i ng i s that as the l i ne i s bei ng drawn, the pattern i s shi fted by one bi t
each ti me a pi xel i s drawn (or factor pi xel s are drawn, i f factor i sn’t 1). When a seri es of connected l i ne
segments i s drawn between a si ngl e glBegin() and glEnd(), the pattern conti nues to shi ft as one segment
turns i nto the next. Thi s way, a sti ppl i ng pattern conti nues across a seri es of connected l i ne segments.
When glEnd() i s executed, the pattern i s reset, andi f more l i nes are drawn before sti ppl i ng i s di sabl ed
the sti ppl i ng restarts at the begi nni ng of the pattern. I f you’re drawi ng l i nes wi th GL_LI NES, the
pattern resets for each i ndependent l i ne.
Example 2−1i l l ustrates the resul ts of drawi ng wi th a coupl e of di fferent sti ppl e patterns and l i ne
wi dths. I t al so i l l ustrates what happens i f the l i nes are drawn as a seri es of i ndi vi dual segments
i nstead of a si ngl e connected l i ne stri p. The resul ts of runni ng the program appear i n Figure 2−8 .
31
Figure 2−8 Wi de Sti ppl ed Li nes
Example 2−1 Usi ng Li ne Sti ppl e Patterns: l i nes.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
#define drawOneLine(x1,y1,x2,y2) glBegin(GL_LINES); \
glVertex2f ((x1),(y1)); glVertex2f ((x2),(y2)); glEnd();
void myinit (void) {
/* background to be cleared to black */
glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel (GL_FLAT);
}
void display(void)
{
int i;
glClear (GL_COLOR_BUFFER_BIT);
/* draw all lines in white */
glColor3f (1.0, 1.0, 1.0);
/* in 1st row, 3 lines, each with a different stipple */
glEnable (GL_LINE_STIPPLE);
glLineStipple (1, 0x0101); /* dotted */
drawOneLine (50.0, 125.0, 150.0, 125.0);
glLineStipple (1, 0x00FF); /* dashed */
drawOneLine (150.0, 125.0, 250.0, 125.0);
glLineStipple (1, 0x1C47); /* dash/dot/dash */
drawOneLine (250.0, 125.0, 350.0, 125.0);
/* in 2nd row, 3 wide lines, each with different stipple */
glLineWidth (5.0);
glLineStipple (1, 0x0101);
drawOneLine (50.0, 100.0, 150.0, 100.0);
32
glLineStipple (1, 0x00FF);
drawOneLine (150.0, 100.0, 250.0, 100.0);
glLineStipple (1, 0x1C47);
drawOneLine (250.0, 100.0, 350.0, 100.0);
glLineWidth (1.0);
/* in 3rd row, 6 lines, with dash/dot/dash stipple, */
/* as part of a single connected line strip */
glLineStipple (1, 0x1C47);
glBegin (GL_LINE_STRIP);
for (i = 0; i < 7; i++)
glVertex2f (50.0 + ((GLfloat) i * 50.0), 75.0);
glEnd ();
/* in 4th row, 6 independent lines, */
/* with dash/dot/dash stipple */
for (i = 0; i < 6; i++) {
drawOneLine (50.0 + ((GLfloat) i * 50.0),
50.0, 50.0 + ((GLfloat)(i+1) * 50.0), 50.0);
}
/* in 5th row, 1 line, with dash/dot/dash stipple */
/* and repeat factor of 5 */
glLineStipple (5, 0x1C47);
drawOneLine (50.0, 25.0, 350.0, 25.0);
glFlush ();
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
auxInitPosition (0, 0, 400, 150);
auxInitWindow (argv[0]);
myinit ();
auxMainLoop(display);
}
Polygon Details
Pol ygons are typi cal l y drawn by fi l l i ng i n al l the pi xel s encl osed wi thi n the boundary, but you can al so
draw them as outl i ned pol ygons, or si mpl y as poi nts at the verti ces. A fi l l ed pol ygon mi ght be sol i dl y
fi l l ed, or sti ppl ed wi th a certai n pattern. Al though the exact detai l s are omi tted here, pol ygons are
drawn i n such a way that i f adjacent pol ygons share an edge or vertex, the pi xel s maki ng up the edge or
vertex are drawn exactl y oncethey’re i ncl uded i n onl y one of the pol ygons. Thi s i s done so that
parti al l y transparent pol ygons don’t have thei r edges drawn twi ce, whi ch woul d make those edges
appear darker (or bri ghter, dependi ng on what col or you’re drawi ng wi th). Note that i t mi ght resul t i n
narrow pol ygons havi ng no fi l l ed pi xel s i n one or more rows or col umns of pi xel s. Anti al i asi ng pol ygons
i s more compl i cated than for poi nts and l i nes; see "Antialiasing," for detai l s.
Polygons as Points, Outlines, or Solids
A pol ygon has two si desfront and backand mi ght be rendered di fferentl y dependi ng on whi ch si de
i s faci ng the vi ewer. Thi s al l ows you to have cutaway vi ews of sol i d objects i n whi ch there i s an obvi ous
33
di sti ncti on between the parts that are i nsi de and those that are outsi de. By defaul t, both front and
back faces are drawn i n the same way. To change thi s, or to draw onl y outl i nes or verti ces, use
glPolygonMode().
voi d glPolygonMode(GLenum face, GLenum mode);
Control s the drawi ng mode for a pol ygon’s front and back faces. The parameter facecan be
GL_FRONT_AND_BACK, GL_FRONT, or GL_BACK; modecan be GL_POI NT, GL_LI NE, or GL_FI LL
to i ndi cate whether the pol ygon shoul d be drawn as poi nts, outl i ned, or fi l l ed. By defaul t, both the front
and back faces are drawn fi l l ed.
For exampl e, you can have the front faces fi l l ed and the back faces outl i ned wi th two cal l s to thi s
routi ne:
glPolygonMode(GL_FRONT, GL_FILL);
glPolygonMode(GL_BACK, GL_LINE);
See the next secti on for more i nformati on about how to control whi ch faces are consi dered front−faci ng
and whi ch back−faci ng.
Reversing and Culling Polygon Faces
By conventi on, pol ygons whose verti ces appear i n countercl ockwi se order on the screen are cal l ed
front−faci ng. You can construct the surface of any "reasonabl e" sol i da mathemati ci an woul d cal l such
a surface an ori entabl e mani fol d (spheres, donuts, and teapots are ori entabl e; Kl ei n bottl es and Möbi us
stri ps aren’t)from pol ygons of consi stent ori entati on. I n other words, you can use al l cl ockwi se
pol ygons, or al l countercl ockwi se pol ygons. (Thi s i s essenti al l y the mathemati cal defi ni ti on of orientable
.)
Suppose you’ve consi stentl y descri bed a model of an ori entabl e surface but that you happen to have the
cl ockwi se ori entati on on the outsi de. You can swap what OpenGL consi ders the back face by usi ng the
functi on glFrontFace(), suppl yi ng the desi red ori entati on for front−faci ng pol ygons.
voi d glFrontFace(GLenum mode);
Control s how front−faci ng pol ygons are determi ned. By defaul t, modei s GL_CCW, whi ch corresponds
to a countercl ockwi se ori entati on of the ordered verti ces of a projected pol ygon i n wi ndow coordi nates.
I f modei s GL_CW, faces wi th a cl ockwi se ori entati on are consi dered front−faci ng.
Advanced
I n more techni cal terms, the deci si on of whether a face of a pol ygon i s front− or back−faci ng depends on
the si gn of the pol ygon’s area computed i n wi ndow coordi nates. One way to compute thi s area i s
where x
i
and y
i
are the x and y wi ndow coordi nates of the ith vertex of the n−vertex pol ygon and:
34
Assumi ng that GL_CCW has been speci fi ed, i f a>0, the pol ygon correspondi ng to that vertex i s
consi dered to be front−faci ng; otherwi se, i t’s back−faci ng. I f GL_CW i s speci fi ed and i f a<0, then the
correspondi ng pol ygon i s front−faci ng; otherwi se, i t’s back−faci ng.
I n a compl etel y encl osed surface constructed from pol ygons wi th a consi stent ori entati on, none of the
back−faci ng pol ygons are ever vi si bl ethey’re al ways obscured by the front−faci ng pol ygons. I n thi s
si tuati on, you can maxi mi ze drawi ng speed by havi ng OpenGL di scard pol ygons as soon as i t
determi nes that they’re back−faci ng. Si mi l arl y, i f you are i nsi de the object, onl y back−faci ng pol ygons
are vi si bl e. To i nstruct OpenGL to di scard front− or back−faci ng pol ygons, use the command
glCullFace() and enabl e cul l i ng wi th glEnable().
voi d glCullFace(GLenum mode);
I ndi cates whi ch pol ygons shoul d be di scarded (cul l ed) before they’re converted to screen coordi nates.
The mode i s ei ther GL_FRONT, GL_BACK, or GL_FRONT_AND_BACK to i ndi cate front−faci ng,
back−faci ng, or al l pol ygons. To take effect, cul l i ng must be enabl ed usi ng glEnable() wi th
GL_CULL_FACE; i t can be di sabl ed wi th glDisable() and the same argument.
Stippling Polygons
By defaul t, fi l l ed pol ygons are drawn wi th a sol i d pattern. They can al so be fi l l ed wi th a 32−bi t by
32−bi t wi ndow−al i gned sti ppl e pattern, whi ch you speci fy wi th glPolygonStipple().
voi d glPolygonStipple(const GLubyte *mask);
Defi nes the current sti ppl e pattern for fi l l ed pol ygons. The argument mask i s a poi nter to a 32×32
bi tmap that’s i nterpreted as a mask of 0s and 1s. Where a 1 appears, the correspondi ng pi xel i n the
pol ygon i s drawn, and where a 0 appears, nothi ng i s drawn. Figure 2−9 shows how a sti ppl e pattern
i s constructed from the characters i n mask. Pol ygon sti ppl i ng i s enabl ed and di sabl ed by usi ng
glEnable() and glDisable() wi th GL_POLYGON_STI PPLE as the argument. The i nterpretati on of the
mask data i s affected by the glPixelStore*() GL_UNPACK* modes. See "Controlling Pixel−Storage
Modes."
35 36
Figure 2−9 Constructi ng a Pol ygon Sti ppl e Pattern
I n addi ti on to defi ni ng the current pol ygon sti ppl i ng pattern, you must enabl e sti ppl i ng:
glEnable(GL_POLYGON_STIPPLE);
Use glDisable() wi th the same argument to di sabl e pol ygon sti ppl i ng.
Figure 2−10shows the resul ts of pol ygons drawn unsti ppl ed and then wi th two di fferent sti ppl i ng
patterns. The program i s shown i n Example 2−2. The reversal of whi te to bl ack (from Figure 2−9 to
Figure 2−10) occurs because the program draws i n whi te over a bl ack background, usi ng the pattern
i n Figure 2−9 as a stenci l .
Figure 2−10 Sti ppl ed Pol ygons
Example 2−2 Usi ng Pol ygon Sti ppl e Patterns: pol ys.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
void display(void)
{
GLubyte fly[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x80, 0x01, 0xC0, 0x06, 0xC0, 0x03, 0x60,
0x04, 0x60, 0x06, 0x20, 0x04, 0x30, 0x0C, 0x20,
0x04, 0x18, 0x18, 0x20, 0x04, 0x0C, 0x30, 0x20,
0x04, 0x06, 0x60, 0x20, 0x44, 0x03, 0xC0, 0x22,
0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22,
0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22,
0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22,
0x66, 0x01, 0x80, 0x66, 0x33, 0x01, 0x80, 0xCC,
0x19, 0x81, 0x81, 0x98, 0x0C, 0xC1, 0x83, 0x30,
0x07, 0xe1, 0x87, 0xe0, 0x03, 0x3f, 0xfc, 0xc0,
0x03, 0x31, 0x8c, 0xc0, 0x03, 0x33, 0xcc, 0xc0,
0x06, 0x64, 0x26, 0x60, 0x0c, 0xcc, 0x33, 0x30,
0x18, 0xcc, 0x33, 0x18, 0x10, 0xc4, 0x23, 0x08,
0x10, 0x63, 0xC6, 0x08, 0x10, 0x30, 0x0c, 0x08,
0x10, 0x18, 0x18, 0x08, 0x10, 0x00, 0x00, 0x08};
GLubyte halftone[] = {
37
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55};
glClear (GL_COLOR_BUFFER_BIT);
glColor3f (1.0, 1.0, 1.0);
glRectf (25.0, 25.0, 125.0, 125.0);
glEnable (GL_POLYGON_STIPPLE);
glPolygonStipple (fly);
glRectf (125.0, 25.0, 225.0, 125.0);
glPolygonStipple (halftone);
glRectf (225.0, 25.0, 325.0, 125.0);
glDisable (GL_POLYGON_STIPPLE);
glFlush ();
}
void myinit (void)
{
glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel (GL_FLAT);
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
auxInitPosition (0, 0, 350, 150);
auxInitWindow (argv[0]);
myinit ();
auxMainLoop(display);
}
As menti oned i n "Display−List Design Philosophy," you mi ght want to use di spl ay l i sts to store
pol ygon sti ppl e patterns to maxi mi ze effi ci ency.
Marking Polygon Boundary Edges
Advanced
38
OpenGL can render onl y convex pol ygons, but many nonconvex pol ygons ari se i n practi ce. To draw
these nonconvex pol ygons, you typi cal l y subdi vi de them i nto convex pol ygonsusual l y tri angl es, as
shown i n Figure 2−11and then draw the tri angl es. Unfortunatel y, i f you decompose a general
pol ygon i nto tri angl es and draw the tri angl es, you can’t real l y use glPolygonMode() to draw the
pol ygon’s outl i ne, si nce you get al l the tri angl e outl i nes i nsi de i t. To sol ve thi s probl em, you can tel l
OpenGL whether a parti cul ar vertex precedes a boundary edge; OpenGL keeps track of thi s
i nformati on by passi ng al ong wi th each vertex a bi t i ndi cati ng whether that vertex i s fol l owed by a
boundary edge. Then, when a pol ygon i s drawn i n GL_LI NE mode, the nonboundary edges aren’t
drawn. I n Figure 2−11, the dashed l i nes represent added edges.
Figure 2−11 Subdi vi di ng a Nonconvex Pol ygon
By defaul t, al l verti ces are marked as precedi ng a boundary edge, but you can manual l y control the
setti ng of the edge fl ag wi th the command glEdgeFlag*(). Thi s command i s used between glBegin() and
glEnd() pai rs, and i t affects al l the verti ces speci fi ed after i t unti l the next glEdgeFlag() cal l i s made. I t
appl i es onl y to verti ces speci fi ed for pol ygons, tri angl es, and quads, not to those speci fi ed for stri ps of
tri angl es or quads.
voi d glEdgeFlag(GLbool ean flag);
voi d glEdgeFlagv(const GLbool ean *flag);
I ndi cates whether a vertex shoul d be consi dered as i ni ti al i zi ng a boundary edge of a pol ygon. I f flagi s
GL_TRUE, the edge fl ag i s set to TRUE (the defaul t), and any verti ces created are consi dered to
precede boundary edges unti l thi s functi on i s cal l ed agai n wi th flagbei ng 0.
As an exampl e, Example 2−3 draws the outl i ne shown i n Figure 2−12.
39
Figure 2−12 An Outl i ned Pol ygon Drawn Usi ng Edge Fl ags
Example 2−3 Marki ng Pol ygon Boundary Edges
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glBegin(GL_POLYGON);
glEdgeFlag(GL_TRUE);
glVertex3fv(V0);
glEdgeFlag(GL_FALSE);
glVertex3fv(V1);
glEdgeFlag(GL_TRUE);
glVertex3fv(V2);
glEnd();
Normal Vectors
A normal vector (or normal , for short) i s a vector that poi nts i n a di recti on that’s perpendi cul ar to a
surface. For a fl at surface, one perpendi cul ar di recti on suffi ces for every poi nt on the surface, but for a
general curved surface, the normal di recti on mi ght be di fferent at each poi nt. Wi th OpenGL, you can
speci fy a normal for each vertex. Verti ces mi ght share the same normal , but you can’t assi gn normal s
anywhere other than at the verti ces.
An object’s normal vectors defi ne the ori entati on of i ts surface i n spacei n parti cul ar, i ts ori entati on
rel ati ve to l i ght sources. These vectors are used by OpenGL to determi ne how much l i ght the object
recei ves at i ts verti ces. Li ghti nga l arge topi c by i tsel fi s the subject of Chapter 6 , and you mi ght
40
want to revi ew the fol l owi ng i nformati on after you’ve read that chapter. Normal vectors are di scussed
bri efl y here because you general l y defi ne normal vectors for an object at the same ti me you defi ne the
object’s geometry.
You use glNormal*() to set the current normal to the val ue of the argument passed i n. Subsequent cal l s
to glVertex*() cause the speci fi ed verti ces to be assi gned the current normal . Often, each vertex has a
di fferent normal , whi ch necessi tates a seri es of al ternati ng cal l s l i ke thi s:
glBegin (GL_POLYGON);
glNormal3fv(n0);
glVertex3fv(v0);
glNormal3fv(n1);
glVertex3fv(v1);
glNormal3fv(n2);
glVertex3fv(v2);
glNormal3fv(n3);
glVertex3fv(v3);
glEnd();
voi d glNormal3{bsi df}(TYPEnx, TYPEny, TYPEnz);
voi d glNormal3{bsi df}v(const TYPE *v);
Sets the current normal vector as speci fi ed by the arguments. The nonvector versi on (wi thout the v)
takes three arguments, whi ch speci fy an (nx, ny, nz) vector that’s taken to be the normal . Al ternati vel y,
you can use the vector versi on of thi s functi on (wi th the v) and suppl y a si ngl e array of three el ements
to speci fy the desi red normal . The b, s, and i versi ons scal e thei r parameter val ues l i nearl y to the range
[−1.0,1.0].
There’s no magi c to fi ndi ng the normal s for an objectmost l i kel y, you have to perform some
cal cul ati ons that mi ght i ncl ude taki ng deri vati vesbut there are several techni ques and tri cks you can
use to achi eve certai n effects. Appendix F expl ai ns how to fi nd normal vectors for surfaces. I f you
al ready know how to do thi s, i f you can count on al ways bei ng suppl i ed wi th normal vectors, or i f you
don’t want to use OpenGL’s l i ghti ng faci l i ty, you don’t need to read thi s appendi x.
Note that at a gi ven poi nt on a surface, two vectors are perpendi cul ar to the surface, and they poi nt i n
opposi te di recti ons. By conventi on, the normal i s the one that poi nts to the outsi de of the surface bei ng
model ed. (I f you get i nsi de and outsi de reversed i n your model , just change every normal vector from (x,
y, z) to (−x, −y, −z)).
Al so, keep i n mi nd that si nce normal vectors i ndi cate di recti on onl y, thei r l ength i s mostl y i rrel evant.
You can speci fy normal s of any l ength, but eventual l y they have to be converted to havi ng a l ength of 1
before l i ghti ng cal cul ati ons are performed. (A vector that has a l ength of 1 i s sai d to be of uni t l ength, or
normal i zed.) I n general , then, you shoul d suppl y normal i zed normal vectors. These vectors remai n
normal i zed as l ong as your model transformati ons i ncl ude onl y rotati ons and transl ati ons.
(Transformati ons are di scussed i n detai l i n Chapter 3 .) I f you perform i rregul ar transformati ons
(such as scal i ng or mul ti pl yi ng by a shear matri x), or i f you speci fy nonuni t−l ength normal s, then you
shoul d have OpenGL automati cal l y normal i ze your normal vectors after the transformati ons. To do
thi s, cal l glEnable() wi th GL_NORMALI ZE as i ts argument. By defaul t, automati c normal i zati on i s
di sabl ed. Note that i n some i mpl ementati ons of OpenGL, automati c normal i zati on requi res addi ti onal
cal cul ati ons that mi ght reduce the performance of your appl i cati on.
Some Hints for Building Polygonal Models of Surfaces
Fol l owi ng are some techni ques that you mi ght want to use as you bui l d pol ygonal approxi mati ons of
surfaces. You mi ght want to revi ew thi s secti on after you’ve read Chapter 6 on l i ghti ng and Chapter
4 on di spl ay l i sts. The l i ghti ng condi ti ons affect how model s l ook once they’re drawn, and some of the
fol l owi ng techni ques are much more effi ci ent when used i n conjuncti on wi th di spl ay l i sts. As you read
41
these techni ques, keep i n mi nd that when l i ghti ng cal cul ati ons are enabl ed, normal vectors must be
speci fi ed to get proper resul ts.
Constructi ng pol ygonal approxi mati ons to surfaces i s an art, and there i s no substi tute for experi ence.
Thi s secti on, however, l i sts a few poi nters that mi ght make i t a bi t easi er to get started.
• Keep pol ygon ori entati ons consi stent. Make sure that when vi ewed from the outsi de, al l the
pol ygons on the surface are ori ented i n the same di recti on (al l cl ockwi se or al l countercl ockwi se).
Try to get thi s ri ght the fi rst ti me, si nce i t’s excruci ati ngl y pai nful to fi x the probl em l ater.
• When you subdi vi de a surface, watch out for any nontri angul ar pol ygons. The three verti ces of a
tri angl e are guaranteed to l i e on a pl ane; any pol ygon wi th four or more verti ces mi ght not.
Nonpl anar pol ygons can be vi ewed from some ori entati on such that the edges cross each other, and
OpenGL mi ght not render such pol ygons correctl y.
• There’s al ways a trade−off between the di spl ay speed and the qual i ty of the i mage. I f you subdi vi de
a surface i nto a smal l number of pol ygons, i t renders qui ckl y but mi ght have a jagged appearance;
i f you subdi vi de i t i nto mi l l i ons of ti ny pol ygons, i t probabl y l ooks good but mi ght take a l ong ti me
to render. I deal l y, you can provi de a parameter to the subdi vi si on routi nes that i ndi cates how fi ne a
subdi vi si on you want, and i f the object i s farther from the eye, you can use a coarser subdi vi si on.
Al so, when you subdi vi de, use rel ati vel y l arge pol ygons where the surface i s rel ati vel y fl at, and
smal l pol ygons i n regi ons of hi gh curvature.
• For hi gh−qual i ty i mages, i t’s a good i dea to subdi vi de more on the si l houette edges than i n the
i nteri or. I f the surface i s to be rotated rel ati ve to the eye, thi s i s tougher to do, si nce the si l houette
edges keep movi ng. Si l houette edges occur where the normal vectors are perpendi cul ar to the vector
from the surface to the vi ewpoi ntthat i s, when thei r vector dot product i s zero. Your subdi vi si on
al gori thm mi ght choose to subdi vi de more i f thi s dot product i s near zero.
• Try to avoi d T−i ntersecti ons i n your model s (see Figure 2−13). As shown, there’s no guarantee
that the l i ne segments AB and BC l i e on exactl y the same pi xel s as the segment AC. Someti mes
they do, and someti mes they don’t, dependi ng on the transformati ons and ori entati on. Thi s can
cause cracks to appear i ntermi ttentl y i n the surface.
Figure 2−13 Modi fyi ng an Undesi rabl e T−i ntersecti on
• I f you’re constructi ng a cl osed surface, make sure to use exactl y the same numbers for coordi nates
at the begi nni ng and end of a cl osed l oop, or you can get gaps and cracks due to numeri cal
round−off. Here’s a two−di mensi onal exampl e of bad code:
/* don’t use this code */
#define PI 3.14159265
#define EDGES 30
/* draw a circle */
for (i = 0; i < EDGES; i++) {
glBegin(GL_LINE_STRIP);
42
glVertex2f(cos((2*PI*i)/EDGES), sin((2*PI*i)/EDGES);
glVertex2f(cos((2*PI*(i+1))/EDGES),
sin((2*PI*(i+1))/EDGES);
glEnd();
}
The edges meet exactl y onl y i f your machi ne manages to cal cul ate the si ne and cosi ne of 0 and of
(2*PI *EDGES/EDGES) and gets exactl y the same val ues. I f you trust the fl oati ng−poi nt uni t on
your machi ne to do thi s ri ght, the authors have a bri dge they’d l i ke to sel l you.... To correct the
code, make sure that when i == EDGES−1, you use 0 for the si ne and cosi ne, not
2*PI *EDGES/EDGES.
• Fi nal l y, note that unl ess tessel l ati on i s very fi ne, any change i s l i kel y to be vi si bl e. I n some
ani mati ons, these changes are more vi sual l y di sturbi ng than the arti facts of undertessel l ati on.
An Example: Building an Icosahedron
To i l l ustrate some of the consi derati ons that ari se i n approxi mati ng a surface, l et’s l ook at some
exampl e code sequences. Thi s code concerns the verti ces of a regul ar i cosahedron (whi ch i s a Pl atoni c
sol i d composed of twenty faces that span twel ve verti ces, each face of whi ch i s an equi l ateral tri angl e).
An i cosahedron can be consi dered a rough approxi mati on for a sphere. Example 2−4 defi nes the
verti ces and tri angl es maki ng up an i cosahedron and then draws the i cosahedron.
Example 2−4 Drawi ng an I cosahedron
#define X .525731112119133606
#define Z .850650808352039932
static GLfloat vdata[12][3] = {
{−X, 0.0, Z}, {X, 0.0, Z}, {−X, 0.0, −Z}, {X, 0.0, −Z},
{0.0, Z, X}, {0.0, Z, −X}, {0.0, −Z, X}, {0.0, −Z, −X},
{Z, X, 0.0}, {−Z, X, 0.0}, {Z, −X, 0.0}, {−Z, −X, 0.0}
};
static GLint tindices[20][3] = {
{0,4,1}, {0,9,4}, {9,5,4}, {4,5,8}, {4,8,1},
{8,10,1}, {8,3,10}, {5,3,8}, {5,2,3}, {2,7,3},
{7,10,3}, {7,6,10}, {7,11,6}, {11,0,6}, {0,1,6},
{6,1,10}, {9,0,11}, {9,11,2}, {9,2,5}, {7,2,11} };
for (i = 0; i < 20; i++) {
/* color information here */
glBegin(GL_TRIANGLE);
glVertex3fv(&vdata[tindices[i][0]][0]);
glVertex3fv(&vdata[tindices[i][1]][0]);
glVertex3fv(&vdata[tindices[i][2]][0]);
glEnd();
}
The strange numbers X and Z are chosen so that the di stance from the ori gi n to any of the verti ces of
the i cosahedron i s 1.0. The coordi nates of the twel ve verti ces are gi ven i n the array vdata[][], where the
zeroth vertex i s {−X, 0.0, Z}, the fi rst i s {X, 0.0, Z}, and so on. The array tindices[][] tel l s how to l i nk the
verti ces to make tri angl es. For exampl e, the fi rst tri angl e i s made from the zeroth, fourth, and fi rst
vertex. I f you take the verti ces for tri angl es i n the order gi ven, al l the tri angl es have the same
ori entati on.
The l i ne that menti ons col or i nformati on shoul d be repl aced by a command that sets the col or of the ith
43
face. I f no code appears here, al l faces are drawn i n the same col or, and i t’l l be i mpossi bl e to di scern the
three−di mensi onal qual i ty of the object. An al ternati ve to expl i ci tl y speci fyi ng col ors i s to defi ne surface
normal s and use l i ghti ng, as descri bed i n the next secti on.
Note: I n al l the exampl es descri bed i n thi s secti on, unl ess the surface i s to be drawn onl y once, you
shoul d probabl y save the cal cul ated vertex and normal coordi nates so that the cal cul ati ons
don’t need to be repeated each ti me that the surface i s drawn. Thi s can be done usi ng your own
data structures or by constructi ng di spl ay l i sts (see Chapter 4 .)
Defining the Icosahedron’s Normals
I f the i cosahedron i s to be l i t, you need to suppl y the vector normal to the surface. Wi th the fl at surfaces
of an i cosahedron, al l three verti ces defi ni ng a surface have the same normal vector. Thus, the normal
needs to be speci fi ed onl y once for each set of three verti ces. The code i n Example 2−5 can repl ace the
"col or i nformati on here" l i ne i n Example 2−4 for drawi ng the i cosahedron.
Example 2−5 Suppl yi ng Normal s for an I cosahedron
GLfloat d1[3], d2[3], norm[3];
for (j = 0; j < 3; j++) {
d1[j] = vdata[tindices[i][0]][j] − vdata[tindices[i][1]][j];
d2[j] = vdata[tindices[i][1]][j] − vdata[tindices[i][2]][j];
}
normcrossprod(d1, d2, norm);
glNormal3fv(norm);
The functi on normcrossprod() produces the normal i zed cross product of two vectors, as shown i n
Example 2−6.
Example 2−6 Cal cul ati ng the Normal i zed Cross Product of Two Vectors
void normalize(float v[3]) {
GLfloat d = sqrt(v[1]*v[1]+v[2]*v[2]+v[3]*v[3]);
if (d == 0.0) {
error("zero length vector");
return;
}
v[1] /= d; v[2] /= d; v[3] /= d;
}
void normcrossprod(float v1[3], float v2[3], float out[3])
{
GLint i, j;
GLfloat length;
out[0] = v1[1]*v2[2] − v1[2]*v2[1];
out[1] = v1[2]*v2[0] − v1[0]*v2[2];
out[2] = v1[0]*v2[1] − v1[1]*v2[0];
normalize(out);
}
I f you’re usi ng an i cosahedron as an approxi mati on for a shaded sphere, you’l l want to use normal
vectors that are perpendi cul ar to the true surface of the sphere, rather than bei ng perpendi cul ar to the
faces. For a sphere, the normal vectors are si mpl e; each poi nts i n the same di recti on as the vector from
the ori gi n to the correspondi ng vertex. Si nce the i cosahedron vertex data i s for an i cosahedron of radi us
1, the normal and vertex data i s i denti cal . Here i s the code that woul d draw an i cosahedral
44
approxi mati on of a smoothl y shaded sphere (assumi ng that l i ghti ng i s enabl ed, as descri bed i n
Chapter 6 ):
for (i = 0; i < 20; i++) {
glBegin(GL_POLYGON);
glNormal3fv(&vdata[tindices[i][0]][0]);
glVertex3fv(&vdata[tindices[i][0]][0]);
glNormal3fv(&vdata[tindices[i][1]][0]);
glVertex3fv(&vdata[tindices[i][1]][0]);
glNormal3fv(&vdata[tindices[i][2]][0]);
glVertex3fv(&vdata[tindices[i][2]][0]);
glEnd();
}
Improving the Model
A twenty−si ded approxi mati on to a sphere doesn’t l ook good unl ess the i mage of the sphere on the
screen i s qui te smal l , but there’s an easy way to i ncrease the accuracy of the approxi mati on. I magi ne
the i cosahedron i nscri bed i n a sphere, and subdi vi de the tri angl es as shown i n Figure 2−14. The
newl y i ntroduced verti ces l i e sl i ghtl y i nsi de the sphere, so push them to the surface by normal i zi ng
them (di vi di ng them by a factor to make them have l ength 1). Thi s subdi vi si on process can be repeated
for arbi trary accuracy. The three objects shown i n Figure 2−14 use twenty, ei ghty, and three hundred
and twenty approxi mati ng tri angl es, respecti vel y.
Figure 2−14 Subdi vi di ng to I mprove a Pol ygonal Approxi mati on to a Surface
Example 2−7performs a si ngl e subdi vi si on, creati ng an ei ghty−si ded spheri cal approxi mati on.
Example 2−7 Si ngl e Subdi vi si on
void drawtriangle(float *v1, float *v2, float *v3)
{
glBegin(GL_POLYGON);
glNormal3fv(v1); vlVertex3fv(v1);
glNormal3fv(v2); vlVertex3fv(v2);
glNormal3fv(v3); vlVertex3fv(v3);
glEnd();
}
45
void subdivide(float *v1, float *v2, float *v3)
{
GLfloat v12[3], v23[3], v31[3];
GLint i;
for (i = 0; i < 3; i++) {
v12[i] = v1[i]+v2[i];
v23[i] = v2[i]+v3[i];
v31[i] = v3[i]+v1[i];
}
normalize(v12);
normalize(v23);
normalize(v31);
drawtriangle(v1, v12, v31);
drawtriangle(v2, v23, v12);
drawtriangle(v3, v31, v23);
drawtriangle(v12, v23, v31);
}
for (i = 0; i < 20; i++) {
subdivide(&vdata[tindices[i][0]][0],
&vdata[tindices[i][1]][0],
&vdata[tindices[i][2]][0]);
}
Example 2−8i s a sl i ght modi fi cati on of Example 2−7 that recursi vel y subdi vi des the tri angl es to the
proper depth. I f the depth val ue i s 0, no subdi vi si ons are performed, and the tri angl e i s drawn as i s. I f
the depth i s 1, a si ngl e subdi vi son i s performed, and so on.
Example 2−8 Recursi ve Subdi vi si on
void subdivide(float *v1, float *v2, float *v3, long depth)
{
GLfloat v12[3], v23[3], v31[3];
GLint i;
if (depth == 0) {
drawtriangle(v1, v2, v3);
return;
}
for (i = 0; i < 3; i++) {
v12[i] = v1[i]+v2[i];
v23[i] = v2[i]+v3[i];
v31[i] = v3[i]+v1[i];
}
normalize(v12);
normalize(v23);
normalize(v31);
subdivide(v1, v12, v31, depth−1);
subdivide(v2, v23, v12, depth−1);
subdivide(v3, v31, v23, depth−1);
subdivide(v12, v23, v31, depth−1);
}
46
Generalized Subdivision
A recursi ve subdi vi si on techni que such as the one descri bed i n Example 2−8 can be used for other
types of surfaces. Typi cal l y, the recursi on ends ei ther i f a certai n depth i s reached, or i f some condi ti on
on the curvature i s sati sfi ed (hi ghl y curved parts of surfaces l ook better wi th more subdi vi si on).
To l ook at a more general sol uti on to the probl em of subdi vi si on, consi der an arbi trary surface
parameteri zed by two vari abl es u[0] and u[1]. Suppose that two routi nes are provi ded:
void surf(GLfloat u[2], GLfloat vertex[3], GLfloat normal[3]);
float curv(GLfloat u[2]);
I f surf() i s passed u[], the correspondi ng three−di mensi onal vertex and normal vectors (of l ength 1) are
returned. I f u[] i s passed to curv(), the curvature of the surface at that poi nt i s cal cul ated and returned.
(See an i ntroductory textbook on di fferenti al geometry for more i nformati on about measuri ng surface
curvature.)
Example 2−9shows the recursi ve routi ne that subdi vi des a tri angl e ei ther unti l the maxi mum depth i s
reached or unti l the maxi mum curvature at the three verti ces i s l ess than some cutoff.
Example 2−9 General i zed Subdi vi si on
void subdivide(float u1[2], float u2[2], float u3[2],
float cutoff, long depth)
{
GLfloat v1[3], v2[3], v3[3], n1[3], n2[3], n3[3];
GLfloat u12[2], u23[2], u32[2];
GLint i;
if (depth == maxdepth || (curv(u1) < cutoff &&
curv(u2) < cutoff && curv(u3) < cutoff)) {
surf(u1, v1, n1); surf(u2, v2, n2); surf(u3, v3, n3);
glBegin(GL_POLYGON);
glNormal3fv(n1); glVertex3fv(v1);
glNormal3fv(n2); glVertex3fv(v2);
glNormal3fv(n3); glVertex3fv(v3);
glEnd();
return;
}
for (i = 0; i < 2; i++) {
u12[i] = (u1[i] + u2[i])/2.0;
u23[i] = (u2[i] + u3[i])/2.0;
u31[i] = (u3[i] + u1[i])/2.0;
}
subdivide(u1, u12, u31, cutoff, depth+1);
subdivide(u2, u23, u12, cutoff, depth+1);
subdivide(u3, u31, u23, cutoff, depth+1);
subdivide(u12, u23, u31, cutoff, depth+1);
}
Chapter 3
Viewing
Chapter Objectives
After readi ng thi s chapter, you’l l be abl e to do the fol l owi ng:
47
• Vi ew a geometri c model i n any ori entati on by transformi ng i t i n three−di mensi onal space
• Control the l ocati on i n three−di mensi onal space from whi ch the model i s vi ewed
• Cl i p undesi red porti ons of the model out of the scene that’s to be vi ewed
• Mani pul ate the appropri ate matri x stacks that control model transformati on for vi ewi ng and
project the model onto the screen
• Combi ne mul ti pl e transformati ons to mi mi c sophi sti cated systems i n moti on, such as a sol ar
system or an arti cul ated robot arm
Chapter 2 expl ai ned how to i nstruct OpenGL to draw the geometri c model s you want di spl ayed i n
your scene. Now you must deci de how you want to posi ti on the model s i n the scene, and you must
choose a vantage poi nt from whi ch to vi ew the scene. You can use the defaul t posi ti oni ng and vantage
poi nt, but most l i kel y you want to speci fy them.
Look at the i mage on the cover of thi s book. The program that produced that i mage contai ned a si ngl e
geometri c descri pti on of a bui l di ng bl ock. Each bl ock was careful l y posi ti oned i n the scene: Some bl ocks
were scattered on the fl oor, some were stacked on top of each other on the tabl e, and some were
assembl ed to make the gl obe. Al so, a parti cul ar vi ewpoi nt had to be chosen. Obvi ousl y, we wanted to
l ook at the corner of the room contai ni ng the gl obe. But how far away from the sceneand where
exactl yshoul d the vi ewer be? We wanted to make sure that the fi nal i mage of the scene contai ned a
good vi ew out the wi ndow, that a porti on of the fl oor was vi si bl e, and that al l the objects i n the scene
were not onl y vi si bl e but presented i n an i nteresti ng arrangement. Thi s chapter expl ai ns how to use
OpenGL to accompl i sh these tasks: how to posi ti on and ori ent model s i n three−di mensi onal space and
how to establ i sh the l ocati onal so i n three−di mensi onal spaceof the vi ewpoi nt. Al l of these factors
hel p determi ne exactl y what i mage appears on the sceen.
You want to remember that the poi nt of computer graphi cs i s to create a two−di mensi onal i mage of
three−di mensi onal objects (i t has to be two−di mensi onal because i t’s drawn on the screen), but you
need to thi nk i n three−di mensi onal coordi nates whi l e maki ng many of the deci si ons that determi ne
what gets drawn on the screen. A common mi stake peopl e make when creati ng three−di mensi onal
graphi cs i s to start thi nki ng too soon that the fi nal i mage appears on a fl at, two−di mensi onal screen.
Avoi d thi nki ng about whi ch pi xel s need to be drawn, and i nstead try to vi sual i ze three−di mensi onal
space. Create your model s i n some three−di mensi onal uni verse that l i es deep i nsi de your computer,
and l et the computer do i ts job of cal cul ati ng whi ch pi xel s to col or.
A seri es of three computer operati ons convert an object’s three−di mensi onal coordi nates to pi xel
posi ti ons on the screen:
• Transformati ons, whi ch are represented by matri x mul ti pl i cati on, i ncl ude model i ng, vi ewi ng, and
projecti on operati ons. Such operati ons i ncl ude rotati on, transl ati on, scal i ng, refl ecti ng,
orthographi c projecti on, and perspecti ve projecti on. General l y, you use a combi nati on of several
transformati ons to draw a scene.
• Si nce the scene i s rendered on a rectangul ar wi ndow, objects (or parts of objects) that l i e outsi de
the wi ndow must be cl i pped. I n three−di mensi onal computer graphi cs, cl i ppi ng occurs by throwi ng
out objects on one si de of a cl i ppi ng pl ane.
• Fi nal l y, a correspondence must be establ i shed between the transformed coordi nates and screen
pi xel s. Thi s i s known as a viewport transformati on.
Thi s chapter descri bes al l of these operati ons, and how to control them, i n the fol l owi ng major secti ons:
• "Overview: The Camera Analogy"gi ves an overvi ew of the transformati on process by descri bi ng
the anal ogy of taki ng a photograph wi th a camera, presents a si mpl e exampl e program that
transforms an object, and bri efl y descri bes the basi c OpenGL transformati on commands.
• "Viewing and Modeling Transformations"expl ai ns i n detai l how to speci fy and to i magi ne the
effect of vi ewi ng and model i ng transformati ons. These transformati ons ori ent the model and the
camera rel ati ve to each other to obtai n the desi red fi nal i mage.
• "Projection Transformations"descri bes how to speci fy the shape and ori entati on of the viewing
volume. The vi ewi ng vol ume determi nes how a scene i s projected onto the screen (wi th a
perspecti ve or orthographi c projecti on) and whi ch objects or parts of objects are cl i pped out of the
scene.
48
• "Viewport Transformation"expl ai ns how to control the conversi on of three−di mensi onal model
coordi nates to screen coordi nates.
• "Troubleshooting Transformations"presents some ti ps for di scoveri ng why you mi ght not be
getti ng the desi red effect from your model i ng, vi ewi ng, projecti on, and vi ewport transformati ons.
• "Manipulating the Matrix Stacks"di scusses how to save and restore certai n transformati ons.
Thi s i s parti cul arl y useful when you’re drawi ng compl i cated objects that are bui l t up from si mpl er
ones.
• "Additional Clipping Planes"descri bes how to speci fy addi ti onal cl i ppi ng pl anes beyond those
defi ned by the vi ewi ng vol ume.
• "Examples of Composing Several Transformations"wal ks you through a coupl e of more
compl i cated uses for transformati ons.
Overview: The Camera Analogy
The transformati on process to produce the desi red scene for vi ewi ng i s anal ogous to taki ng a
photograph wi th a camera. As shown i n Figure 3−1 , the steps wi th a camera (or a computer) mi ght be
the fol l owi ng:
1. Setti ng up your tri pod and poi nti ng the camera at the scene (vi ewi ng transformati on).
2. Arrangi ng the scene to be photographed i nto the desi red composi ti on (model i ng transformati on).
3. Choosi ng a camera l ens or adjusti ng the zoom (projecti on transformati on).
4. Determi ni ng how l arge you want the fi nal photograph to befor exampl e, you mi ght want i t
enl arged (vi ewport transformati on).
After these steps are performed, the pi cture can be snapped, or the scene can be drawn.
49 50
Figure 3−1 The Camera Anal ogy
Note that these steps correspond to the order i n whi ch you speci fy the desi red transformati ons i n your
program, not necessari l y the order i n whi ch the rel evant mathemati cal operati ons are performed on an
object’s verti ces. The vi ewi ng transformati ons must precede the model i ng transformati ons i n your code,
but you can speci fy the projecti on and vi ewport transformati ons at any poi nt before drawi ng occurs.
Figure 3−2 shows the order i n whi ch these operati ons occur on your computer.
Figure 3−2 Stages of Vertex Transformati on
To speci fy vi ewi ng, model i ng, and projecti on transformati ons, you construct a 4×4 matri x M, whi ch i s
then mul ti pl i ed by the coordi nates of each vertex v i n the scene to accompl i sh the transformati on
v’=Mv
(Remember that verti ces al ways have four coordi nates (x ,y, z, w), though i n most cases w i s 1 and for
two−di mensi onal data z i s 0.) Note that vi ewi ng and model i ng transformati ons are automati cal l y
appl i ed to surface normal vectors, i n addi ti on to verti ces. (Normal vectors are used onl y i n eye
coordi nates.) Thi s ensures that the normal vector’s rel ati onshi p to the vertex data i s properl y
preserved.
The vi ewi ng and model i ng transformati ons you speci fy are combi ned to form the model vi ew matri x,
whi ch i s appl i ed to the i ncomi ng object coordi nates to yi el d eye coordi nates. Next, i f you’ve speci fi ed
arbi trary cl i ppi ng pl anes to remove certai n objects from the scene or to provi de cutaway vi ews of
objects, these cl i ppi ng pl anes are appl i ed.
After that, OpenGL appl i es the projecti on matri x to yi el d clip coordinates. Thi s transformati on defi nes
a vi ewi ng vol ume; objects outsi de thi s vol ume are cl i pped so that they’re not drawn i n the fi nal scene.
After thi s poi nt, the perspecti ve di vi si on i s performed by di vi di ng coordi nate val ues by w, to produce
normalized devicecoordinates. (See Appendix G for more i nformati on about the meani ng of the w
coordi nate and how i t affects matri x transformati ons.) Fi nal l y, the transformed coordi nates are
converted to wi ndow coordi nates by appl yi ng the vi ewport transformati on. You can mani pul ate the
di mensi ons of the vi ewport to cause the fi nal i mage to be enl arged, shrunk, or stretched.
You mi ght correctl y suppose that the x and y coordi nates are suffi ci ent to determi ne whi ch pi xel s need
to be drawn on the screen. However, al l the transformati ons are performed on the z coordi nates as wel l .
Thi s way, at the end of thi s transformati on process, the z val ues correctl y refl ect the depth of a gi ven
vertex (measured i n di stance away from the screen). One use for thi s depth val ue i s to el i mi nate
unnecessary drawi ng. For exampl e, suppose two verti ces have the same x and y val ues but di fferent z
51
val ues. OpenGL can use thi s i nformati on to determi ne whi ch surfaces are obscured by other surfaces
and can then avoi d drawi ng the hi dden surfaces. (See Chapter 10 for more i nformati on about thi s
techni que, whi ch i s cal l ed hidden−surfaceremoval.)
As you’ve probabl y guessed by now, you need to know a few thi ngs about matri x mathemati cs to get the
most out of thi s chapter. I f you want to brush up on your knowl edge i n thi s area, you mi ght consul t a
textbook on l i near al gebra.
A Simple Example: Drawing a Cube
Example 3−1draws a cube that’s scal ed by a model i ng transformati on (see Figure 3−3 ). The vi ewi ng
transformati on used i s a si mpl e transl ati on down the z−axi s. A projecti on transformati on and a
vi ewport transformati on are al so speci fi ed. The rest of thi s secti on wal ks you through Example 3−1
and bri efl y expl ai ns the transformati on commands i t uses. The succeedi ng secti ons contai n the
compl ete, detai l ed di scussi on of al l OpenGL’s transformati on commands.
Figure 3−3 A Transformed Cube
Example 3−1 A Transformed Cube: cube.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
void display (void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f (1.0, 1.0, 1.0);
glLoadIdentity (); /* clear the matrix */
glTranslatef (0.0, 0.0, −5.0); /* viewing transformation */
glScalef (1.0, 2.0, 1.0); /* modeling transformation */
auxWireCube(1.0); /* draw the cube */
glFlush();
}
void myinit (void)
{
glShadeModel (GL_FLAT);
}
void myReshape(GLsizei w, GLsizei h)
{
glMatrixMode (GL_PROJECTION); /* prepare for and then */
glLoadIdentity (); /* define the projection */
52
glFrustum (−1.0, 1.0, −1.0, 1.0, /* transformation */
1.5, 20.0);
glMatrixMode (GL_MODELVIEW); /* back to modelview matrix */
glViewport (0, 0, w, h); /* define the viewport */
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
auxInitPosition (0, 0, 500, 500);
auxInitWindow (argv[0]);
myinit ();
auxReshapeFunc (myReshape);
auxMainLoop(display);
}
The Viewing Transformation
Recal l that the vi ewi ng transformati on i s anal ogous to posi ti oni ng and ai mi ng a camera. I n thi s code
exampl e, before the vi ewi ng transformati on can be speci fi ed, the current matri x i s set to the i denti ty
matri x wi th glLoadI dentity(). Thi s step i s necessary si nce most of the transformati on commands
mul ti pl y the current matri x by the speci fi ed matri x and then set the resul t to be the current matri x. I f
you don’t cl ear the current matri x by l oadi ng i t wi th the i denti ty matri x, you conti nue to combi ne
previ ous transformati on matri ces wi th the new one you suppl y. I n some cases, you do want to perform
such combi nati ons, but you al so need to cl ear the matri x someti mes.
Once the matri x i s i ni ti al i zed, the vi ewi ng transformati on i s speci fi ed wi th glTranslatef(). The
arguments for thi s command i ndi cate how the camera shoul d be transl ated (moved) i n the x, y, and z
di recti ons. The arguments used here move the camera 5 uni ts i n the negati ve z di recti on. By defaul t,
the camera as wel l as any objects i n the scene are ori gi nal l y si tuated at the ori gi n; al so, the camera
i ni ti al l y poi nts down the negati ve z−axi s. Thus, the parti cul ar vi ewi ng transformati on used here has
the effect of pul l i ng the camera away from where the cube i s, but i t l eaves the camera poi nti ng at the
object. I f the camera needed to be poi nted i n another di recti on, you coul d have used the glRotatef()
command to change i ts ori entati on. Vi ewi ng transformati ons are di scussed i n detai l i n "Viewing and
Modeling Transformations."
The Modeling Transformation
You use the model i ng transformati on to posi ti on and ori ent the model . For exampl e, you can rotate,
transl ate, or scal e the model or perform some combi nati on of these operati ons. Rotati ng and
transl ati ng are performed usi ng the commands al ready menti onedglRotatef() and glTranslatef(). I n
thi s exampl e, however, the model i ng transformati on i s i nvoked wi th glScalef(). The arguments for thi s
command speci fy how scal i ng shoul d occur al ong the three axes. I f al l the arguments are 1.0, thi s
command has no effect; i n Example 3−1, the cube i s drawn twi ce as l arge i n the y di recti on. Thus, i f
one corner of the cube had ori gi nal l y been at (3.0, 3.0, 3.0), that corner woul d wi nd up bei ng drawn at
(3.0, 6.0, 3.0). The effect of thi s model i ng transformati on i s to transform the cube so that i t i sn’t a cube
but a rectangul ar box.
Note that i nstead of pul l i ng the camera back away from the cube (wi th a vi ewi ng transformati on) so
that i t coul d be vi ewed, you coul d have moved the cube away from the camera (wi th a model i ng
transformati on). Thi s dual i ty i n the nature of vi ewi ng and model i ng transformati ons i s why you need to
thi nk about the effect of both types of transformati ons si mul taneousl y. I t doesn’t make sense to try to
separate the effects, but someti mes i t’s easi er to thi nk about them one way rather than the other. Thi s
i s al so why model i ng and vi ewi ng transformati ons are combi ned i nto the model vi ew matri x before the
53
transformati ons are appl i ed. "Viewing and Modeling Transformations," expl ai ns i n more detai l
how to thi nk about model i ng and vi ewi ng transformati ons and how to speci fy them so that you get the
resul t you want.
Al so note that the model i ng and vi ewi ng transformati ons are i ncl uded i n the display() routi ne, al ong
wi th the cal l that’s used to draw the cube, auxWireCube(). Thi s way, display() can be used repeatedl y to
draw the contents of the wi ndow i f, for exampl e, the wi ndow i s moved or uncovered, and you’ve ensured
that each ti me, the cube i s drawn i n the desi red way, wi th the appropri ate transformati ons. The
potenti al repeated use of display() underscores the need to l oad the i denti ty matri x before performi ng
the vi ewi ng and model i ng transformati ons, especi al l y when other transformati ons mi ght be performed
between cal l s to display().
The Projection Transformation
Speci fyi ng the projecti on transformati on i s l i ke choosi ng a l ens for a camera. You can thi nk of thi s
transformati on as determi ni ng what the fi el d of vi ew or vi ewi ng vol ume i s and therefore what objects
are i nsi de i t and to some extent how they l ook. Thi s i s equi val ent to choosi ng among wi de−angl e,
normal , and tel ephoto l enses, for exampl e. Wi th a wi de−angl e l ens, you can i ncl ude a wi der scene i n the
fi nal photograph than wi th a tel ephoto l ens, but a tel ephoto l ens al l ows you to photograph objects as
though they’re cl oser to you than they actual l y are. I n computer graphi cs, you don’t have to pay $10,000
for a 2000−mi l l i meter tel ephoto l ens; once you’ve bought your graphi cs workstati on, al l you need to do
i s use a smal l er number for your fi el d of vi ew.
I n addi ti on to the fi el d−of−vi ew consi derati ons, the projecti on transformati on determi nes how objects
are projected onto the screen, as i ts name suggests. Two basi c types of projecti ons are provi ded for you
by OpenGL, al ong wi th several correspondi ng commands for descri bi ng the rel evant parameters i n
di fferent ways. One type i s the perspectiveprojecti on, whi ch matches how you see thi ngs i n dai l y l i fe.
Perspecti ve makes objects that are farther away appear smal l er; for exampl e, i t makes rai l road tracks
appear to converge i n the di stance. I f you’re tryi ng to make real i sti c pi ctures, you’l l want to choose
perspecti ve projecti on, whi ch i s speci fi ed wi th the glFrustum() command i n thi s code exampl e.
The other type of projecti on i s orthographi c, whi ch maps objects di rectl y onto the screen wi thout
affecti ng thei r rel ati ve si ze. Orthographi c projecti on i s used i n archi tectural and computer−ai ded
desi gn appl i cati ons where the fi nal i mage needs to refl ect the measurements of objects rather than how
they mi ght l ook. Archi tects create perspecti ve drawi ngs to show how parti cul ar bui l di ngs or i nteri or
spaces l ook when vi ewed from vari ous vantage poi nts; the need for orthographi c projecti on ari ses when
bl uepri nt pl ans or el evati ons are generated, whi ch are used i n the constructi on of bui l di ngs.
"Projection Transformations," di scusses the ways to speci fy both ki nds of projecti on
transformati ons i n more detai l .
Before glFrustum() can be cal l ed to set the projecti on transformati on, some preparati on needs to
happen. As shown i n the myReshape() routi ne i n Example 3−1, the command cal l ed glMatrixMode() i s
used fi rst, wi th the argument GL_PROJECTI ON. Thi s i ndi cates that the current matri x speci fi es the
projecti on transformati on; the fol l owi ng transformati on cal l s then affect the projecti on matri x. As you
can see, a few l i nes l ater glMatrixMode() i s cal l ed agai n, thi s ti me wi th GL_MODELVI EW as the
argument. Thi s i ndi cates that succeedi ng transformati ons now affect the model vi ew matri x i nstead of
the projecti on matri x. See "Manipulating the Matrix Stacks," for more i nformati on about how to
control the projecti on and model vi ew matri ces.
Note that glLoadI dentity() i s used to i ni ti al i ze the current projecti on matri x so that onl y the speci fi ed
projecti on transformati on has an effect. Now glFrustum() can be cal l ed, wi th arguments that defi ne the
parameters of the projecti on transformati on. I n thi s exampl e, both the projecti on transformati on and
the vi ewport transformati on are contai ned i n the myReshape() routi ne, whi ch i s cal l ed when the
wi ndow i s fi rst created and whenever the wi ndow i s moved or reshaped. Thi s makes sense, si nce both
projecti ng and appl yi ng the vi ewport rel ate di rectl y to the screen, and speci fi cal l y to the si ze of the
wi ndow on the screen.
54
The Viewport Transformation
Together, the projecti on transformati on and the vi ewport transformati on determi ne how a scene gets
mapped onto the computer screen. The projecti on transformati on speci fi es the mechani cs of how the
mappi ng shoul d occur, and the vi ewport i ndi cates the shape of the avai l abl e screen area i nto whi ch the
scene i s mapped. Si nce the vi ewport speci fi es the regi on the i mage occupi es on the computer screen,
you can thi nk of the vi ewport transformati on as defi ni ng the si ze and l ocati on of the fi nal processed
photographwhether i t shoul d be enl arged or shrunk, for exampl e.
The arguments to glViewport() descri be the ori gi n of the avai l abl e screen space wi thi n the wi ndow(0,
0) i n thi s exampl eand the wi dth and hei ght of the avai l abl e screen area, al l measured i n pi xel s on the
screen. Thi s i s why thi s command needs to be cal l ed wi thi n myReshape()i f the wi ndow changes si ze,
the vi ewport needs to change accordi ngl y. Note that the wi dth and hei ght are speci fi ed usi ng the actual
wi dth and hei ght of the wi ndow; often, you want to speci fy the vi ewport thi s way rather than gi vi ng an
absol ute si ze. See "Viewport Transformation," for more i nformati on about how to defi ne the
vi ewport.
Drawing the Scene
Once al l the necessary transformati ons have been speci fi ed, you can draw the scene (that i s, take the
photograph). As the scene i s drawn, OpenGL transforms each vertex of every object i n the scene by the
model i ng and vi ewi ng transformati ons. Each vertex i s then transformed as speci fi ed by the projecti on
transformati on and cl i pped i f i t l i es outsi de the vi ewi ng vol ume descri bed by the projecti on
transformati on. Fi nal l y, the remai ni ng transformed verti ces are di vi ded by w and mapped onto the
vi ewport.
General−Purpose Transformation Commands
Thi s secti on di scusses some OpenGL commands that you mi ght fi nd useful as you speci fy desi red
transformati ons. You’ve al ready seen a coupl e of these commands, glMatrixMode() and glLoadI dentity().
The other two commands descri bed hereglLoadMatrix*() and glMultMatrix*()al l ow you to speci fy
any transformati on matri x di rectl y and then to mul ti pl y the current matri x by that speci fi ed matri x.
More speci fi c transformati on commandssuch as glTranslate*() and glScale*()are descri bed i n l ater
secti ons.
As descri bed i n the precedi ng secti on, you need to state whether you want to modi fy the model vi ew or
projecti on matri x before suppl yi ng a transformati on command. You do thi s wi th glMatrixMode(). When
you use nested sets of OpenGL commands that mi ght be cal l ed repeatedl y, remember to reset the
matri x mode correctl y. (The glMatrixMode() command can al so be used to i ndi cate the texture matri x;
texturi ng i s di scussed i n detai l i n Chapter 9 .)
voi d glMatrixMode(GLenum mode);
Speci fi es whether the model vi ew, projecti on, or texture matri x wi l l be modi fi ed, usi ng the argument
GL_MODELVI EW, GL_PROJECTI ON, or GL_TEXTURE for mode. Subsequent transformati on
commands affect the speci fi ed matri x. Note that onl y one matri x can be modi fi ed at a ti me. By defaul t,
the model vi ew matri x i s the one that’s modi fi abl e, and al l three matri ces contai n the i denti ty matri x.
You use the glLoadI dentity() command to cl ear the currentl y modi fi abl e matri x for future
transformati on commands, si nce these commands modi fy the current matri x. Typi cal l y, you al ways cal l
thi s command before speci fyi ng projecti on or vi ewi ng transformati ons, but you mi ght al so cal l i t before
speci fyi ng a model i ng transformati on.
voi d glLoadI dentity(voi d);
Sets the currentl y modi fi abl e matri x to the 4×4 i denti ty matri x.
I f you want to expl i ci tl y speci fy a parti cul ar matri x to be l oaded as the current matri x, use
glLoadMatrix*(). Si mi l arl y, use glMultMatrix*() to mul ti pl y the current matri x by the matri x passed i n
55
as an argument. The argument for both these commands i s a vector of si xteen val ues (m1, m2, ... , m16)
that speci fi es a matri x M as fol l ows:
Remember that you mi ght be abl e to maxi mi ze effi ci ency by usi ng di spl ay l i sts to store frequentl y used
matri ces (and thei r i nverses) rather than recomputi ng them; see "Display−List Design Philosophy."
(OpenGL i mpl ementati ons often must compute the i nverse of the model vi ew matri x so that normal s
and cl i ppi ng pl anes can be correctl y transformed to eye coordi nates.)
Caution: I f you’re programmi ng i n C, and you decl are a matri x as m[4][4], then the el ement m[i][j] i s
i n the ith col umn and jth row of the OpenGL transformati on matri x. Thi s i s the reverse of
the standard C conventi on i n whi ch m[i][j] i s i n row i and col umn j. To avoi d confusi on, you
shoul d decl are your matri ces as m[16].
voi d glLoadMatrix{fd}(const TYPE *m);
Sets the si xteen val ues of the current matri x to those speci fi ed by m.
voi d glMultMatrix{fd}(const TYPE *m);
Mul ti pl i es the matri x speci fi ed by the si xteen val ues poi nted to by m by the current matri x and stores
the resul t as the current matri x.
Note: Al l matri x mul ti pl i cati on wi th OpenGL occurs as fol l ows: Suppose the current matri x i s C and
the matri x speci fi ed wi th glMultMatrix*() or any of the transformati on commands i s M. After
mul ti pl i cati on, the fi nal matri x i s al ways CM. Si nce matri x mul ti pl i cati on i sn’t general l y
commutati ve, the order makes a di fference.
Viewing and Modeling Transformations
As noted i n "A Simple Example: Drawing a Cube," vi ewi ng and model i ng transformati ons are
i nextri cabl y rel ated i n OpenGL and are i n fact combi ned i nto a si ngl e model vi ew matri x. One of the
toughest probl ems newcomers to computer graphi cs face i s understandi ng the effects of combi ned
three−di mensi onal transformati ons. As you’ve al ready seen, there are al ternati ve ways to thi nk about
transformati onsdo you want to move the camera i n one di recti on, or move the object i n the opposi te
di recti on? Each way of thi nki ng about transformati ons has advantages and di sadvantages, but i n some
56
cases one way more natural l y matches the effect of the i ntended transformati on. I f you can fi nd a
natural approach for your parti cul ar appl i cati on, i t’s easi er to vi sual i ze the necessary transformati ons
and then wri te the correspondi ng code to speci fy the matri x mani pul ati ons. The fi rst part of thi s
secti on di scusses how to thi nk about transformati ons; l ater, speci fi c commands are presented. For now,
we use onl y the matri x−mani pul ati on commands you’ve al ready seen. Fi nal l y, keep i n mi nd that you
must cal l glMatrixMode() wi th GL_MODELVI EW as i ts argument pri or to performi ng model i ng or
vi ewi ng transformati ons.
Thinking about Transformations
Let’s start wi th a si mpl e case of two transformati ons: a 45−degree countercl ockwi se rotati on about the
ori gi n around the z−axi s, and a transl ati on down the x−axi s. Suppose that the object you’re drawi ng i s
smal l compared to the transl ati on (so that you can see the effect of the transl ati on), and that i t’s
ori gi nal l y l ocated at the ori gi n. I f you rotate the object fi rst and then transl ate i t, the rotated object
appears on the x−axi s. I f you transl ate i t down the x−axi s fi rst, however, and then rotate about the
ori gi n, the object i s on the l i ne y=x, as shown i n Figure 3−4 . I n general , the order of transformati ons i s
cri ti cal . I f you do transformati on A and then transformati on B, you al most certai nl y get somethi ng
di fferent than i f you do them i n the opposi te order.
Figure 3−4 Rotati ng Fi rst or Transl ati ng Fi rst
Now l et’s tal k about the order i n whi ch you speci fy a seri es of transformati ons. Al l vi ewi ng and
model i ng transformati ons are represented as 4×4 matri ces. Each successi ve glMultMatrix*() or
transformati on command mul ti pl i es a new 4×4 matri x M by the current model vi ew matri x C to yi el d
CM. Fi nal l y, verti ces v are mul ti pl i ed by the current model vi ew matri x. Thi s process means that the
l ast transformati on command cal l ed i n your program i s actual l y the fi rst one appl i ed to the verti ces:
CMv. Thus, one way of l ooki ng at i t i s to say that you have to speci fy the matri ces i n the reverse order.
Li ke many other thi ngs, however, once you’ve gotten used to thi nki ng about thi s correctl y, backward
wi l l seem l i ke forward.
Consi der the fol l owi ng code sequence, whi ch draws a si ngl e poi nt usi ng three transformati ons:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMultMatrixf(N); /* apply transformation N */
glMultMatrixf(M); /* apply transformation M */
glMultMatrixf(L); /* apply transformation L */
glBegin(GL_POINTS);
57
glBegin(GL_POINTS);
glVertex3f(v); /* draw transformed vertex v */
glEnd();
Wi th thi s code, the model vi ew matri x successi vel y contai ns I , N, NM, and fi nal l y NML, where I
represents the i denti ty matri x. The transformed vertex i s NMLv. Thus, the vertex transformati on i s
N(M(Lv))that i s, v i s mul ti pl i ed fi rst by L, the resul ti ng Lv i s mul ti pl i ed by M, and the resul ti ng MLv
i s mul ti pl i ed by N. Noti ce that the transformati ons to vertex v effecti vel y occur i n the opposi te order
than they were speci fi ed. (Actual l y, onl y a si ngl e mul ti pl i cati on of a vertex by the model vi ew matri x
occurs; i n thi s exampl e, the N, M, and L matri ces are al ready mul ti pl i ed i nto a si ngl e matri x before i t’s
appl i ed to v.)
Thus, i f you l i ke to thi nk i n terms of a grand, fi xed coordi nate systemi n whi ch matri x mul ti pl i cati ons
affect the posi ti on, ori entati on, and scal i ng of your model you have to thi nk of the mul ti pl i cati ons as
occurri ng i n the opposi te order from how they appear i n the code. Usi ng the si mpl e exampl e di scussed
i n Figure 3−4 (a rotati on about the ori gi n and a transl ati on al ong the x−axi s), i f you want the object to
appear on the axi s after the operati ons, the rotati on must occur fi rst, fol l owed by the transl ati on. To do
thi s, the code l ooks somethi ng l i ke thi s (where R i s the rotati on matri x and T i s the transl ati on matri x):
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMultMatrixf(T); /* translation */
glMultMatrixf(R); /* rotation */
draw_the_object();
Another way to vi ew matri x mul ti pl i cati ons i s to forget about a grand, fi xed coordi nate system i n whi ch
your model i s transformed and i nstead i magi ne that a l ocal coordi nate system i s ti ed to the object you’re
drawi ng. Al l operati ons occur rel ati ve to thi s changi ng coordi nate system. Wi th thi s approach, the
matri x mul ti pl i cati ons now appear i n the natural order i n the code. (Regardl ess of whi ch anal ogy you’re
usi ng, the code i s the same, but how you thi nk about i t di ffers.) To see thi s i n the transl ati on−rotati on
exampl e, begi n by vi sual i zi ng the object wi th a coordi nate system ti ed to i t. The transl ati on operati on
moves the object and i ts coordi nate system down the x−axi s. Then, the rotati on occurs about the
(now−transl ated) ori gi n, so the object rotates i n pl ace i n i ts posi ti on on the axi s.
Thi s approach i s what you shoul d use for appl i cati ons such as arti cul ated robot arms, where there are
joi nts at the shoul der, el bow, and wri st, and on each of the fi ngers. To fi gure out where the ti ps of the
fi ngers go rel ati ve to the body, you’d l i ke to start at the shoul der, go down to the wri st, and so on,
appl yi ng the appropri ate rotati ons and transl ati ons at each joi nt. Thi nki ng about i t i n reverse woul d be
far more confusi ng.
Thi s second approach can be probl emati c, however, i n cases where scal i ng occurs, and especi al l y so
when the scal i ng i s nonuni form (scal i ng di fferent amounts al ong the di fferent axes). After uni form
scal i ng, transl ati ons move a vertex by a mul ti pl e of what they di d before, si nce the coordi nate system i s
stretched. Nonuni form scal i ng mi xed wi th rotati ons may make the axes of the l ocal coordi nate system
nonperpendi cul ar.
As menti oned earl i er, you normal l y i ssue vi ewi ng transformati on commands i n your program before
any model i ng transformati ons. Thi s way, a vertex i n a model i s fi rst transformed i nto the desi red
ori entati on and then transformed by the vi ewi ng operati on. Si nce the matri x mul ti pl i cati ons must be
speci fi ed i n reverse order, the vi ewi ng commands need to come fi rst. Note, however, that you don’t need
to speci fy ei ther vi ewi ng or model i ng transformati ons i f you’re sati sfi ed wi th the defaul t condi ti ons. I f
there’s no vi ewi ng transformati on, the "camera" i s l eft i n the defaul t posi ti on at the ori gi n, poi nted
toward the negati ve z−axi s; i f there’s no model i ng transformati on, the model i sn’t moved, and i t retai ns
i ts speci fi ed posi ti on, ori entati on, and si ze.
Si nce the commands for performi ng model i ng transformati ons can be used to perform vi ewi ng
transformati ons, model i ng transformati ons are discussed fi rst, even i f vi ewi ng transformati ons are
actual l y issued fi rst. Thi s order for di scussi on al so matches the way many programmers thi nk when
58
pl anni ng thei r code: Often, they wri te al l the code necessary to compose the scene, whi ch i nvol ves
transformati ons to posi ti on and ori ent objects correctl y rel ati ve to each other. Then, they deci de where
they want the vi ewpoi nt to be rel ati ve to the scene they’ve composed, and they wri te the vi ewi ng
transformati ons accordi ngl y.
Modeling Transformations
The three OpenGL routi nes for model i ng transformati ons are glTranslate*(), glRotate*(), and glScale*().
As you mi ght suspect, these routi nes transform an object (or coordi nate system, i f you’re thi nki ng of i t
that way) by movi ng, rotati ng, stretchi ng, or shri nki ng i t. Al l three commands are equi val ent to
produci ng an appropri ate transl ati on, rotati on, or scal i ng matri x, and then cal l i ng glMultMatrix*()
wi th that matri x as the argument. However, these three routi nes mi ght be faster than usi ng
glMultMatrix*(). OpenGL automati cal l y computes the matri ces for you; i f you’re i nterested i n the
detai l s, see Appendix G .
I n the command summari es that fol l ow, each matri x mul ti pl i cati on i s descri bed i n terms of what i t does
to the verti ces of a geometri c object usi ng the fi xed coordi nate system approach, and i n terms of what i t
does to the l ocal coordi nate system that’s attached to an object.
Translate
voi d gl Transl ate{fd}(TYPEx, TYPE y, TYPEz);
Mul ti pl i es the current matri x by a matri x that moves (transl ates) an object by the gi ven x, y, and z
val ues (or moves the l ocal coordi nate system by the same amounts).
Figure 3−5 shows the effect of glTranslatef().
59
Figure 3−5 Transl ati ng an Object
Note that usi ng (0.0, 0.0, 0.0) as the argument for glTranslate*() i s the i denti ty operati onthat i s, i t
has no effect on an object or i ts l ocal coordi nate system.
Rotate
voi d glRotate{fd}(TYPE angle, TYPE x, TYPE y, TYPE z);
Mul ti pl i es the current matri x by a matri x that rotates an object (or the l ocal coordi nate system) i n a
countercl ockwi se di recti on about the ray from the ori gi n through the poi nt (x, y, z). The angle
parameter speci fi es the angl e of rotati on i n degrees.
The effect of glRotatef(45.0, 0.0, 0.0, 1.0), whi ch i s a rotati on of 45 degrees about the z−axi s, i s shown i n
Figure 3−6 .
Figure 3−6 Rotati ng an Object
Note that an object that l i es farther from the axi s of rotati on i s more dramati cal l y rotated (has a l arger
orbi t) than an object drawn near the axi s. Al so, i f the angleargument i s zero, the glRotate*() command
has no effect.
Scale
voi d glScale{fd}(TYPEx, TYPE y, TYPEz);
Mul ti pl i es the current matri x by a matri x that stretches, shri nks, or refl ects an object al ong the axes.
Each x, y, and z coordi nate of every poi nt i n the object i s mul ti pl i ed by the correspondi ng argument x, y,
or z. Wi th the l ocal coordi nate system approach, the l ocal coordi nate axes are stretched by the x, y, and z
60
factors, and the associ ated object i s stretched wi th them.
Figure 3−7 shows the effect of glScalef(2.0, −0.5, 1.0).
Figure 3−7 Scal i ng and Refl ecti ng an Object
glScale*() i s the onl y one of the three model i ng transformati ons that changes the apparent si ze of an
object: Scal i ng wi th val ues greater than 1.0 stretches an object, and usi ng val ues l ess than 1.0 shri nks
i t. Scal i ng wi th a −1.0 val ue refl ects an object across an axi s. The i denti ty val ues for scal i ng are (1.0,
1.0, 1.0). I n general , you shoul d l i mi t your use of glScale*() to those cases where i t i s necessary. Usi ng
glScale*() decreases the performance of l i ghti ng cal cul ati ons, because the normal vectors have to be
renormal i zed after transformati on.
Note: A scal e val ue of zero col l apses al l object coordi nates al ong that axi s to zero. I t’s usual l y not a
good i dea to do thi s, because such an operati on cannot be undone. Mathemati cal l y speaki ng,
the matri x cannot be i nverted, and i nverse matri ces are requi red for certai n l i ghti ng operati ons
(see Chapter 6 ). Someti mes col l apsi ng coordi nates does make sense, however; the cal cul ati on
of shadows on a pl anar surface i s a typi cal appl i cati on (see "Shadows,"). I n general , i f a
coordi nate system i s to be col l apsed, the projecti on matri x shoul d be used rather than the
model vi ew matri x.
A Modeling Transformation Code Example
Example 3−2i s a porti on of a program that renders a tri angl e four ti mes, as shown i n Figure 3−8 :
• A sol i d wi reframe tri angl e i s drawn wi th no model i ng transformati on.
• The same tri angl e i s drawn agai n, but wi th a dashed l i ne sti ppl e and transl ated.
• A tri angl e i s drawn wi th a l ong dashed l i ne sti ppl e, wi th i ts hei ght (y−axi s) hal ved and i ts wi dth (x
61
−axi s) doubl ed.
• A rotated, scal ed tri angl e, made of dotted l i nes, i s drawn.
Figure 3−8 Model i ng Transformati on Exampl e
Example 3−2 Usi ng Model i ng Transformati ons: model .c
glLoadIdentity();
glColor3f(1.0, 1.0, 1.0);
draw_triangle(); /* solid lines */
glEnable(GL_LINE_STIPPLE); /* dashed lines */
glLineStipple(1, 0xF0F0);
glLoadIdentity();
glTranslatef(−20.0, 0.0, 0.0);
draw_triangle();
glLineStipple(1, 0xF00F); /*long dashed lines */
glLoadIdentity();
glScalef(1.5, 0.5, 1.0);
draw_triangle();
glLineStipple(1, 0x8888); /* dotted lines */
glLoadIdentity();
glRotatef (90.0, 0.0, 0.0, 1.0);
draw_triangle ();
glDisable (GL_LINE_STIPPLE);
Note the use of glLoadI dentity() to i sol ate the effects of model i ng transformati ons; i ni ti al i zi ng the
matri x val ues prevents successi ve transformati ons from havi ng a cumul ati ve effect. Even though usi ng
glLoadI dentity() repeatedl y has the desi red effect, i t mi ght be i neffi ci ent, dependi ng on your parti cul ar
OpenGL i mpl ementati on. See "Manipulating the Matrix Stacks" for a better way to i sol ate
transformati ons.
Note: Someti mes, programmers who want a conti nuousl y rotati ng object attempt to achi eve thi s by
repeatedl y appl yi ng a rotati on matri x that has smal l val ues. The probl em wi th thi s techni que
i s that because of round−off errors, the product of thousands of ti ny rotati ons gradual l y dri fts
away from the val ue you real l y want (i t mi ght even become somethi ng that i sn’t a rotati on).
I nstead of usi ng thi s techni que, i ncrement the angl e and i ssue a new rotati on command wi th
the new angl e at each update step.
Viewing Transformations
62
A vi ewi ng transformati on changes the posi ti on and ori entati on of the vi ewpoi nt. I f you recal l the
camera anal ogy, the vi ewi ng transformati on posi ti ons the camera tri pod, poi nti ng the camera toward
the model . Just as you move the camera to some posi ti on and rotate i t unti l i t poi nts i n the desi red
di recti on, vi ewi ng transformati ons are general l y composed of transl ati ons and rotati ons. Al so
remember that, to achi eve a certai n scene composi ti on i n the fi nal i mage or photograph, ei ther you can
move the camera, or you can move al l the objects i n the opposi te di recti on. Thus, a model i ng
transformati on that rotates an object countercl ockwi se i s equi val ent to a vi ewi ng transformati on that
rotates the camera cl ockwi se, for exampl e. Fi nal l y, keep i n mi nd that the vi ewi ng transformati on
commands must be cal l ed before any model i ng transformati ons are performed, so that the model i ng
transformati ons take effect on the objects fi rst.
You can accompl i sh a vi ewi ng transformati on i n any of several ways, as descri bed bel ow. You can al so
choose to use the defaul t l ocati on and ori entati on of the vi ewpoi nt, whi ch i s at the ori gi n, l ooki ng down
the negati ve z−axi s.
• Use one or more model i ng transformati on commands (that i s, glTranslate*() and glRotate*()). You
can thi nk of the effect of these transformati ons as movi ng the camera posi ti on or as movi ng al l the
objects i n the worl d, rel ati ve to a stati onary camera.
• Use the Uti l i ty Li brary routi ne gluLookAt() to defi ne a l i ne of si ght. Thi s routi ne encapsul ates a
seri es of rotati on and transl ati on commands.
• Create your own uti l i ty routi ne that encapsul ates rotati ons and transl ati ons. Some appl i cati ons
mi ght requi re custom routi nes that al l ow you to speci fy the vi ewi ng transformati on i n a conveni ent
way. For exampl e, you mi ght want to speci fy the rol l , pi tch, and headi ng rotati on angl es of a pl ane
i n fl i ght, or you mi ght want to speci fy a transformati on i n terms of pol ar coordi nates for a camera
that’s orbi ti ng around an object.
Using glTranslate*() and glRotate*()
When you use model i ng transformati on commands to emul ate vi ewi ng transformati ons, you’re tryi ng to
move the vi ewpoi nt i n a desi red way whi l e keepi ng the objects i n the worl d stati onary. Si nce the
vi ewpoi nt i s i ni ti al l y l ocated at the ori gi n and si nce objects are often most easi l y constructed there as
wel l (see Figure 3−9 ), i n general you have to perform some transformati on so that the objects can be
vi ewed. Note that, as shown i n the fi gure, the camera i ni ti al l y poi nts down the negati ve z−axi s. (You’re
seei ng the back of the camera.)
63
Figure 3−9 Object and Vi ewpoi nt at the Ori gi n
I n the si mpl est case, you can move the vi ewpoi nt backward, away from the objects; thi s has the same
effect as movi ng the objects forward, or away from the vi ewpoi nt. Remember that by defaul t forward i s
down the negati ve z−axi s; i f you rotate the vi ewpoi nt, forward has a di fferent meani ng. So, to put 5
uni ts of di stance between the vi ewpoi nt and the objects by movi ng the vi ewpoi nt, as shown i n Figure
3−10 , use
glTranslatef(0.0, 0.0, −5.0);
64
Figure 3−10 Separati ng the Vi ewpoi nt and the Object
Now suppose you want to vi ew the objects from the si de. Shoul d you i ssue a rotate command before or
after the transl ate command? I f you’re thi nki ng i n terms of a grand, fi xed coordi nate system, fi rst
i magi ne both the object and the camera at the ori gi n. You coul d rotate the object fi rst and then move i t
away from the camera so that the desi red si de i s vi si bl e. Si nce you know that wi th the fi xed coordi nate
system approach, commands have to be i ssued i n the opposi te order i n whi ch they shoul d take effect,
you know that you need to wri te the transl ate command fi rst i n your code and fol l ow i t wi th the rotate
command.
Now l et’s use the l ocal coordi nate system approach. I n thi s case, thi nk about movi ng the object and i ts
l ocal coordi nate system away from the ori gi n; then, the rotate command i s carri ed out usi ng the
now−transl ated coordi nate system. Wi th thi s approach, commands are i ssued i n the order i n whi ch
they’re appl i ed, so once agai n the transl ate command comes fi rst. Thus, the sequence of transformati on
commands to produce the desi red resul t i s
glTranslatef(0.0, 0.0, −5.0);
glRotatef(90.0, 0.0, 1.0, 0.0);
I f you’re havi ng troubl e keepi ng track of the effect of successi ve matri x mul ti pl i cati ons, try usi ng both
the fi xed and l ocal coordi nate system approaches and see whether one makes more sense to you. Note
that wi th the fi xed coordi nate system, rotati ons al ways occur about the grand ori gi n, whereas wi th the
l ocal coordi nate system, rotati ons occur about the ori gi n of the l ocal system. You mi ght al so try usi ng
the gluLookAt() uti l i ty routi ne descri bed i n the next secti on.
Using the gluLookAt() Utility Routine
Often, programmers construct a scene around the ori gi n or some other conveni ent l ocati on, then they
want to l ook at i t from an arbi trary poi nt to get a good vi ew of i t. As i ts name suggests, the gluLookAt()
65
uti l i ty routi ne i s desi gned for just thi s purpose. I t takes three sets of arguments, whi ch speci fy the
l ocati on of the vi ewpoi nt, defi ne a reference poi nt toward whi ch the camera i s ai med, and i ndi cate
whi ch di recti on i s up. Choose the vi ewpoi nt to yi el d the desi red vi ew of the scene. The reference poi nt i s
typi cal l y somewhere i n the mi ddl e of the scene: I f you’ve bui l t your scene at the ori gi n, the reference
poi nt i s probabl y the ori gi n. I t mi ght be a l i ttl e tri cki er to speci fy the correct up−vector. Agai n, i f you’ve
bui l t some real −worl d scene at or around the ori gi n, and i f you’ve been taki ng the posi ti ve y−axi s to
poi nt upward, then that’s your up−vector for gluLookAt(). However, i f you’re desi gni ng a fl i ght
si mul ator, up i s the di recti on perpendi cul ar to the pl ane’s wi ngs, from the pl ane toward the sky when
the pl ane i s ri ght−si de up on the ground.
The gluLookAt() routi ne i s parti cul arl y useful when you want to pan across a l andscape, for i nstance.
Wi th a vi ewi ng vol ume that’s symmetri c i n both x and y, the (eyex, eyey, eyez) poi nt speci fi ed i s al ways
i n the center of the i mage on the screen, so you can use a seri es of commands to move thi s poi nt
sl i ghtl y, thereby panni ng across the scene.
voi d gluLookAt(GLdoubl e eyex, GLdoubl e eyey, GLdoubl e eyez, GLdoubl e centerx, GLdoubl e centery,
GLdoubl e centerz, GLdoubl e upx, GLdoubl e upy, GLdoubl e upz);
Defi nes a vi ewi ng matri x and mul ti pl i es i t to the ri ght of the current matri x. The desi red vi ewpoi nt i s
speci fi ed by eyex, eyey, and eyez. The centerx, centery, and centerz arguments speci fy any poi nt al ong the
desi red l i ne of si ght, but typi cal l y they’re some poi nt i n the center of the scene bei ng l ooked at. The upx,
upy, and upz arguments i ndi cate whi ch di recti on i s up (that i s, the di recti on from the bottom to the top
of the vi ewi ng vol ume).
Note that gluLookAt() i s part of the Uti l i ty Li brary rather than the basi c OpenGL l i brary. Thi s i sn’t
because i t’s not useful , but because i t encapsul ates several basi c OpenGL commandsspeci fi cal l y,
glTranslate*() and gl Rotate*(). To see thi s, i magi ne a camera l ocated at an arbi trary vi ewpoi nt and
ori ented accordi ng to a l i ne of si ght, both as speci fi ed wi th gluLookAt(), and a scene l ocated at the
ori gi n. To "undo" what gluLookAt() does, you need to transform the camera so that i t si ts at the ori gi n
and poi nts down the negati ve z−axi s, the defaul t posi ti on. A si mpl e transl ate moves the camera to the
ori gi n. You can easi l y i magi ne a seri es of rotati ons about each of the three axes of a fi xed coordi nate
system that woul d ori ent the camera so that i t poi nted toward negati ve z val ues. Si nce OpenGL al l ows
rotati on about an arbi trary axi s, you can accompl i sh any desi red rotati on of the camera wi th a si ngl e
glRotate*() command.
Advanced
To transform any arbi trary vector so that i t’s coi nci dent wi th another arbi trary vector (for i nstance, the
negati ve z−axi s), you need to do a l i ttl e mathemati cs. The axi s about whi ch you want to rotate i s gi ven
by the cross product of the two normal i zed vectors. To fi nd the angl e of rotati on, normal i ze the i ni ti al
two vectors. The cosi ne of the desi red angl e between the vectors i s equal to the dot product of the
normal i zed vectors. To di sambi guate between the two possi bl e angl es i denti fi ed by the cosi ne (x degrees
and x+180 degrees), recal l that the l ength of the cross product of the normal i zed vectors equal s the si ne
of the angl e of rotati on. (See Appendix F for defi ni ti ons of cross and dot products.)
Creating a Custom Utility Routine
Advanced
For some speci al i zed appl i cati ons, you mi ght want to defi ne your own transformati on routi ne. Si nce
thi s i s rarel y done and i n any case i s a fai rl y advanced topi c, i t’s l eft mostl y as an exerci se for the
reader. The fol l owi ng exerci ses suggest two custom vi ewi ng transformati ons that mi ght be useful .
Try This:
Try This
• Suppose you’re wri ti ng a fl i ght si mul ator and you’d l i ke to di spl ay the worl d from the poi nt of vi ew
of the pi l ot of a pl ane. The worl d i s descri bed i n a coordi nate system wi th the ori gi n on the runway
66
and the pl ane at coordi nates (x, y, z). Suppose further that the pl ane has some roll, pitch, and
heading (these are rotati on angl es of the pl ane rel ati ve to i ts center of gravi ty).
Show that the fol l owi ng routi ne coul d serve as the vi ewi ng transformati on:
void pilotView{GLdouble planex, GLdouble planey,
GLdouble planez, GLdouble roll,
GLdouble pitch, GLdouble heading)
{
glRotated(roll, 0.0, 0.0, 1.0);
glRotated(pitch, 0.0, 1.0, 0.0);
glRotated(heading, 1.0, 0.0, 0.0);
glTranslated(−planex, −planey, −planez);
}
• Suppose your appl i cati on i nvol ves orbi ti ng the camera around an object that’s centered at the
ori gi n. I n thi s case, you’d l i ke to speci fy the vi ewi ng transformati on by usi ng pol ar coordi nates. Let
the distancevari abl e defi ne the radi us of the orbi t, or how far the camera i s from the ori gi n.
(I ni ti al l y, the camera i s moved distanceuni ts al ong the posi ti ve z−axi s.) The azimuth descri bes the
angl e of rotati on of the camera about the object i n the x−y pl ane, measured from the posi ti ve y
−axi s. Si mi l arl y, elevation i s the angl e of rotati on of the camera i n the y−z pl ane, measured from
the posi ti ve z−axi s. Fi nal l y, twist represents the rotati on of the vi ewi ng vol ume around i ts l i ne of
si ght.
Show that the fol l owi ng routi ne coul d serve as the vi ewi ng transformati on:
void polarView{GLdouble distance, GLdouble twist,
GLdouble elevation, GLdouble azimuth)
{
glTranslated(0.0, 0.0, −distance);
glRotated(−twist, 0.0, 0.0, 1.0);
glRotated(−elevation, 1.0, 0.0, 0.0);
glRotated(azimuth, 0.0, 0.0, 1.0);
}
Projection Transformations
The previ ous secti on descri bed how to compose the desi red model vi ew matri x so that the correct
model i ng and vi ewi ng transformati ons are appl i ed. Thi s secti on expl ai ns how to defi ne the desi red
projecti on matri x, whi ch i s al so used to transform the verti ces i n your scene. Before you i ssue any of the
transformati on commands descri bed i n thi s secti on, remember to cal l
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
so that the commands affect the projecti on matri x rather than the model vi ew matri x, and so that you
avoi d compound projecti on transformati ons. Si nce each projecti on transformati on command compl etel y
descri bes a parti cul ar transformati on, typi cal l y you don’t want to combi ne a projecti on transformati on
wi th another transformati on.
The purpose of the projecti on transformati on i s to defi ne a viewing volume, whi ch i s used i n two ways.
The vi ewi ng vol ume determi nes how an object i s projected onto the screen (that i s, by usi ng a
perspecti ve or an orthographi c projecti on), and i t defi nes whi ch objects or porti ons of objects are cl i pped
out of the fi nal i mage. You can thi nk of the vi ewpoi nt we’ve been tal ki ng about as exi sti ng at one end of
the vi ewi ng vol ume. At thi s poi nt, you mi ght want to reread "A Simple Example: Drawing a Cube,"
for i ts overvi ew of al l the transformati ons, i ncl udi ng projecti on transformati ons.
67
Perspective Projection
The most unmi stakabl e characteri sti c of perspecti ve projecti on i s foreshorteni ng: the farther an object
i s from the camera, the smal l er i t appears i n the fi nal i mage. Thi s occurs because the vi ewi ng vol ume
for a perspecti ve projecti on i s a frustum of a pyrami d (a truncated pyrami d whose top has been cut off
by a pl ane paral l el to i ts base). Objects that fal l wi thi n the vi ewi ng vol ume are projected toward the
apex of the pyrami d, where the camera or vi ewpoi nt i s. Objects that are cl oser to the vi ewpoi nt appear
l arger because they occupy a proporti onal l y l arger amount of the vi ewi ng vol ume than those that are
farther away, i n the l arger part of the frustum. Thi s method of projecti on i s commonl y used for
ani mati on, vi sual si mul ati on, and any other appl i cati ons that stri ve for some degree of real i sm because
i t’s si mi l ar to how our eye (or a camera) works.
The command to defi ne a frustum, glFrustum(), cal cul ates a matri x that accompl i shes perspecti ve
projecti on and mul ti pl i es the current projecti on matri x (typi cal l y the i denti ty matri x) by i t. Recal l that
the vi ewi ng vol ume i s used to cl i p objects that l i e outsi de of i t; the four si des of the frustum, i ts top, and
i ts base correspond to the si x cl i ppi ng pl anes of the vi ewi ng vol ume, as shown i n Figure 3−11. Objects
or parts of objects outsi de these pl anes are cl i pped from the fi nal i mage. Note that glFrustum() doesn’t
requi re you to defi ne a symmetri c vi ewi ng vol ume.
Figure 3−11 The Perspecti ve Vi ewi ng Vol ume Speci fi ed by gl Frustum()
voi d glFrustum(GLdoubl e left, GLdoubl e right, GLdoubl e bottom, GLdoubl e top, GLdoubl e near,
GLdoubl e far);
Creates a matri x for a perspecti ve−vi ew frustum and mul ti pl i es the current matri x by i t. The frustum’s
vi ewi ng vol ume i s defi ned by the parameters: (left, bottom, −near) and (right, top, −near) speci fy the (x, y,
z) coordi nates of the l ower l eft and upper ri ght corners of the near cl i ppi ng pl ane; near and far gi ve the
di stances from the vi ewpoi nt to the near and far cl i ppi ng pl anes. They shoul d al ways be posi ti ve.
The frustum has a defaul t ori entati on i n three−di mensi onal space. You can perform rotati ons or
transl ati ons on the projecti on matri x to al ter thi s ori entati on, but thi s i s tri cky and nearl y al ways
avoi dabl e.
Advanced
Al so, the frustum doesn’t have to be symmetri cal , and i ts axi s i sn’t necessari l y al i gned wi th the z−axi s.
68
For exampl e, you can use glFrustum() to draw a pi cture as i f you were l ooki ng through a rectangul ar
wi ndow of a house, where the wi ndow was above and to the ri ght of you. Photographers use such a
vi ewi ng vol ume to create fal se perspecti ves. You mi ght use i t to have the hardware cal cul ate i mages at
much hi gher than normal resol uti ons, perhaps for use on a pri nter. For exampl e, i f you want an i mage
that has twi ce the resol uti on of your screen, draw the same pi cture four ti mes, each ti me usi ng the
frustum to cover the enti re screen wi th one−quarter of the i mage. After each quarter of the i mage i s
rendered, you can read the pi xel s back to col l ect the data for the hi gher−resol uti on i mage. (See
Chapter 8 for more i nformati on about readi ng pi xel data.)
Al though i t’s easy to understand conceptual l y, glFrustum() i sn’t i ntui ti ve to use. I nstead, you mi ght try
the Uti l i ty Li brary routi ne gluPerspective(). Thi s routi ne creates a vi ewi ng vol ume of the same shape as
glFrustum() does, but you speci fy i t i n a di fferent way. Rather than speci fyi ng corners of the near
cl i ppi ng pl ane, you speci fy the angl e of the fi el d of vi ew i n the x−z pl ane and the aspect rati o of the
wi dth to hei ght (x/ y). (For a square porti on of the screen, the aspect rati o i s 1.0.) These two parameters
are enough to determi ne an untruncated pyrami d al ong the l i ne of si ght, as shown i n Figure 3−12.
You al so speci fy the di stance between the vi ewpoi nt and the near and far cl i ppi ng pl anes, thereby
truncati ng the pyrami d. Note that gluPerspective() i s l i mi ted to creati ng frustums that are symmetri c
i n both the x− and y−axes al ong the l i ne of si ght, but thi s i s usual l y what you want.
Figure 3−12 The Perspecti ve Vi ewi ng Vol ume Speci fi ed by gl uPerspecti ve()
voi d gluPerspective(GLdoubl e fovy, GLdoubl e aspect, GLdoubl e zNear, GLdoubl e zFar);
Creates a matri x for a symmetri c perspecti ve−vi ew frustum and mul ti pl i es the current matri x by i t.
The fovy argument i s the angl e of the fi el d of vi ew i n the x−z pl ane; i ts val ue must be i n the range
[0.0,180.0]. The aspect rati o i s the wi dth of the frustum di vi ded by i ts hei ght. The zNear and zFar
val ues are the di stances between the vi ewpoi nt and the cl i ppi ng pl anes, al ong the negati ve z−axi s.
They shoul d al ways be posi ti ve.
Just as wi th glFrustum(), you can appl y rotati ons or transl ati ons to change the defaul t ori entati on of
the vi ewi ng vol ume created by gluPerspective(). Wi th no such transformati ons, the vi ewpoi nt remai ns
at the ori gi n, and the l i ne of si ght poi nts down the negati ve z−axi s.
Wi th gluPerspective(), you need to pi ck appropri ate val ues for the fi el d of vi ew, or the i mage may l ook
di storted. For exampl e, suppose you’re drawi ng to the enti re screen, whi ch happens to be 11 i nches
hi gh. I f you choose a fi el d of vi ew of 90 degrees, your eye has to be about 7.8 i nches from the screen for
69
the i mage to appear undi storted. (Thi s i s the di stance that makes the screen subtend 90 degrees.) I f
your eye i s farther from the screen, as i t usual l y i s, the perspecti ve doesn’t l ook ri ght. I f your drawi ng
area occupi es l ess than the ful l screen, your eye has to be even cl oser. To get a perfect fi el d of vi ew,
fi gure out how far your eye normal l y i s from the screen and how bi g the wi ndow i s, and cal cul ate the
angl e the wi ndow subtends at that si ze and di stance. I t’s probabl y smal l er than you woul d guess.
Another way to thi nk about i t i s that a 94−degree fi el d of vi ew wi th a 35−mi l l i meter camera requi res a
20−mi l l i meter l ens, whi ch i s a very wi de−angl e l ens. "Troubleshooting Transformations," gi ves
more detai l s on how to cal cul ate the desi red fi el d of vi ew.
The precedi ng paragraph menti ons i nches and mi l l i metersdo these real l y have anythi ng to do wi th
OpenGL? The answer i s, i n a word, no. The projecti on and other transformati ons are i nherentl y
uni tl ess. I f you want to thi nk of the near and far cl i ppi ng pl anes as l ocated at 1.0 and 20.0 meters,
i nches, ki l ometers, or l eagues, i t’s up to you. The onl y rul e i s that you have to use a consi stent uni t of
measurement. Then the resul ti ng i mage i s drawn to scal e.
Orthographic Projection
Wi th an orthographi c projecti on, the vi ewi ng vol ume i s a rectangul ar paral l el epi ped, or more
i nformal l y, a box (see Figure 3−13). Unl i ke perspecti ve projecti on, the si ze of the vi ewi ng vol ume
doesn’t change from one end to the other, so di stance from the camera doesn’t affect how l arge an object
appears. Thi s type of projecti on i s used for appl i cati ons such as creati ng archi tectural bl uepri nts and
computer−ai ded desi gn, where i t’s cruci al to mai ntai n the actual si zes of objects and angl es between
them as they’re projected.
Figure 3−13 The Orthographi c Vi ewi ng Vol ume
The command glOrtho() creates an orthographi c paral l el vi ewi ng vol ume. As wi th glFrustum(), you
speci fy the corners of the near cl i ppi ng pl ane and the di stance to the far cl i ppi ng pl ane.
voi d glOrtho(GLdoubl e left, GLdoubl e right, GLdoubl e bottom,
70
GLdoubl e top, GLdoubl e near, GLdoubl e far);
Creates a matri x for an orthographi c paral l el vi ewi ng vol ume and mul ti pl i es the current matri x by i t.
The near cl i ppi ng pl ane i s a rectangl e wi th the l ower l eft corner at (left, bottom, −near) and the upper
ri ght corner at (right, top, −near). The far cl i ppi ng pl ane i s a rectangl e wi th corners at (left, bottom, −far
) and (right, top, −far). Both near and far can be posi ti ve or negati ve.
Wi th no other transformati ons, the di recti on of projecti on i s paral l el to the z−axi s, and the vi ewpoi nt
faces toward the negati ve z−axi s. Note that thi s means that the val ues passed i n for far and near are
used as negati ve z val ues i f these pl anes are i n front of the vi ewpoi nt, and posi ti ve i f they’re behi nd the
vi ewpoi nt.
For the speci al case of projecti ng a two−di mensi onal i mage onto a two−di mensi onal screen, use the
Uti l i ty Li brary routi ne gluOrtho2D(). Thi s routi ne i s i denti cal to the three−di mensi onal versi on,
glOrtho(), except that al l the z coordi nates for objects i n the scene are assumed to l i e between −1.0 and
1.0. I f you’re drawi ng two−di mensi onal objects usi ng the two−di mensi onal vertex commands, al l the z
coordi nates are zero; thus, none of the objects are cl i pped because of thei r z val ues.
voi d gluOrtho2D(GLdoubl e left, GLdoubl e right, GLdoubl e bottom, GLdoubl e top);
Creates a matri x for projecti ng two−di mensi onal coordi nates onto the screen and mul ti pl i es the current
projecti on matri x by i t. The cl i ppi ng pl ane i s a rectangl e wi th the l ower l eft corner at (left, bottom) and
the upper ri ght corner at (right, top).
Viewing Volume Clipping
After the verti ces of the objects i n the scene have been transformed by the model vi ew and projecti on
matri ces, any verti ces that l i e outsi de the vi ewi ng vol ume are cl i pped. The si x cl i ppi ng pl anes used are
those that defi ne the si des and ends of the vi ewi ng vol ume. You can speci fy addi ti onal cl i ppi ng pl anes
and l ocate them wherever you choose; thi s rel ati vel y advanced topi c i s di scussed i n "Additional
Clipping Planes." Keep i n mi nd that OpenGL reconstructs the edges of pol ygons that get cl i pped.
Viewport Transformation
Recal l i ng the camera anal ogy, the vi ewport transformati on corresponds to the stage where the si ze of
the devel oped photograph i s chosen. Do you want a wal l et−si ze or a poster−si ze photograph? Si nce thi s
i s computer graphi cs, the vi ewport i s the rectangul ar regi on of the wi ndow where the i mage i s drawn.
Figure 3−14 shows a vi ewport that occupi es most of the screen. The vi ewport i s measured i n wi ndow
coordi nates, whi ch refl ect the posi ti on of pi xel s on the screen rel ati ve to the l ower l eft corner of the
wi ndow. Keep i n mi nd that al l verti ces have been transformed by the model vi ew and projecti on
matri ces by thi s poi nt, and verti ces outsi de the vi ewi ng vol ume have been cl i pped.
71
Figure 3−14 A Vi ewport Rectangl e
Defining the Viewport
The wi ndow manager, not OpenGL, i s responsi bl e for openi ng a wi ndow on the screen. However, by
defaul t the vi ewport i s set to the enti re pi xel rectangl e of the wi ndow that’s opened. You use the
glViewport() command to choose a smal l er drawi ng regi on; for exampl e, you can subdi vi de the wi ndow
to create a spl i t−screen effect for mul ti pl e vi ews i n the same wi ndow.
voi d glViewport(GLi nt x, GLi nt y, GLsi zei width, GLsi zei height);
Defi nes a pi xel rectangl e i n the wi ndow i nto whi ch the fi nal i mage i s mapped. The (x, y) parameter
speci fi es the l ower l eft corner of the vi ewport, and width and height are the si ze of the vi ewport
rectangl e. By defaul t, the i ni ti al vi ewport val ues are (0, 0, winWidth, winHeight), where winWidth and
winHeight are the si ze of the wi ndow.
The aspect rati o of a vi ewport shoul d general l y equal the aspect rati o of the vi ewi ng vol ume. I f the two
rati os are di fferent, the projected i mage wi l l be di storted as i t’s mapped to the vi ewport, as shown i n
Figure 3−15. Note that subsequent changes to the si ze of the wi ndow don’t expl i ci tl y affect the
vi ewport. Your appl i cati on shoul d detect wi ndow resi ze events and modi fy the vi ewport appropri atel y.
Figure 3−15 Mappi ng the Vi ewi ng Vol ume to the Vi ewport
For exampl e, thi s sequence maps a square i mage onto a square vi ewport:
gluPerspective(myFovy, 1.0, myNear, myFar);
glViewport(0, 0, 400, 400);
However, the fol l owi ng sequence projects a nonequi l ateral rectangul ar i mage onto a square vi ewport.
72
The i mage appears compressed al ong the x−axi s, as shown i n Figure 3−15.
gluPerspective(myFovy, 2.0, myNear, myFar);
glViewport (0, 0, 400, 400);
To avoi d the di storti on, thi s l i ne coul d be used:
glViewport(0, 0, 400, 200);
Try This
Try This
• Modi fy an exi sti ng program so that an object i s drawn twi ce, i n di fferent vi ewports. You mi ght
draw the object wi th di fferent projecti on and/or vi ewi ng transformati ons for each vi ewport. To
create two si de−by−si de vi ewports, you mi ght i ssue these commands, al ong wi th the appropri ate
model i ng, vi ewi ng, and projecti on transformati ons:
glViewport (0, 0, sizex/2, sizey);
.
.
.
glViewport (sizex/2, 0, sizex/2, sizey);
The Transformed z Coordinate
The z or depth coordi nate i s encoded and then stored duri ng the vi ewport transformati on. You can scal e
z val ues to l i e wi thi n a desi red range wi th the glDepthRange() command. (Chapter 10 di scusses the
depth buffer and the correspondi ng uses for the z coordi nate.) Unl i ke x and y wi ndow coordi nates, z
wi ndow coordi nates are treated by OpenGL as though they al ways range from 0.0 to 1.0.
voi d glDepthRange(GLcl ampd near, GLcl ampd far);
Defi nes an encodi ng for z coordi nates that’s performed duri ng the vi ewport transformati on. The near
and far val ues represent adjustments to the mi ni mum and maxi mum val ues that can be stored i n the
depth buffer. By defaul t, they’re 0.0 and 1.0, respecti vel y, whi ch work for most appl i cati ons. These
parameters are cl amped to l i e wi thi n [0,1].
Troubleshooting Transformations
I t’s pretty easy to get a camera poi nted i n the ri ght di recti on, but i n computer graphi cs, you have to
speci fy posi ti on and di recti on wi th coordi nates and angl es. As we can attest, i t’s al l too easy to achi eve
the wel l −known bl ack−screen effect. Al though any number of thi ngs can go wrong, often you get thi s
effectwhi ch resul ts i n absol utel y nothi ng bei ng drawn i n the wi ndow you open on the screenfrom
i ncorrectl y ai mi ng the "camera" and taki ng a pi cture wi th the model behi nd you. A si mi l ar probl em
ari ses i f you don’t choose a fi el d of vi ew that’s wi de enough to vi ew your objects but narrow enough so
they appear reasonabl y l arge.
I f you fi nd yoursel f exerti ng great programmi ng effort onl y to create a bl ack wi ndow, try these
di agnosti c steps:
1. Check the obvi ous possi bi l i ti es. Make sure your system i s pl ugged i n. Make sure you’re drawi ng
your objects wi th a col or that’s di fferent from the col or wi th whi ch you’re cl eari ng the screen. Make
sure that whatever states you’re usi ng (such as l i ghti ng, texturi ng, al pha bl endi ng, l ogi cal
operati ons, or anti al i asi ng) are correctl y turned on or off, as desi red.
2. Remember that wi th the projecti on commands, the near and far coordi nates measure di stance from
the vi ewpoi nt and that (by defaul t) you’re l ooki ng down the negati ve z axi s. Thus, i f the near val ue
73
i s 1.0 and the far 3.0, objects must have z coordi nates between −1.0 and −3.0 i n order to be vi si bl e.
To ensure that you haven’t cl i pped everythi ng out of your scene, temporari l y set the near and far
cl i ppi ng pl anes to some absurdl y i ncl usi ve val ues, such as 0.001 and 1000000.0. Thi s mi ght
negati vel y affect performance for such operati ons as depth−bufferi ng and fog, but i t mi ght uncover
i nadvertentl y cl i pped objects.
3. Determi ne where the vi ewpoi nt i s, i n whi ch di recti on you’re l ooki ng, and where your objects are. I t
mi ght hel p to create a real three−di mensi onal spaceusi ng your hands, for i nstanceto fi gure
these thi ngs out.
4. Make sure you know where you’re rotati ng about. You mi ght be rotati ng about some arbi trary
l ocati on unl ess you transl ated back to the ori gi n fi rst. I t’s OK to rotate about any poi nt unl ess
you’re expecti ng to rotate about the ori gi n.
5. Check your ai m. Use gluLookAt() to ai m the vi ewi ng vol ume at your objects. Or draw your objects
at or near the ori gi n, and use glTranslate*() as a vi ewi ng transformati on to move the camera far
enough i n the z di recti on onl y, so that the objects fal l wi thi n the vi ewi ng vol ume. Once you’ve
managed to make your objects vi si bl e, try to i ncremental l y change the vi ewi ng vol ume to achi eve
the exact resul t you want, as descri bed bel ow.
Even after you’ve ai med the camera i n the correct di recti on and you can see your objects, they mi ght
appear too smal l or too l arge. I f you’re usi ng gluPerspective(), you mi ght need to al ter the angl e defi ni ng
the fi el d of vi ew by changi ng the val ue of the fi rst parameter for thi s command. You can use
tri gonometry to cal cul ate the desi red fi el d of vi ew gi ven the si ze of the object and i ts di stance from the
vi ewpoi nt: The tangent of hal f the desi red angl e i s hal f the si ze of the object di vi ded by the di stance to
the object (see Figure 3−16). Thus, you can use an arctangent routi ne to compute hal f the desi red
angl e. Example 3−3 assumes such a routi ne, atan2(), whi ch cal cul ates the arctangent gi ven the
l ength of the opposi te and adjacent si des of a ri ght tri angl e. Thi s resul t then needs to be converted from
radi ans to degrees.
Figure 3−16 Usi ng Tri gonometry to Cal cul ate the Fi el d of Vi ew
Example 3−3 Cal cul ati ng Fi el d of Vi ew
#define PI 3.1415926535
74
double calculateAngle(double size, double distance)
{
double radtheta, degtheta;
radtheta = 2.0 * atan2 (size/2.0, distance);
degtheta = (180.0 * radtheta) / PI;
return (degtheta);
}
Of course, typi cal l y you don’t know the exact si ze of an object, and the di stance can onl y be determi ned
between the vi ewpoi nt and a si ngl e poi nt i n your scene. To obtai n a fai rl y good approxi mate val ue, fi nd
the boundi ng box for your scene by determi ni ng the maxi mum and mi ni mum x, y, and z coordi nates of
al l the objects i n your scene. Then cal cul ate the radi us of a boundi ng sphere for that box, and use the
center of the sphere to determi ne the di stance and the radi us to determi ne the si ze.
For exampl e, suppose al l the coordi nates i n your object sati sfy the equati ons −1 ≤x≤ 3, 5 ≤y≤ 7, and −5 ≤z
≤ 5. Then, the center of the boundi ng box i s (1, 6, 0), and the radi us of a boundi ng sphere i s the di stance
from the center of the box to any cornersay (3, 7, 5)or:
I f the vi ewpoi nt i s at (8, 9, 10), the di stance between i t and the center i s
The tangent of the hal f angl e i s 5.477 di vi ded by 12.570, or 0.4357, so the hal f angl e i s 23.54 degrees.
Remember that the fi el d−of−vi ew angl e affects the opti mal posi ti on for the vi ewpoi nt, i f you’re tryi ng to
achi eve a real i sti c i mage. For exampl e, i f your cal cul ati ons i ndi cate that you need a 179−degree fi el d of
vi ew, the vi ewpoi nt must be a fracti on of an i nch from the screen to achi eve real i sm. I f your cal cul ated
fi el d of vi ew i s too l arge, you mi ght need to move the vi ewpoi nt farther away from the object.
Manipulating the Matrix Stacks
The model vi ew and projecti on matri ces you’ve been creati ng, l oadi ng, and mul ti pl yi ng have onl y been
the vi si bl e ti ps of thei r respecti ve i cebergs: Each of these matri ces i s actual l y the topmost member of a
stack of matri ces (see Figure 3−17).
75
Figure 3−17 Model vi ew and Projecti on Matri x Stacks
A stack of matri ces i s useful for constructi ng hi erarchi cal model s, i n whi ch compl i cated objects are
constructed from si mpl er ones. For exampl e, suppose you’re drawi ng an automobi l e that has four
wheel s, each of whi ch i s attached to the car wi th fi ve bol ts. You have a si ngl e routi ne to draw a wheel
and another to draw a bol t, si nce al l the wheel s and al l the bol ts l ook the same. These routi nes draw a
wheel or a bol t i n some conveni ent posi ti on and ori entati on, say centered at the ori gi n wi th i ts axi s
coi nci dent wi th the z axi s. When you draw the car, i ncl udi ng the wheel s and bol ts, you want to cal l the
wheel −drawi ng routi ne four ti mes wi th di fferent transformati ons i n effect each ti me to posi ti on the
wheel s correctl y. As you draw each wheel , you want to draw the bol ts fi ve ti mes, each ti me transl ated
appropri atel y rel ati ve to the wheel .
Suppose for a mi nute that al l you have to do i s draw the car body and the wheel s. The Engl i sh
descri pti on of what you want to do mi ght be somethi ng l i ke thi s:
Draw the car body. Remember where you are, and transl ate to the ri ght front wheel . Draw the wheel
and throw away the l ast transl ati on so your current posi ti on i s back at the ori gi n of the car body.
Remember where you are, and transl ate to the l eft front wheel ....
Si mi l arl y, for each wheel , you want to draw the wheel , remember where you are, and successi vel y
transl ate to each of the posi ti ons that bol ts are drawn, throwi ng away the transformati ons after each
bol t i s drawn.
Si nce the transformati ons are stored as matri ces, a matri x stack provi des an i deal mechani sm for doi ng
thi s sort of successi ve rememberi ng, transl ati ng, and throwi ng away. Al l the matri x operati ons that
have been descri bed so far (glLoadMatrix(), glMultMatrix(), glLoadI dentity(), and the commands that
create speci fi c transformati on matri ces) deal wi th the current matri x, or the top matri x on the stack.
You can control whi ch matri x i s on top wi th the commands that perform stack operati ons:
glPushMatrix(), whi ch copi es the current matri x and adds the copy to the top of the stack, and
glPopMatrix(), whi ch di scards the top matri x on the stack, as shown i n Figure 3−18. (Remember that
the current matri x i s al ways the matri x on the top.) I n effect, glPushMatrix() means "remember where
you are" and glPopMatrix() means "go back to where you were."
76
Figure 3−18 Pushi ng and Poppi ng the Matri x Stack
voi d glPushMatrix(voi d);
Pushes al l matri ces i n the current stack down one l evel . The current stack i s determi ned by
glMatrixMode(). The topmost matri x i s copi ed, so i ts contents are dupl i cated i n both the top and
second−from−the−top matri x. I f too many matri ces are pushed, an error i s generated.
voi d glPopMatrix(voi d);
Pops the top matri x off the stack. What was the second−from−the−top matri x becomes the top matri x.
The current stack i s determi ned by glMatrixMode(). The contents of the topmost matri x are destroyed.
I f the stack contai ns a si ngl e matri x, cal l i ng glPopMatrix() generates an error.
Example 3−4draws an automobi l e, assumi ng the exi stence of routi nes that draw the car body, a
wheel , and a bol t.
Example 3−4 Pushi ng and Poppi ng the Matri x
draw_wheel_and_bolts()
{
long i;
draw_wheel();
for(i=0;i<5;i++){
glPushMatrix();
glRotatef(72.0*i,0.0,0.0,1.0);
glTranslatef(3.0,0.0,0.0);
draw_bolt();
glPopMatrix();
}
}
draw_body_and_wheel_and_bolts()
{
draw_car_body();
glPushMatrix();
glTranslatef(40,0,30); /*move to first wheel
position*/
77
draw_wheel_and_bolts();
glPopMatrix();
glPushMatrix();
glTranslatef(40,0,−30); /*move to 2nd wheel
position*/
draw_wheel_and_bolts();
glPopMatrix();
... /*draw last two wheels similarly*/
}
Thi s code assumes the wheel and bol t axes are coi nci dent wi th the z−axi s, that the bol ts are evenl y
spaced every 72 degrees, 3 uni ts (maybe i nches) from the center of the wheel , and that the front wheel s
are 40 uni ts i n front of and 30 uni ts to the ri ght and l eft of the car’s ori gi n.
A stack i s more effi ci ent than an i ndi vi dual matri x, especi al l y i f the stack i s i mpl emented i n hardware.
When you push a matri x, you don’t need to copy the current data back to the mai n process, and the
hardware may be abl e to copy more than one el ement of the matri x at a ti me. Someti mes you mi ght
want to keep an i denti ty matri x at the bottom of the stack so that you don’t need to cal l
glLoadI dentity() repeatedl y.
The Modelview Matrix Stack
As you’ve seen earl i er i n thi s chapter, the model vi ew matri x contai ns the cumul ati ve product of
mul ti pl yi ng vi ewi ng and model i ng transformati on matri ces. Each vi ewi ng or model i ng transformati on
creates a new matri x that mul ti pl i es the current model vi ew matri x; the resul t, whi ch becomes the new
current matri x, represents the composi te transformati on. The model vi ew matri x stack contai ns at l east
thi rty−two 4×4 matri ces; i ni ti al l y, the topmost matri x i s the i denti ty matri x. Some i mpl ementati ons of
OpenGL may support more than thi rty−two matri ces on the stack. You can use the query command
glGetI ntegerv() wi th the argument GL_MAX_MODELVI EW_STACK_DEPTH to fi nd the maxi mum
al l owabl e number of matri ces.
The Projection Matrix Stack
The projecti on matri x contai ns a matri x for the projecti on transformati on, whi ch descri bes the vi ewi ng
vol ume. General l y, you don’t want to compose projecti on matri ces, so you i ssue glLoadI dentity() before
performi ng a projecti on transformati on. Al so for thi s reason, the projecti on matri x stack need be onl y
two l evel s deep; some OpenGL i mpl ementati ons may al l ow more than two 4×4 matri ces. (You can use
glGetI ntegerv() wi th GL_MAX_PROJECTI ON_STACK_DEPTH as the argument to fi nd the stack
depth.)
One use for a second matri x i n the stack woul d be an appl i cati on that needs to di spl ay a hel p wi ndow
wi th text i n i t, i n addi ti on to i ts normal wi ndow showi ng a three−di mensi onal scene. Si nce text i s most
easi l y drawn wi th an orthographi c projecti on, you coul d change temporari l y to an orthographi c
projecti on, di spl ay the hel p, and then return to your previ ous projecti on:
glMatrixMode(GL_PROJECTION);
glPushMatrix(); /*save the current projection*/
glLoadIdentity();
glOrtho(...); /*set up for displaying help*/
display_the_help();
glPopMatrix();
Note that you’d probabl y have to al so change the model vi ew matri x appropri atel y.
Advanced
I f you know enough mathemati cs, you can create custom projecti on matri ces that perform arbi trary
78
projecti ve transformati ons. For exampl e, the OpenGL and i ts Uti l i ty Li brary have no bui l t−i n
mechani sm for two−poi nt perspecti ve. I f you were tryi ng to emul ate the drawi ngs i n drafti ng texts, you
mi ght need such a projecti on matri x.
Additional Clipping Planes
I n addi ti on to the si x cl i ppi ng pl anes of the vi ewi ng vol ume (l eft, ri ght, bottom, top, near, and far), you
can defi ne up to si x addi ti onal cl i ppi ng pl anes to further restri ct the vi ewi ng vol ume, as shown i n
Figure 3−19. Thi s i s useful for removi ng extraneous objects i n a scenefor exampl e, i f you want to
di spl ay a cutaway vi ew of an object.
Each pl ane i s speci fi ed by the coeffi ci ents of i ts equati on: Ax+By+Cz+D = 0. The cl i ppi ng pl anes are
automati cal l y transformed appropri atel y by model i ng and vi ewi ng transformati ons. The cl i ppi ng
vol ume becomes the i ntersecti on of the vi ewi ng vol ume and al l hal f−spaces defi ned by the addi ti onal
cl i ppi ng pl anes. Remember that pol ygons that get cl i pped automati cal l y have thei r edges reconstructed
appropri atel y by OpenGL.
Figure 3−19 Addi ti onal Cl i ppi ng Pl anes and the Vi ewi ng Vol ume
voi d glClipPlane(GLenum plane, const GLdoubl e *equation);
Defi nes a cl i ppi ng pl ane. The equation argument poi nts to the four coeffi ci ents of the pl ane equati on, A
x+By+Cz+D = 0. Al l poi nts wi th eye coordi nates (x
e
, y
e
, z
e
, w
e
) that sati sfy (A B C D)M−1 (x
e
y
e
z
e
w
e
)T
>= 0 l i e i n the hal f−space defi ned by the pl ane, where M i s the current model vi ew matri x at the ti me
glClipPlane() i s cal l ed. Al l poi nts not i n thi s hal f−space are cl i pped away. The planeargument i s
GL_CLI P_PLANEi, where i i s an i nteger between 0 and 5, speci fyi ng whi ch of the si x cl i ppi ng pl anes to
defi ne.
Note: Cl i ppi ng performed as a resul t of glClipPlane() i s done i n eye coordi nates, not i n cl i p
coordi nates. Thi s di fference i s noti ceabl e i f the projecti on matri x i s si ngul ar (that i s, a real
projecti on matri x that fl attens three−di mensi onal coordi nates to two−di mensi onal ones).
Cl i ppi ng performed i n eye coordi nates conti nues to take pl ace i n three di mensi ons even when
the projecti on matri x i s si ngul ar.
You need to enabl e each addi ti onal cl i ppi ng pl ane you defi ne:
79
glEnable(GL_CLIP_PLANEi);
You can di sabl e a pl ane wi th
glDisable(GL_CLIP_PLANEi);
Some i mpl ementati ons may al l ow more than si x cl i ppi ng pl anes. You can use glGetI ntegerv() wi th
GL_MAX_CLI P_PLANES to fi nd how many cl i ppi ng pl anes are supported.
A Clipping Plane Code Example
Example 3−5renders a wi reframe sphere wi th two cl i ppi ng pl anes that sl i ce away three−quarters of
the ori gi nal sphere, as shown i n Figure 3−20.
Figure 3−20 A Cl i pped Wi reframe Sphere
Example 3−5 A Wi reframe Sphere wi th Two Cl i ppi ng Pl anes: cl i p.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
void display(void)
{
GLdouble eqn[4] = {0.0, 1.0, 0.0, 0.0}; /* y < 0 */
GLdouble eqn2[4] = {1.0, 0.0, 0.0, 0.0}; /* x < 0 */
glClear(GL_COLOR_BUFFER_BIT);
glColor3f (1.0, 1.0, 1.0);
glPushMatrix();
glTranslatef (0.0, 0.0, −5.0);
glClipPlane (GL_CLIP_PLANE0, eqn);
glEnable (GL_CLIP_PLANE0);
glClipPlane (GL_CLIP_PLANE1, eqn2);
glEnable (GL_CLIP_PLANE1);
glRotatef (90.0, 1.0, 0.0, 0.0);
auxWireSphere(1.0);
glPopMatrix();
glFlush();
80
}
void myinit (void)
{
glShadeModel (GL_FLAT);
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
auxInitPosition (0, 0, 500, 500);
auxInitWindow (argv[0]);
myinit ();
auxReshapeFunc (myReshape);
auxMainLoop(display);
}
Try This
Try This
• Try changi ng the coeffi ci ents that descri be the cl i ppi ng pl anes i n Example 3−5.
• Try cal l i ng a model i ng transformati on, such as glRotate*(), to affect glClipPlane(). Make the
cl i ppi ng pl ane move i ndependentl y of the objects i n the scene.
Examples of Composing Several Transformations
Thi s secti on demonstrates how to combi ne several transformati ons to achi eve a parti cul ar resul t. The
two exampl es di scussed are a sol ar system, i n whi ch objects need to rotate on thei r axes as wel l as i n
orbi t around each other, and a robot arm, whi ch has several joi nts that effecti vel y transform coordi nate
systems as they move rel ati ve to each other.
Building a Solar System
The program descri bed i n thi s secti on draws a si mpl e sol ar system wi th a pl anet and a sun, both usi ng
the same sphere−drawi ng routi ne. To wri te thi s program, you need to use glRotate*() for the revol uti on
of the pl anet around the sun and for the rotati on of the pl anet around i ts own axi s. You al so need
glTranslate*() to move the pl anet out to i ts orbi t, away from the ori gi n of the sol ar system. Remember
that you can speci fy the desi red si ze of the two spheres by suppl yi ng the appropri ate arguments for the
auxSphere() routi ne.
To draw the sol ar system, you fi rst want to set up a projecti on and a vi ewi ng transformati on. For thi s
exampl e, gluPerspective() and gluLookAt() are used.
Drawi ng the sun i s strai ghtforward, si nce i t shoul d be l ocated at the ori gi n of the grand, fi xed
81
coordi nate system, whi ch i s where the sphere routi ne pl aces i t. Thus, drawi ng the sun doesn’t requi re
transl ati on; you can use glRotate*() to make the sun rotate about an arbi trary axi s. To draw a pl anet
rotati ng around the sun, as shown i n Figure 3−21, requi res several model i ng transformati ons. The
pl anet needs to rotate about i ts own axi s once a day. And once a year, the pl anet compl etes one
revol uti on around the sun.
Figure 3−21 Pl anet and Sun
To determi ne the order of model i ng transformati ons, vi sual i ze what happens to the l ocal coordi nate
system. An i ni ti al glRotate*() rotates the l ocal coordi nate system that i ni ti al l y coi nci des wi th the grand
coordi nate system. Next, glTranslate*() moves the l ocal coordi nate system to a posi ti on on the pl anet’s
orbi t; the di stance moved shoul d equal the radi us of the orbi t. Thus, the i ni ti al glRotate*() actual l y
determi nes where al ong the orbi t the pl anet i s (or what ti me of year i t i s).
A second glRotate*() rotates the l ocal coordi nate system around the l ocal axes, thus determi ni ng the
ti me of day for the pl anet. Once you’ve i ssued al l these transformati on commands, the pl anet can be
drawn.
I n summary, these are the OpenGL commands to draw the sun and pl anet; the ful l program i s shown
i n Example 3−6.
glPushMatrix();
auxWireSphere(1.0); /* draw sun */
glRotatef ((GLfloat) year, 0.0, 1.0, 0.0);
glTranslatef (2.0, 0.0, 0.0);
glRotatef ((GLfloat) day, 0.0, 1.0, 0.0);
auxWireSphere(0.2); /* draw smaller planet */
glPopMatrix();
Example 3−6 A Pl anetary System: pl anet.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
static int year = 0, day = 0;
void dayAdd (void)
{
day = (day + 10) % 360;
}
82
void daySubtract (void)
{
day = (day − 10) % 360;
}
void yearAdd (void)
{
year = (year + 5) % 360;
}
void yearSubtract (void)
{
year = (year − 5) % 360;
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f (1.0, 1.0, 1.0);
glPushMatrix();
auxWireSphere(1.0); /* draw sun */
glRotatef((GLfloat) year, 0.0, 1.0, 0.0);
glTranslatef (2.0, 0.0, 0.0);
glRotatef((GLfloat) day, 0.0, 1.0, 0.0);
auxWireSphere(0.2); /* draw smaller planet */
glPopMatrix();
glFlush();
}
void myinit(void)
{
glShadeModel(GL_FLAT);
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef (0.0, 0.0, −5.0);
}
int main(int argc, char** argv)
{
auxInitDisplayMode(AUX_SINGLE | AUX_RGBA);
auxInitPosition(0, 0, 500, 500);
auxInitWindow(argv[0]);
myinit();
auxKeyFunc(AUX_LEFT, yearSubtract);
83
auxKeyFunc(AUX_RIGHT, yearAdd);
auxKeyFunc(AUX_UP, dayAdd);
auxKeyFunc(AUX_DOWN, daySubtract);
auxReshapeFunc(myReshape);
auxMainLoop(display);
}
Try This
Try This
• Try addi ng a moon to the pl anet. Or try several moons and addi ti onal pl anets. Hi nt: Use
glPushMatrix() and glPopMatrix() to save and restore the posi ti on and ori entati on of the coordi nate
system at appropri ate moments. I f you’re goi ng to draw several moons around a pl anet, you need to
save the coordi nate system pri or to posi ti oni ng each moon and restore the coordi nate system after
each moon i s drawn.
• Try ti l ti ng the pl anet’s axi s.
Building an Articulated Robot Arm
Thi s secti on di scusses a program that creates an arti cul ated robot arm wi th two or more segments. The
arm shoul d be connected wi th pi vot poi nts at the shoul der, el bow, or other joi nts. Figure 3−22 shows a
si ngl e joi nt of such an arm.
Figure 3−22 A Robot Arm
You can use a scal ed box as a segment of the robot arm, but fi rst you must cal l the appropri ate
model i ng transformati ons to ori ent each segment. Si nce the ori gi n of the l ocal coordi nate system i s
i ni ti al l y at the center of the box, you need to move the l ocal coordi nate system to one edge of the box.
Otherwi se, the box rotates about i ts center rather than the pi vot poi nt.
After you cal l glTranslate*() to establ i sh the pi vot poi nt and glRotate*() to pi vot the box, transl ate back
to the center of the box and then draw the box. Here’s what your code mi ght l ook l i ke for thi s fi rst
segment of the arm (the enti re program i s shown i n Example 3−7):
glTranslatef (−1.0, 0.0, 0.0);
glRotatef ((GLfloat) shoulder_angle, 0.0, 0.0, 1.0);
glTranslatef (1.0, 0.0, 0.0);
auxWireBox(2.0, 0.4, 1.0);
To bui l d a second segment, you need to move the l ocal coordi nate system to the next pi vot poi nt. Si nce
the coordi nate system has previ ousl y been rotated, the x−axi s i s al ready ori ented al ong the l ength of
the rotated arm. Therefore, transl ati ng al ong the x−axi s moves the l ocal coordi nate system to the next
pi vot poi nt. Once i t’s at that pi vot poi nt, you can use the same code to draw the second segment as you
used for the fi rst one. Thi s can be conti nued for an i ndefi ni te number of segments (shoul der, el bow,
wri st, fi ngers).
84
glTranslatef (1.0, 0.0, 0.0);
glRotatef ((GLfloat) elbow_angle, 0.0, 0.0, 1.0);
glTranslatef (1.0, 0.0, 0.0);
auxWireBox(2.0, 0.4, 1.0);
Example 3−7 A Robot Arm: robot.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
static int shoulder = 0, elbow = 0;
void elbowAdd (void)
{
elbow = (elbow + 5) % 360;
}
void elbowSubtract (void)
{
elbow = (elbow − 5) % 360;
}
void shoulderAdd (void)
{
shoulder = (shoulder + 5) % 360;
}
void shoulderSubtract (void)
{
shoulder = (shoulder − 5) % 360;
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f (1.0, 1.0, 1.0);
glPushMatrix();
glTranslatef (−1.0, 0.0, 0.0);
glRotatef ((GLfloat) shoulder, 0.0, 0.0, 1.0);
glTranslatef (1.0, 0.0, 0.0);
auxWireBox(2.0, 0.4, 1.0); /* shoulder */
glTranslatef (1.0, 0.0, 0.0);
glRotatef ((GLfloat) elbow, 0.0, 0.0, 1.0);
glTranslatef (1.0, 0.0, 0.0);
auxWireBox(2.0, 0.4, 1.0); /* elbow */
glPopMatrix();
glFlush();
}
void myinit (void)
85
{
glShadeModel (GL_FLAT);
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(65.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, −5.0);
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
auxInitPosition (0, 0, 400, 400);
auxInitWindow (argv[0]);
myinit ();
auxKeyFunc (AUX_LEFT, shoulderSubtract);
auxKeyFunc (AUX_RIGHT, shoulderAdd);
auxKeyFunc (AUX_UP, elbowAdd);
auxKeyFunc (AUX_DOWN, elbowSubtract);
auxReshapeFunc (myReshape);
auxMainLoop(display);
}
Try This
Try This
• Modi fy Example 3−7 to add addi ti onal segments onto the robot arm.
• Modi fy Example 3−7 to add addi ti onal segments at the same posi ti on. For exampl e, gi ve the robot
arm several "fi ngers" at the wri st, as shown i n Figure 3−23. Hi nt: Use glPushMatrix() and
glPopMatrix() to save and restore the posi ti on and ori entati on of the coordi nate system at the wri st.
I f you’re goi ng to draw fi ngers at the wri st, you need to save the current matri x pri or to posi ti oni ng
each fi nger and restore the current matri x after each fi nger i s drawn.
86
Figure 3−23 Robot Arm wi th Fi ngers
Chapter 4
Display Lists
Chapter Objectives
After readi ng thi s chapter, you’l l be abl e to do the fol l owi ng:
• Understand how cl i ents and servers work together i n a networked OpenGL system
• Understand how di spl ay l i sts can be used al ong wi th commands i n i mmedi ate mode to i mprove
performance
• Maxi mi ze performance by knowi ng how and when to use di spl ay l i sts
A di spl ay l i st i s a group of OpenGL commands that have been stored for l ater executi on. When a
di spl ay l i st i s i nvoked, the commands i n i t are executed i n the order i n whi ch they were i ssued. Most
OpenGL commands can be ei ther stored i n a di spl ay l i st or i ssued i n i mmedi ate mode, whi ch causes
them to be executed i mmedi atel y. You can freel y mi x i mmedi ate−mode programmi ng and di spl ay l i sts
wi thi n a si ngl e program. The programmi ng exampl es you’ve seen so far have used i mmedi ate mode.
Thi s chapter di scusses what di spl ay l i sts are and how best to use them. I t has the fol l owi ng major
secti ons:
• "An Example of Using a Display List"gi ves a bri ef exampl e, showi ng the basi c commands for
usi ng di spl ay l i sts.
• "Display−List Design Philosophy"expl ai ns when to use di spl ay l i sts.
• "Creating and Executing a Display List"di scusses i n detai l the commands for creati ng and
executi ng di spl ay l i sts.
• "Managing Display Lists and Their Indices"expl ai ns how to l et OpenGL generate di spl ay−l i st
i ndi ces for you automati cal l y.
• "Executing Multiple Display Lists"shows how to execute several di spl ay l i sts i n successi on,
usi ng a smal l character set as an exampl e.
• "Encapsulating Mode Changes"tel l s you how to use di spl ay l i sts to swi tch effi ci entl y among
di fferent modes.
An Example of Using a Display List
A di spl ay l i st i s a conveni ent and effi ci ent way to name and organi ze a set of OpenGL commands. For
exampl e, suppose you want to draw a ci rcl e wi th 100 l i ne segments. Wi thout usi ng di spl ay l i sts, you
mi ght wri te i mmedi ate−mode code l i ke thi s:
drawCircle()
{
GLint i;
GLfloat cosine, sine;
glBegin(GL_POLYGON);
for(i=0;i<100;i++){
cosine=cos(i*2*PI/100.0);
sine=sin(i*2*PI/100.0);
glVertex2f(cosine,sine);
}
glEnd();
}
Thi s method i s terri bl y i neffi ci ent because the tri gonometry has to be performed each ti me the ci rcl e i s
87
rendered. I nstead, you coul d save the coordi nates i n a tabl e, and then pul l the coordi nates out of the
tabl e as needed:
drawCircle()
{
GLint i;
GLfloat cosine, sine;
static GLfloat circoords[100][2];
static GLint inited=0;
if(inited==0){
inited=1;
for(i=0;i<100;i++){
circcoords[i][0]=cos(i*2*PI/100.0);
circcoords[i][1]=sin(i*2*PI/100.0);
}
}
glBegin(GL_POLYGON);
for(i=0;i<100;i++)
glVertex2fv(&circcoords[i][0]);
glEnd();
}
Even wi th thi s i mproved method, you sti l l i ncur a sl i ght penal ty from i ncrementi ng and testi ng the
vari abl e i. What you real l y want to do i s draw the ci rcl e once and have OpenGL remember how to draw
i t for l ater use. Thi s i s exactl y what a di spl ay l i st i s for, as shown i n Example 4−1.
Example 4−1 Creati ng a Di spl ay Li st
#define MY_CIRCLE_LIST 1
buildCircle()
{
GLint i;
GLfloat cosine, sine;
glNewList(MY_CIRCLE_LIST, GL_COMPILE);
glBegin(GL_POLYGON);
for(i=0;i<100;i++){
cosine=cos(i*2*PI/100.0);
sine=sin(i*2*PI/100.0);
glVertex2f(cosine,sine);
}
glEnd();
glEndList();
}
Note that the code for drawi ng a ci rcl e i s bracketed by glNewList() and glEndList(). As you mi ght have
guessed, these commands defi ne a di spl ay l i st. The argument MY_CI RCLE_LI ST for glNewList() i s an
i nteger i ndex that uni quel y i denti fi es thi s di spl ay l i st. You can execute the di spl ay l i st l ater wi th thi s
glCallList() command:
glCallList(MY_CIRCLE_LIST);
A di spl ay l i st contai ns onl y OpenGL cal l s. Other cal l si n Example 4−1, the C functi ons cos() and
sin()aren’t stored i n the di spl ay l i st. I nstead, the coordi nates and other vari abl es (such as array
88
contents) are eval uated and copi ed i nto the di spl ay l i st wi th the val ues they have when the l i st i s
compi l ed. After such a l i st has been compi l ed, these val ues can’t be changed. You can del ete a di spl ay
l i st and create a new one, but you can’t edi t an exi sti ng di spl ay l i st.
Display−List Design Philosophy
OpenGL di spl ay l i sts are desi gned to opti mi ze performance, parti cul arl y over networks, but never at
the expense of performance on a l ocal machi ne. A di spl ay l i st resi des wi th the OpenGL server state,
whi ch i n a networked envi ronment mi ght be on a di fferent machi ne than the host (or cl i ent state).
"What Is OpenGL?" di scusses OpenGL’s cl i ent−server model .
To opti mi ze performance, an OpenGL di spl ay l i st i s a cache of commands rather than a dynami c
database. I n other words, once a di spl ay l i st i s created, i t can’t be modi fi ed. I f a di spl ay l i st were
modi fi abl e, performance coul d be reduced by the overhead requi red to search through the di spl ay l i st
and to perform memory management. As porti ons of a modi fi abl e di spl ay l i st were changed, memory
al l ocati on and deal l ocati on mi ght l ead to memory fragmentati on. Usi ng di spl ay l i sts i s typi cal l y at l east
as fast as usi ng i mmedi ate mode. Di spl ay l i sts can substanti al l y i ncrease performanceparti cul arl y
when you i ssue OpenGL routi nes across networks, si nce di spl ay l i sts resi de wi th the server and
network traffi c i s mi ni mi zed.
Even l ocal l y, a di spl ay l i st mi ght be more effi ci ent si nce i t can be processed as i t’s created i nto a form
that’s more compati bl e wi th the graphi cs hardware. The parti cul ar commands that are so opti mi zed
may vary from i mpl ementati on to i mpl ementati on. For exampl e, a command as si mpl e as glRotate*()
mi ght show a si gni fi cant i mprovement i f i t’s i n a di spl ay l i st, si nce the cal cul ati ons to produce the
rotati on matri x aren’t tri vi al (they can i nvol ve square roots and tri gonometri c functi ons). I n the di spl ay
l i st, however, onl y the fi nal rotati on matri x needs to be stored, so a di spl ay−l i st rotati on command can
be executed as fast as the hardware can execute glMultMatrix(). A sophi sti cated OpenGL
i mpl ementati on mi ght even concatenate adjacent transformati on commands i nto a si ngl e matri x
mul ti pl i cati on.
Al though you’re not guaranteed that your OpenGL i mpl ementati on opti mi zes di spl ay l i sts for any
parti cul ar uses, you know that executi on of di spl ay l i sts i sn’t sl ower than executi ng the commands
contai ned wi thi n them. There i s some overhead, however, i nvol ved i n jumpi ng to a di spl ay l i st. I f a
parti cul ar l i st i s smal l , thi s overhead coul d exceed any executi on advantage. The most l i kel y
possi bi l i ti es for opti mi zati on are l i sted bel ow, wi th references to the chapters where the topi cs are
di scussed.
• Matri x operati ons (Chapter 3 ). Most matri x operati ons requi re OpenGL to compute i nverses. Both
the computed matri x and i ts i nverse mi ght be stored by a parti cul ar OpenGL i mpl ementati on i n a
di spl ay l i st.
• Raster bi tmaps and i mages (Chapter 4 ). The format i n whi ch you speci fy raster data i sn’t l i kel y to
be one that’s i deal for the hardware. When a di spl ay l i st i s compi l ed, OpenGL mi ght transform the
data i nto the representati on preferred by the hardware. Thi s can have a si gni fi cant effect on the
speed of raster character drawi ng, si nce character stri ngs usual l y consi st of a seri es of smal l
bi tmaps.
• Li ghts, materi al properti es, and l i ghti ng model s (Chapter 6 ). When you draw a scene wi th
compl ex l i ghti ng condi ti ons, you mi ght change the materi al s for each i tem i n the scene. Setti ng the
materi al s can be sl ow, si nce i t mi ght i nvol ve si gni fi cant cal cul ati ons. I f you put the materi al
defi ni ti ons i n di spl ay l i sts, these cal cul ati ons don’t have to be done each ti me you swi tch materi al s,
si nce onl y the resul ts of the cal cul ati ons need to be stored; as a resul t, renderi ng l i t scenes mi ght be
faster. See "Encapsulating Mode Changes" for more detai l s on usi ng di spl ay l i sts to change such
val ues as l i ghti ng condi ti ons.
• Textures (Chapter 9 ). You mi ght be abl e to maxi mi ze effi ci ency when defi ni ng textures by
compi l i ng them i nto a di spl ay l i st, si nce the hardware texture format mi ght di ffer from the OpenGL
format, and the conversi on can be done at di spl ay−l i st compi l e ti me rather than duri ng di spl ay.
• Pol ygon sti ppl e patterns (Chapter 2 ).
89
Some of the commands to speci fy the properti es l i sted here are context− sensi ti ve, so you need to take
thi s i nto account to ensure opti mum performance. Most si tuati ons where thi s makes a di fference
i nvol ve pi xel −transfer functi ons, l i ghti ng model s, and texturi ng. Si nce al l these topi cs haven’t been
i ntroduced yetthey’re covered i n l ater chaptersthe fol l owi ng exampl e i s a bi t contri ved. Al though
the speci fi cs of thi s exampl e are very unl i kel y, i t i l l ustrates an i mportant pri nci pl e that’s di scussed
agai n i n l ater chapters.
I magi ne an i mpl ementati on of OpenGL that’s opti mi zed to perform matri x transformati ons on verti ces
before stori ng them i n a di spl ay l i st. I f thi s were true, the ti me needed to perform the transformati ons
woul d occur before rather than duri ng di spl ay. Now suppose your code l ooked somethi ng l i ke thi s:
glLoadMatrix(M);
glNewList(1, GL_COMPILE);
draw_some_geometric_objects();
glEndList();
The verti ces i n the objects woul d be compi l ed i nto the di spl ay l i st after havi ng been transformed by
matri x M. Suppose you i nvoke the di spl ay l i st as fol l ows:
glLoadMatrix(N);
glCallList(1);
I n thi s case, the geometri c objects shoul d be drawn usi ng matri x N, but the data i n the di spl ay l i st has
been transformed by matri x M before i t was stored. Thus, the di spl ay l i st has to save two copi es of the
ori gi nal data (both the untransformed and the transformed verti ces), thereby wasti ng memory. I n
addi ti on, the verti ces undergo two transformati ons when perhaps one woul d have suffi ced. I f i nstead
you had defi ned the di spl ay l i st as fol l ows:
glNewList(1, GL_COMPILE);
glLoadMatrix(M);
draw_some_geometry();
glEndList();
then no extra data woul d have to be stored, and ful l opti mi zati on woul d be possi bl e. Of course, i n thi s
second case, you’d want to be sure that matri x M was real l y the transformati on matri x you wanted.
Remember that di spl ay l i sts have some di sadvantages. The buildCircle() exampl e i n Example 4−1
requi res storage for at l east 200 fl oati ng−poi nt numbers, whereas the object code for the ori gi nal
drawCircle() routi ne (i n i mmedi ate mode) i s probabl y a l ot smal l er than that. Another di sadvantage i s
the i mmutabi l i ty of the contents of a di spl ay l i st. To opti mi ze performance, an OpenGL di spl ay l i st
can’t be changed, and i ts contents can’t be read.
Creating and Executing a Display List
As you’ve al ready seen, glNewList() and glEndList() are used to begi n and end the defi ni ti on of a
di spl ay l i st, whi ch i s then i nvoked by suppl yi ng i ts i denti fyi ng i ndex wi th glCallList(). I n Example
4−2, a di spl ay l i st i s created i n the makeList() routi ne. Thi s di spl ay l i st contai ns OpenGL commands to
draw a red tri angl e. Then, i n the display() routi ne, the di spl ay l i st i s executed ten ti mes. I n addi ti on, a
l i ne i s drawn i n i mmedi ate mode. Note that the di spl ay l i st al l ocates memory to store the commands
and the val ues of any necessary vari abl es.
Example 4−2 Usi ng a Di spl ay Li st: l i st.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
90
GLuint listName = 1;
void myinit (void)
{
glNewList (listName, GL_COMPILE);
glColor3f(1.0, 0.0, 0.0);
glBegin (GL_TRIANGLES);
glVertex2f (0.0, 0.0);
glVertex2f (1.0, 0.0);
glVertex2f (0.0, 1.0);
glEnd ();
glTranslatef (1.5, 0.0, 0.0);
glEndList ();
glShadeModel (GL_FLAT);
}
void drawLine (void)
{
glBegin (GL_LINES);
glVertex2f (0.0, 0.5);
glVertex2f (15.0, 0.5);
glEnd ();
}
void display(void)
{
GLuint i;
glClear (GL_COLOR_BUFFER_BIT);
glColor3f(0.0, 1.0, 0.0);
for (i = 0; i < 10; i++)
glCallList (listName);
drawLine ();
glFlush ();
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
gluOrtho2D (0.0, 2.0, −0.5 * (GLfloat) h/(GLfloat) w,
1.5 * (GLfloat) h/(GLfloat) w);
else
gluOrtho2D (0.0, 2.0 * (GLfloat) w/(GLfloat) h, −0.5,
1.5);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
91
auxInitPosition (0, 0, 400, 50);
auxInitWindow (argv[0]);
myinit ();
auxReshapeFunc (myReshape);
auxMainLoop(display);
}
The glTranslatef() routi ne i n the di spl ay l i st al ters the posi ti on of the next object to be drawn. Wi thout
i t, cal l i ng the di spl ay l i st twi ce woul d just draw the tri angl e on top of i tsel f. The drawLine() routi ne,
whi ch i s cal l ed i n i mmedi ate mode, i s al so affected by the ten glTranslatef() cal l s that precede i t. Thus,
i f you cal l transformati on commands wi thi n a di spl ay l i st, don’t forget to take the effect of those
commands i nto account l ater i n your program.
Onl y one di spl ay l i st can be created at a ti me. I n other words, you must eventual l y fol l ow glNewList()
wi th glEndList() to end the creati on of a di spl ay l i st before starti ng another one. As you mi ght expect,
cal l i ng glEndList() wi thout havi ng started a di spl ay l i st generates the error
GL_I NVALI D_OPERATI ON.
voi d glNewList (GLui nt list, GLenum mode);
Speci fi es the start of a di spl ay l i st. OpenGL routi nes that are cal l ed subsequentl y (unti l glEndList() i s
cal l ed to end the di spl ay l i st) are stored i n a di spl ay l i st, except for a few restri cted OpenGL routi nes
that can’t be stored. (Those restri cted routi nes are executed i mmedi atel y, duri ng the creati on of the
di spl ay l i st.) The list parameter i s a uni que posi ti ve i nteger that i denti fi es the di spl ay l i st. The possi bl e
val ues for the modeparameter are GL_COMPI LE and GL_COMPI LE_AND_EXECUTE. Use
GL_COMPI LE i f you don’t want the fol l owi ng OpenGL commands executed as they’re pl aced i n the
di spl ay l i st; to cause the commands to be executed i mmedi atel y as wel l as pl aced i n the di spl ay l i st for
l ater use, speci fy GL_COMPI LE_AND_EXECUTE.
voi d glEndList (voi d);
Marks the end of a di spl ay l i st.
What’s Stored in a Display List
When you’re bui l di ng a di spl ay l i st, onl y the val ues for expressi ons are stored i n the l i st. Thus, i f val ues
i n an array are subsequentl y changed, for exampl e, the di spl ay−l i st val ues don’t change. I n the
fol l owi ng code fragment, the di spl ay l i st contai ns a command to set the current col or to bl ack (0.0, 0.0,
0.0). The subsequent change of the val ue of the color_vector array to red (1.0, 0.0, 0.0) has no effect on
the di spl ay l i st because the di spl ay l i st contai ns the val ues that were i n effect when i t was created.
GLfloat color_vector[3]={0.0,0.0,0.0};
glNewList(1,GL_COMPILE);
glColor3fv(color_vector);
glEndList();
color_vector[0]=1.0;
Not al l OpenGL commands can be stored and executed from wi thi n a di spl ay l i st. General l y,
commands that pass parameters by reference or that return a val ue can’t be stored i n a di spl ay l i st,
si nce the l i st mi ght be cal l ed outsi de the scope of where the parameters are ori gi nal l y defi ned. I f such
commands are cal l ed when maki ng a di spl ay l i st, they’re executed i mmedi atel y and aren’t stored i n the
di spl ay l i st. Here are the OpenGL commands that aren’t stored i n a di spl ay l i st (al so, note that
glNewList() generates an error i f i t’s cal l ed whi l e you’re creati ng a di spl ay l i st). Some of these
commands haven’t been descri bed yet; you can l ook i n the i ndex to see where they’re di scussed.
gl Del eteLi sts() gl I sEnabl ed()
gl FeedbackBuffer() gl I sLi st()
92
gl Fi ni sh() gl Pi xel Store()
gl Fl ush() gl ReadPi xel s()
gl GenLi sts() gl RenderMode()
gl Get*() gl Sel ectBuffer()
To understand more cl earl y why these commands can’t be stored i n a di spl ay l i st, remember that when
you’re usi ng OpenGL across a network, the cl i ent may be on one machi ne and the server on another.
After a di spl ay l i st i s created, i t resi des wi th the server, so the server can’t rel y on the cl i ent for any
i nformati on rel ated to the di spl ay l i st. I f queryi ng commands, such as glGet*() or glI s*(), were al l owed
i n a di spl ay l i st, the cal l i ng program woul d be surpri sed at random ti mes by data returned over the
network. Wi thout parsi ng the di spl ay l i st as i t was sent, the cal l i ng program woul dn’t know where to
put the data. Thus, any command that returns a val ue can’t be stored i n a di spl ay l i st. Other routi nes
such as glFlush() and glFinish()can’t be stored i n a di spl ay l i st because they depend on i nformati on
about the cl i ent state. Fi nal l y, commands that change a state val ue mai ntai ned by the cl i ent can’t be
stored i n a di spl ay l i st.
Executing a Display List
After you’ve created a di spl ay l i st, you can execute i t by cal l i ng glCallList(). Natural l y, you can execute
the same di spl ay l i st many ti mes, and you can mi x cal l s to execute di spl ay l i sts wi th cal l s to perform
i mmedi ate−mode graphi cs, as you’ve al ready seen.
voi d glCallList (GLui nt list);
Thi s routi ne executes the di spl ay l i st speci fi ed by list. The commands i n the di spl ay l i st are executed i n
the order they were saved, just as i f they were i ssued wi thout usi ng a di spl ay l i st. I f list hasn’t been
defi ned, nothi ng happens.
Si nce a di spl ay l i st can contai n cal l s that change the val ue of OpenGL state vari abl es, these val ues
change as the di spl ay l i st i s executed, just as i f the commands were cal l ed i n i mmedi ate mode. The
changes to OpenGL state persi st after executi on of the di spl ay l i st i s compl eted. I n Example 4−2, the
changes to the current col or and current matri x made duri ng the executi on of the di spl ay l i st remai n i n
effect after i t’s been cal l ed, as shown i n Example 4−3.
Example 4−3 Persi stence of State Changes after Executi on of a Di spl ay Li st
glNewList(listIndex,GL_COMPILE);
glColor3f(1.0, 0.0, 0.0);
glBegin(GL_POLYGON);
glVertex2f(0.0,0.0);
glVertex2f(1.0,0.0);
glVertex2f(0.0,1.0);
glEnd();
glTranslatef(1.5,0.0,0.0);
glEndList();
Someti mes you want state changes to persi st, but other ti mes you want to save the val ues of state
vari abl es before executi ng a di spl ay l i st and then restore these val ues after the l i st has executed. Use
glPushAttrib() to save a group of state vari abl es and glPopAttrib() to restore the val ues when you’re
ready for them. (See Appendix B for more i nformati on about these commands.) To save and restore
the current matri x, use glPushMatrix() and glPopMatrix() as descri bed i n "Manipulating the Matrix
Stacks." To restore the state vari abl es i n Example 4−3, you mi ght use the code shown i n Example
4−4.
Example 4−4 Restori ng State Vari abl es wi thi n a Di spl ay Li st
93
glNewList(listIndex,GL_COMPILE);
glPushMatrix();
glPushAttrib(GL_CURRENT_BIT);
glColor3f(1.0, 0.0, 0.0);
glBegin(GL_POLYGON);
glVertex2f(0.0,0.0);
glVertex2f(1.0,0.0);
glVertex2f(0.0,1.0);
glEnd();
glTranslatef(1.5,0.0,0.0);
glPopAttrib();
glPopMatrix();
glEndList();
Thus, i f you used thi s ki nd of a di spl ay l i st that restores val ues, the code i n Example 4−5 woul d draw
a green, untransl ated l i ne. Wi th the di spl ay l i st i n Example 4−3 that doesn’t save and restore val ues,
the l i ne drawn woul d be red, and i ts posi ti on woul d be transl ated.
Example 4−5 Usi ng a Di spl ay Li st That Restores State Vari abl es
void display(void)
{
GLint i;
glClear (GL_COLOR_BUFFER_BIT);
glColor3f(0.0, 1.0, 0.0);
for (i = 0; i < 10; i++)
glCallList (listIndex);
drawLine ();
glFlush ();
}
You can cal l glCallList() from anywhere wi thi n a program, as l ong as i ts OpenGL context i s sti l l acti ve.
A di spl ay l i st can be created i n one routi ne and executed i n a di fferent one, si nce i ts i ndex uni quel y
i denti fi es i t. Al so, there i s no faci l i ty to save the contents of a di spl ay l i st i nto a data fi l e, nor a faci l i ty to
create a di spl ay l i st from a fi l e. I n thi s sense, a di spl ay l i st i s desi gned for temporary use. Al so, a
di spl ay l i st i s destroyed when i ts OpenGL context i s destroyed.
Hierarchical Display Lists
You can create a hierarchical display list, whi ch i s a di spl ay l i st that executes another di spl ay l i st, by
cal l i ng glCallList() between a glNewList() and glEndList() pai r. A hi erarchi cal di spl ay l i st i s useful for
an object that’s made of components, especi al l y i f some of those components are used more than once.
For exampl e, thi s i s a di spl ay l i st that renders a bi cycl e by cal l i ng other di spl ay l i sts to render parts of
the bi cycl e:
glNewList(listIndex,GL_COMPILE);
glCallList(handlebars);
glCallList(frame);
glTranslatef(1.0,0.0,0.0);
glCallList(wheel);
glTranslatef(3.0,0.0,0.0);
glCallList(wheel);
glEndList();
To avoi d i nfi ni te recursi on, there’s a l i mi t on the nesti ng l evel of di spl ay l i sts; the l i mi t i s at l east 64,
94
but i t mi ght be hi gher, dependi ng on the i mpl ementati on. To determi ne the nesti ng l i mi t for your
i mpl ementati on of OpenGL, cal l
glGetIntegerv(GL_MAX_LIST_NESTING, GLint *data);
OpenGL al l ows you to create a di spl ay l i st that cal l s another l i st that hasn’t been created yet. Nothi ng
happens when the fi rst l i st cal l s the second, undefi ned one.
You can use a hi erarchi cal di spl ay l i st to approxi mate an edi tabl e di spl ay l i st by wrappi ng a l i st around
several l ower−l evel l i sts. For exampl e, to put a pol ygon i n a di spl ay l i st whi l e al l owi ng yoursel f to be
abl e to easi l y edi t i ts verti ces, you coul d use the code i n Example 4−6.
Example 4−6 Usi ng a Hi erarchi cal Di spl ay Li st
glNewList(1,GL_COMPILE);
glVertex3f(v1);
glEndList();
glNewList(2,GL_COMPILE);
glVertex3f(v2);
glEndList();
glNewList(3,GL_COMPILE);
glVertex3f(v3);
glEndList();
glNewList(4,GL_COMPILE);
glBegin(GL_POLYGON);
glCallList(1);
glCallList(2);
glCallList(3);
glEnd();
glEndList();
To render the pol ygon, cal l di spl ay l i st number 4. To edi t a vertex, you need onl y recreate the si ngl e
di spl ay l i st correspondi ng to that vertex. Si nce an i ndex number uni quel y i denti fi es a di spl ay l i st,
creati ng one wi th the same i ndex as an exi sti ng one automati cal l y del etes the ol d one. Keep i n mi nd
that thi s techni que doesn’t necessari l y provi de opti mal memory usage or peak performance, but i t’s
acceptabl e and useful i n some cases.
Managing Display Lists and Their Indices
So far, we’ve used an arbi trary posi ti ve i nteger as a di spl ay−l i st i ndex. Thi s coul d be dangerous i n
practi ce because you mi ght acci dental l y choose an i ndex that’s al ready i n use, thereby overwri ti ng an
exi sti ng di spl ay l i st. To avoi d acci dental del eti ons, use glGenLists() to generate an unused i ndex and
glI sList() to determi ne whether a speci fi c i ndex i s i n use. You can expl i ci tl y del ete a speci fi c di spl ay l i st
or a range of l i sts wi th glDeleteLists().
GLui nt glGenLists(GLsi zei range);
Al l ocates rangenumber of conti guous, previ ousl y unal l ocated di spl ay−l i st i ndi ces. The i nteger returned
i s the i ndex that marks the begi nni ng of a conti guous bl ock of empty di spl ay−l i st i ndi ces. The returned
i ndi ces are al l marked as empty and used, so subsequent cal l s to glGenLists() don’t return these i ndi ces
unti l they’re del eted. Zero i s returned i f the requested number of i ndi ces i sn’t avai l abl e, or i f rangei s
zero.
GLbool ean glI sList(GLui nt list);
95
Returns TRUE i f list i s al ready used for a di spl ay l i st and FALSE otherwi se.
I n the fol l owi ng exampl e, a si ngl e i ndex i s requested, and i f i t proves to be avai l abl e, i t’s used to create
a new di spl ay l i st:
listIndex=glGenLists(1);
if(listIndex!=0) {
glNewList(listIndex,GL_COMPILE);
...
glEndList();
}
The command glDeleteLists() del etes a conti guous group of di spl ay l i sts, thereby maki ng thei r i ndi ces
avai l abl e agai n.
voi d glDeleteLists(GLui nt list, GLsi zei range);
Del etes rangedi spl ay l i sts, starti ng at the i ndex speci fi ed by list. An attempt to del ete a l i st that has
never been created i s i gnored.
Executing Multiple Display Lists
OpenGL provi des an effi ci ent mechani sm to execute several di spl ay l i sts i n successi on. Thi s
mechani sm requi res that you put the di spl ay−l i st i ndi ces i n an array and cal l glCallLists(). An obvi ous
use for such a mechani sm occurs when di spl ay−l i st i ndi ces correspond to meani ngful val ues. For
exampl e, i f you’re creati ng a font, each di spl ay−l i st i ndex mi ght correspond to the ASCI I val ue of a
character i n that font. To have several such fonts, you woul d need to establ i sh a di fferent i ni ti al
di spl ay−l i st i ndex for each font. You can speci fy thi s i ni ti al i ndex by usi ng glListBase() before cal l i ng
glCallLists().
voi d glListBase(GLui nt base);
Speci fi es the offset that’s added to the di spl ay−l i st i ndi ces i n glCallLists() to obtai n the fi nal
di spl ay−l i st i ndi ces. The defaul t di spl ay−l i st base i s 0. The l i st base has no effect on glCallList(), whi ch
executes onl y one di spl ay l i st, or on glNewList().
voi d glCallLists(GLsi zei n, GLenum type, const GLvoi d *lists);
Executes n di spl ay l i sts. The i ndi ces of the l i sts to be executed are computed by addi ng the offset
i ndi cated by the current di spl ay−l i st base (speci fi ed wi th glListBase()) to the si gned i nteger val ues i n
the array poi nted to by lists.
The typeparameter i ndi cates the data type and the "stri de" (or si ze) of each el ement i n the array of
i ndi ces. I t’s usual l y one of these constants: GL_BYTE, GL_UNSI GNED_BYTE, GL_SHORT,
GL_UNSI GNED_SHORT, GL_I NT, GL_UNSI GNED_I NT, or GL_FLOAT. I t can al so be GL_2_BYTES,
GL_3_BYTES, or GL_4_BYTES, i n whi ch case sequences of two, three, or four bytes are shi fted and
added together, byte by byte, to cal cul ate the di spl ay−l i st offset, usi ng thi s al gori thm:
/* b = 2, 3, or 4; bytes are numbered 0, 1, 2, 3 in array */
offset = 0;
for (i = 0; i < b; i++) {
offset = offset << 8;
offset += byte[i];
}
index = offset + listbase;
Thi s means that for mul ti pl e−byte data, as bytes are taken from the array i n order, the hi ghest−order
96
data comes fi rst.
As an exampl e of the use of mul ti pl e di spl ay l i sts, l ook at the program fragments i n Example 4−7
taken from the ful l program i n Example 4−8. Thi s program draws characters wi th a stroked font (a
set of l etters made from l i ne segments). The routi ne initStrokedFont() sets up the di spl ay−l i st i ndi ces
for each l etter so they correspond wi th thei r ASCI I val ues.
Example 4−7 Defi ni ng Mul ti pl e Di spl ay Li sts
void initStrokedFont(void)
{
GLuint base;
base = glGenLists (128);
glListBase(base);
glNewList(base+’A’, GL_COMPILE);
drawLetter(Adata); glEndList();
glNewList(base+’E’, GL_COMPILE);
drawLetter(Edata); glEndList();
glNewList(base+’P’, GL_COMPILE);
drawLetter(Pdata); glEndList();
glNewList(base+’R’, GL_COMPILE);
drawLetter(Rdata); glEndList();
glNewList(base+’S’, GL_COMPILE);
drawLetter(Sdata); glEndList();
glNewList(base+’ ’, GL_COMPILE); /* space character */
glTranslatef(8.0, 0.0, 0.0); glEndList();
}
The glGenLists() command al l ocates 128 conti guous di spl ay−l i st i ndi ces. The fi rst of the conti guous
i ndi ces becomes the di spl ay−l i st base. A di spl ay l i st i s made for each l etter; each di spl ay−l i st i ndex i s
the sum of the base and the ASCI I val ue of that l etter. I n thi s exampl e, onl y a few l etters and the space
character are created.
After the di spl ay l i sts have been created, glCallLists() can be cal l ed to execute the di spl ay l i sts. For
exampl e, you can pass a character stri ng to the subrouti ne printStrokedString():
void printStrokedString(GLbyte *s)
{
GLint len = strlen(s);
glCallLists(len, GL_BYTE, s);
}
The ASCI I val ue for each l etter i n the stri ng i s used as the offset i nto the di spl ay−l i st i ndi ces. The
current l i st base i s added to the ASCI I val ue of each l etter to determi ne the fi nal di spl ay−l i st i ndex to
be executed. The output produced by Example 4−8 i s shown i n Figure 4−1 .
Figure 4−1 Exampl e of a Stroked Font That Defi nes the Characters A, E, P, R, S
97
Example 4−8 Usi ng Mul ti pl e Di spl ay Li sts to Defi ne a Stroked Font: stroke.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
#define PT 1
#define STROKE 2
#define END 3
typedef struct charpoint {
GLfloat x, y;
int type;
} CP;
CP Adata[] = {
{ 0, 0, PT}, {0, 9, PT}, {1, 10, PT}, {4, 10, PT},
{5, 9, PT}, {5, 0, STROKE}, {0, 5, PT}, {5, 5, END}
};
CP Edata[] = {
{5, 0, PT}, {0, 0, PT}, {0, 10, PT}, {5, 10, STROKE},
{0, 5, PT}, {4, 5, END}
};
CP Pdata[] = {
{0, 0, PT}, {0, 10, PT}, {4, 10, PT}, {5, 9, PT},
{5, 6, PT}, {4, 5, PT}, {0, 5, END}
};
CP Rdata[] = {
{0, 0, PT}, {0, 10, PT}, {4, 10, PT}, {5, 9, PT},
{5, 6, PT}, {4, 5, PT}, {0, 5, STROKE}, {3, 5, PT},
{5, 0, END}
};
CP Sdata[] = {
{0, 1, PT}, {1, 0, PT}, {4, 0, PT}, {5, 1, PT}, {5, 4, PT},
{4, 5, PT}, {1, 5, PT}, {0, 6, PT}, {0, 9, PT}, {1, 10, PT},
{4, 10, PT}, {5, 9, END}
};
void drawLetter(CP *l)
{
glBegin(GL_LINE_STRIP);
while (1) {
switch (l−>type) {
case PT:
glVertex2fv(&l−>x);
break;
case STROKE:
glVertex2fv(&l−>x);
glEnd();
98
glBegin(GL_LINE_STRIP);
break;
case END:
glVertex2fv(&l−>x);
glEnd();
glTranslatef(8.0, 0.0, 0.0);
return;
}
l++;
}
}
void myinit (void)
{
GLuint base;
glShadeModel (GL_FLAT);
base = glGenLists (128);
glListBase(base);
glNewList(base+’A’, GL_COMPILE); drawLetter(Adata);
glEndList();
glNewList(base+’E’, GL_COMPILE); drawLetter(Edata);
glEndList();
glNewList(base+’P’, GL_COMPILE); drawLetter(Pdata);
glEndList();
glNewList(base+’R’, GL_COMPILE); drawLetter(Rdata);
glEndList();
glNewList(base+’S’, GL_COMPILE); drawLetter(Sdata);
glEndList();
glNewList(base+’ ‘, GL_COMPILE);
glTranslatef(8.0, 0.0, 0.0); glEndList();
}
char *test1 = "A SPARE SERAPE APPEARS AS";
char *test2 = "APES PREPARE RARE PEPPERS";
void printStrokedString(char *s)
{
GLsizei len = strlen(s);
glCallLists(len, GL_BYTE, (GLbyte *)s);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
glPushMatrix();
glScalef(2.0, 2.0, 2.0);
glTranslatef(10.0, 30.0, 0.0);
printStrokedString(test1);
glPopMatrix();
glPushMatrix();
glScalef(2.0, 2.0, 2.0);
99
glTranslatef(10.0, 13.0, 0.0);
printStrokedString(test2);
glPopMatrix();
glFlush();
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
auxInitPosition (0, 0, 440, 120);
auxInitWindow (argv[0]);
myinit ();
auxMainLoop(display);
}
Encapsulating Mode Changes
You can use di spl ay l i sts to organi ze and store groups of commands to change vari ous modes or set
vari ous parameters. When you want to swi tch from one group of setti ngs to another, usi ng di spl ay l i sts
mi ght be more effi ci ent than maki ng the cal l s di rectl y, si nce the setti ngs mi ght be cached i n a format
that matches the requi rements of your graphi cs system.
Di spl ay l i sts are l i kel y to be more effi ci ent when you’re swi tchi ng between mul ti pl e texture maps, for
exampl e. (Texture mappi ng i s descri bed i n Chapter 9 .) Suppose you have two di fferent textures that
are fai rl y l arge, as textures tend to be, but that both of them fi t i nto texture memory. Wi thout di spl ay
l i sts, you woul d have to l oad the data for the fi rst texture, use i t to draw some objects, wai t for the
second texture to be l oaded i nto memory, and then use i t for drawi ng. When you want to swi tch back to
the fi rst texture, i t woul d have to be l oaded i nto memory agai n rather than bei ng pl ucked out of texture
memory. There’s no way for OpenGL to know that i t’s al ready been stored wi thout the di spl ay−l i st
mechani sm to provi de a "handl e" to i denti fy i t. Wi th di spl ay l i sts, both textures can be l oaded i nto
texture memory once and then used as often as necessary wi thout havi ng to be rel oaded.
Another case where di spl ay l i sts are l i kel y to be more effi ci ent than i mmedi ate mode i s for swi tchi ng
among vari ous l i ghti ng, l i ghti ng−model , and materi al −parameter setti ngs. (These topi cs are di scussed
i n Chapter 6 .) You mi ght al so use di spl ay l i sts for sti ppl e patterns, fog parameters, and
cl i ppi ng−pl ane equati ons. I n general , you’re guaranteed that executi ng di spl ay l i sts i s at l east as fast as
maki ng the rel evant cal l s di rectl y, but remember that some overhead i s i nvol ved i n jumpi ng to a
di spl ay l i st.
Example 4−9shows how to use di spl ay l i sts to swi tch among three di fferent l i ne sti ppl es. Fi rst, you
cal l glGenLists() to al l ocate a di spl ay l i st for each sti ppl e pattern and create a di spl ay l i st for each
pattern. Then, you use glCallList() to swi tch from one sti ppl e pattern to another.
Example 4−9 Usi ng Di spl ay Li sts for Mode Changes
GLuint offset;
offset = glGenLists (3);
glNewList (offset, GL_COMPILE);
glDisable (GL_LINE_STIPPLE);
glEndList ();
glNewList (offset+1, GL_COMPILE);
glEnable (GL_LINE_STIPPLE);
100
glLineStipple (1, 0x0F0F);
glEndList ();
glNewList (offset+2, GL_COMPILE);
glEnable (GL_LINE_STIPPLE);
glLineStipple (1, 0x1111);
glEndList ();
#define drawOneLine(x1,y1,x2,y2) glBegin(GL_LINES); \
glVertex2f ((x1),(y1)); glVertex2f ((x2),(y2)); glEnd();
glCallList (offset);
drawOneLine (50.0, 125.0, 350.0, 125.0);
glCallList (offset+1);
drawOneLine (50.0, 100.0, 350.0, 100.0);
glCallList (offset+2);
drawOneLine (50.0, 75.0, 350.0, 75.0);
Chapter 5
Color
Chapter Objectives
After readi ng thi s chapter, you’l l be abl e to do the fol l owi ng:
• Deci de between usi ng RGBA or col or−i ndex mode for your appl i cati on
• Speci fy desi red col ors for drawi ng objects
• Use smooth shadi ng to draw a si ngl e pol ygon wi th more than one col or
The goal of al most al l OpenGL appl i cati ons i s to draw col or pi ctures i n a wi ndow on the screen. The
wi ndow i s a rectangul ar array of pi xel s, each of whi ch contai ns and di spl ays i ts own col or. Thus, i n a
sense, the poi nt of al l the cal cul ati ons performed by an OpenGL i mpl ementati oncal cul ati ons that
take i nto account OpenGL commands, state i nformati on, and val ues of parametersi s to determi ne
the fi nal col or of every pi xel that’s to be drawn i n the wi ndow. Thi s chapter expl ai ns the commands for
speci fyi ng col ors and how OpenGL i nterprets them i n the fol l owi ng major secti ons:
• "Color Perception"di scusses how the eye percei ves col or.
• "Computer Color"descri bes the rel ati onshi p between pi xel s on a computer moni tor and thei r
col ors; i t al so defi nes the two di spl ay modes, RGBA and col or i ndex.
• "RGBA versus Color−Index Mode"expl ai ns how the two di spl ay modes use graphi cs hardware
and how to deci de whi ch mode to use.
• "Specifying a Color and a Shading Model"descri bes the OpenGL commands you use to speci fy
the desi red col or or shadi ng model .
Color Perception
Physi cal l y, l i ght i s composed of photonsti ny parti cl es of l i ght, each travel i ng al ong i ts own path, and
each vi brati ng at i ts own frequency (or wavel ength, or energyany one of frequency, wavel ength, or
energy determi nes the others). A photon i s compl etel y characteri zed by i ts posi ti on, di recti on, and
frequency/wavel ength/energy. Photons wi th wavel engths rangi ng from about 390 nanometers (nm)
(vi ol et) and 720 nm (red) cover the col ors of the vi si bl e spectrum, formi ng the col ors of a rai nbow
(vi ol et, i ndi go, bl ue, green, yel l ow, orange, red). However, your eyes percei ve l ots of col ors that aren’t i n
101
the rai nbowwhi te, bl ack, brown, and pi nk, for exampl e. How does thi s happen?
What your eye actual l y sees i s a mi xture of photons of di fferent frequenci es. Real l i ght sources are
characteri zed by the di stri buti on of photon frequenci es they emi t. I deal whi te l i ght consi sts of an equal
amount of l i ght of al l frequenci es. Laser l i ght i s usual l y very pure, and al l photons have al most
i denti cal frequenci es (and di recti on and phase, as wel l ). Li ght from a sodi um−vapor l amp has more
l i ght i n the yel l ow frequency. Li ght from most stars i n space has a di stri buti on that depends heavi l y on
thei r temperatures (bl ack−body radi ati on). The frequency di stri buti on of l i ght from most sources i n
your i mmedi ate envi ronment i s more compl i cated.
The human eye percei ves col or when certai n cel l s i n the reti na (cal l ed conecells, or just cones) become
exci ted after bei ng struck by photons. The three di fferent ki nds of cone cel l s respond best to three
di fferent wavel engths of l i ght: one type of cone cel l responds best to red l i ght, one type to green, and the
other to bl ue. (A person who i s col or−bl i nd i s usual l y mi ssi ng one or more types of cone cel l s.) When a
gi ven mi xture of photons enters the eye, the cone cel l s i n the reti na regi ster di fferent degrees of
exci tati on dependi ng on thei r types, and i f a di fferent mi xture of photons comes i n that happens to
exci te the three types of cone cel l s to the same degrees, i ts col or i s i ndi sti ngui shabl e from that of the
fi rst mi xture.
Si nce each col or i s recorded by the eye as the l evel s of exci tati on of the cone cel l s by the i ncomi ng
photons, the eye can percei ve col ors that aren’t i n the spectrum produced by a pri sm or rai nbow. For
exampl e, i f you send a mi xture of red and bl ue photons so that both the red and bl ue cones i n the reti na
are exci ted, your eye sees i t as magenta, whi ch i sn’t i n the spectrum. Other combi nati ons gi ve browns,
turquoi ses, and mauves, none of whi ch appear i n the col or spectrum.
A computer−graphi cs moni tor emul ates vi si bl e col ors by l i ghti ng pi xel s wi th a combi nati on of red,
green, and bl ue l i ght i n proporti ons that exci te the red−, green−, and bl ue−sensi ti ve cones i n the reti na
i n such a way that i t matches the exci tati on l evel s generated by the photon mi x i t’s tryi ng to emul ate. I f
humans had more types of cone cel l s, some that were yel l ow−sensi ti ve for exampl e, col or moni tors
woul d probabl y have a yel l ow gun as wel l , and we’d use RGBY (red, green, bl ue, yel l ow) quadrupl es to
speci fy col ors. And i f everyone were col or−bl i nd i n the same way, thi s chapter woul d be si mpl er.
To di spl ay a parti cul ar col or, the moni tor sends the ri ght amounts of red, green, and bl ue l i ght to
appropri atel y sti mul ate the di fferent types of cone cel l s i n your eye. A col or moni tor can send di fferent
proporti ons of red, green, and bl ue to each of the pi xel s, and the eye sees a mi l l i on or so pi npoi nts of
l i ght, each wi th i ts own col or.
Thi s secti on consi ders onl y how the eye percei ves combi nati ons of photons that enter i t. The si tuati on
for l i ght bounci ng off of materi al s and enteri ng the eye i s even more compl exwhi te l i ght bounci ng off
a red bal l wi l l appear red, or yel l ow l i ght shi ni ng through bl ue gl ass appears al most bl ack, for exampl e.
These effects are di scussed i n "Real−World and OpenGL Lighting."
Computer Color
On a col or computer screen, the hardware causes each pi xel on the screen to emi t di fferent amounts of
red, green, and bl ue l i ght. These are cal l ed the R, G, and B val ues. They’re often packed together
(someti mes wi th a fourth val ue, cal l ed al pha, or A), and the packed val ue i s cal l ed the RGB (or RGBA)
val ue. (See "Blending" for an expl anati on of the al pha val ues.) The col or i nformati on at each pi xel can
be stored ei ther i n RGBA mode, i n whi ch the R, G, B, and possi bl y A val ues are kept for each pi xel , or i n
col or−i ndex mode, i n whi ch a si ngl e number (cal l ed the col or i ndex) i s stored for each pi xel . Each col or
i ndex i ndi cates an entry i n a tabl e that defi nes a parti cul ar set of R, G, and B val ues. Such a tabl e i s
cal l ed a col or map.
I n col or−i ndex mode, you mi ght want to al ter the val ues i n the col or map. Si nce col or maps are
control l ed by the wi ndow system, there are no OpenGL commands to do thi s. Al l the exampl es i n thi s
book i ni ti al i ze the col or−di spl ay mode at the ti me the wi ndow i s opened by usi ng routi nes from the
auxi l i ary l i brary, whi ch i s descri bed i n detai l i n Appendix E .
102
Di fferent graphi cs hardware vari es greatl y i n both the si ze of the pi xel array and the number of col ors
that can be di spl ayed at each pi xel . On a gi ven graphi cs system, every pi xel has the same amount of
memory for stori ng i ts col or, and al l the memory for al l the pi xel s i s cal l ed the color buffer. The si ze of a
buffer i s usual l y measured i n bi ts, so an 8−bi t buffer coul d store 8 bi ts of data (256 possi bl e di fferent
col ors) for each pi xel . The si ze of the possi bl e buffers vari es from machi ne to machi ne. (See Chapter 10
for more i nformati on.)
The R, G, and B val ues can range from 0.0 (none) to 1.0 (ful l i ntensi ty). For exampl e, R = 0.0, G = 0.0,
and B = 1.0 represents the bri ghtest possi bl e bl ue. I f R, G, and B are al l 0.0, the pi xel i s bl ack; i f al l are
1.0, the pi xel i s drawn i n the bri ghtest whi te that can be di spl ayed on the screen. Bl endi ng green and
bl ue creates shades of cyan. Bl ue and red combi ne for magenta. Red and green create yel l ow. To hel p
you create the col ors you want from the R, G, and B components, l ook at the col or cube shown i n
Figure J −12. The axes of thi s cube represent i ntensi ti es of red, bl ue, and green. A bl ack−and−whi te
versi on of the cube i s shown i n Figure 5−1 .
Figure 5−1 The Col or Cube i n Bl ack and Whi te
The commands to speci fy a col or for an object (i n thi s case, a poi nt) can be as si mpl e as thi s:
glColor3f (1.0, 0.0, 0.0); /* the current RGB color is red: */
/* full red, no green, no blue. */
glBegin (GL_POINTS);
glVertex3fv (point_array);
glEnd ();
I n certai n modes (for exampl e, i f l i ghti ng or texturi ng cal cul ati ons are performed), the assi gned col or
mi ght go through other operati ons before arri vi ng i n the framebuffer as a val ue representi ng a col or for
103
a pi xel . I n fact, the col or of a pi xel i s determi ned by a l engthy sequence of operati ons.
Earl y i n a program’s executi on, the col or−di spl ay mode i s set to ei ther RGBA mode or col or−i ndex
mode. Once the col or−di spl ay mode i s i ni ti al i zed, i t can’t be changed. As the program executes, a col or
(ei ther a col or i ndex or an RGBA val ue) i s determi ned on a per−vertex basi s for each geometri c
pri mi ti ve. Ei ther a col or you’ve expl i ci tl y speci fi ed for a vertex i s used or, i f l i ghti ng i s enabl ed, the
transformati on matri ces i nteract wi th the surface normal s and other materi al properti es to determi ne
the vertex’s col or. I n other words, a red bal l wi th a bl ue l i ght shi ni ng on i t l ooks di fferent from the same
bal l wi th no l i ght on i t. (See Chapter 6 for detai l s.) After the rel evant l i ghti ng cal cul ati ons are
performed, the chosen shadi ng model i s appl i ed. As expl ai ned i n "Specifying a Color and a Shading
Model," you can choose fl at or smooth shadi ng, each of whi ch has di fferent effects on the eventual col or
of a pi xel .
Next, the pri mi ti ves are rasteri zed, or converted to a two−di mensi onal i mage. Rasteri zi ng i nvol ves
determi ni ng whi ch squares of an i nteger gri d i n wi ndow coordi nates are occupi ed by the pri mi ti ve and
then assi gni ng col or and other val ues to each such square. A gri d square al ong wi th i ts associ ated
val ues of col or, z (depth), and texture coordi nates i s cal l ed a fragment. Pi xel s are el ements of the
framebuffer; a fragment comes from a pri mi ti ve and i s combi ned wi th i ts correspondi ng pi xel to yi el d a
new pi xel . Once a fragment i s constructed, texturi ng, fog, and anti al i asi ng are appl i edi f they’re
enabl edto the fragments. After that, any speci fi ed al pha bl endi ng, di theri ng, and bi twi se l ogi cal
operati ons are carri ed out usi ng the fragment and the pi xel al ready stored i n the framebuffer. Fi nal l y,
the fragment’s col or val ue (ei ther col or i ndex or RGBA) i s wri tten i nto the pi xel and di spl ayed i n the
wi ndow usi ng the wi ndow’s col or−di spl ay mode.
RGBA versus Color−Index Mode
I n ei ther col or−i ndex or RGBA mode, a certai n amount of col or data i s stored at each pi xel . Thi s
amount i s determi ned by the number of bi tpl anes i n the framebuffer. A bi tpl ane contai ns one bi t of
data for each pi xel . I f there are ei ght col or bi tpl anes, there are 8 col or bi ts per pi xel , and hence 2
8
= 256
di fferent val ues or col ors that can be stored at the pi xel .
Bi tpl anes are often di vi ded evenl y i nto storage for R, G, and B components (that i s, a 24−bi tpl ane
system devotes 8 bi ts each to red, green, and bl ue), but thi s i sn’t al ways true. To fi nd out the number of
bi tpl anes avai l abl e on your system for red, green, bl ue, al pha, or col or−i ndex val ues, use glGetI ntegerv()
wi th GL_RED_BI TS, GL_GREEN_BI TS, GL_BLUE_BI TS, GL_ALPHA_BI TS, and GL_I NDEX_BI TS.
Note: Col or i ntensi ti es on most computer screens aren’t percei ved as l i near by the human eye.
Consi der col ors consi sti ng of just a red component, wi th green and bl ue set to zero. As the
i ntensi ty vari es from 0.0 (off) to 1.0 (ful l on), the number of el ectrons stri ki ng the pi xel s
i ncreases, but the questi on i s, does 0.5 l ook l i ke hal fway between 0.0 and 1.0? To test thi s,
wri te a program that draws al ternate pi xel s i n a checkerboard pattern to i ntensi ti es 0.0 and
1.0, and compare i t wi th a regi on drawn sol i dl y i n col or 0.5. OpenGL assumes they’re the same.
I f they’re not, you need to use whatever correcti on mechani sm i s provi ded on your parti cul ar
system. For exampl e, many systems have a tabl e to adjust i ntensi ti es so that 0.5 appears to be
hal fway between 0.0 and 1.0. The mappi ng usual l y used i s an exponenti al one, wi th the
exponent referred to as gamma (hence the term gamma correcti on). Usi ng the same gamma for
the red, green, and bl ue components gi ves pretty good resul ts, but three di fferent gamma
val ues mi ght gi ve sl i ghtl y better resul ts. For more detai l s on thi s topi c, see Fol ey, van Dam, et
al .
RGBA Display Mode
I n RGBA mode, the hardware sets asi de a certai n number of bi tpl anes for each of the R, G, B, and A
components (not necessari l y the same number for each component). See Figure 5−2 . The R, G, and B
val ues are typi cal l y stored as i ntegers rather than fl oati ng−poi nt numbers, and they’re scal ed to the
104
number of avai l abl e bi ts for storage and retri eval . For exampl e, i f a system has 8 bi ts avai l abl e for the
R component, i ntegers between 0 and 255 can be stored; thus, 0, 1, 2, ..., 255 i n the bi tpl anes woul d
correspond to R val ues of 0/255 = 0.0, 1/255, 2/255, ..., 255/255 = 1.0. Regardl ess of the number of
bi tpl anes, 0.0 speci fi es the mi ni mum i ntensi ty, and 1.0 speci fi es the maxi mum i ntensi ty.
Figure 5−2 RGB Val ues from the Bi tpl anes
Note: The al pha val ue (the A i n RGBA) has no di rect effect on the col or di spl ayed on the screen. I t can
be used for many thi ngs, i ncl udi ng bl endi ng and transparency, and i t can have an effect on the
val ues of R, G, and B that are wri tten. See "Blending" for more i nformati on about al pha
val ues.
The number of di sti nct col ors that can be di spl ayed at a si ngl e pi xel depends on the number of bi tpl anes
and the capaci ty of the hardware to i nterpret those bi tpl anes. The number of di sti nct col ors can’t
exceed 2
n
, where n i s the number of bi tpl anes. Thus, a machi ne wi th 24 bi tpl anes for RGB can di spl ay
up to 16.77 mi l l i on di sti nct col ors.
Dithering
Advanced
Some graphi cs hardware uses di theri ng to i ncrease the number of di spl ayabl e col ors at the expense of
spati al resol uti on. Di theri ng i s the techni que of usi ng combi nati ons of some col ors to create the effect of
other col ors. To i l l ustrate how di theri ng works, suppose your system has onl y one bi t each for R, G, and
B, so i t can di spl ay onl y ei ght col ors: bl ack, whi te, red, bl ue, green, yel l ow, cyan, and magenta. To
di spl ay a pi nk regi on, the hardware can fi l l the regi on i n a checkerboard manner, al ternati ng red and
whi te pi xel s. I f your eye i s far enough back from the screen that i t can’t di sti ngui sh i ndi vi dual pi xel s,
the regi on appears pi nkthe average of red and whi te. Redder pi nks can be achi eved by fi l l i ng a hi gher
proporti on of the pi xel s wi th red, whi ter pi nks woul d use more whi te pi xel s, and so on.
Wi th thi s techni que, there are no pi nk pi xel s. The onl y way to achi eve the effect of "pi nkness" i s to
105
cover a regi on consi sti ng of mul ti pl e pi xel syou can’t di ther a si ngl e pi xel . I f you speci fy an RGB val ue
for an unavai l abl e col or and fi l l a pol ygon, the hardware fi l l s the pi xel s i n the i nteri or of the pol ygon
wi th a mi xture of nearby col ors whose average appears to your eye to be the col or you want.
(Remember, though, that i f you’re readi ng pi xel i nformati on out of the framebuffer, you get the actual
red and whi te pi xel val ues, si nce there aren’t any pi nk ones. See Chapter 8 for more i nformati on
about readi ng pi xel val ues.)
Figure 5−3 i l l ustrates some si mpl e di theri ng of bl ack and whi te pi xel s to make shades of gray. From
l eft to ri ght, the 4×4 patterns at the top represent di theri ng patterns for 50 percent, 19 percent, and 69
percent gray. Under each pattern, you can see repeated reduced copi es of each pattern, but these bl ack
and whi te squares are sti l l bi gger than most pi xel s. I f you l ook at them from across the room, you can
see that they bl ur together and appear as three l evel s of gray.
Figure 5−3 Di theri ng Bl ack and Whi te to Create Gray
Wi th about 8 bi ts each of R, G, and B, you can get a fai rl y hi gh−qual i ty i mage wi thout di theri ng. Just
because your machi ne has twenty−four col or bi tpl anes, however, doesn’t mean that di theri ng won’t
occur. For exampl e, i f you are runni ng i n doubl e−buffer mode, the bi tpl anes mi ght be di vi ded i nto two
sets of twel ve, so there are real l y onl y 4 bi ts each per R, G, and B component. Wi thout di theri ng,
4−bi t−per−component col or can gi ve l ess than sati sfactory resul ts i n many si tuati ons.
You enabl e or di sabl e di theri ng by passi ng GL_DI THER to glEnable() or glDisable().
Color−Index Display Mode
Wi th col or−i ndex mode, OpenGL uses a col or map (or lookup table), whi ch i s si mi l ar to usi ng a pal ette
to mi x pai nts to prepare for a pai nt−by−number scene. A pai nter’s pal ette provi des spaces to mi x pai nts
106
together; si mi l arl y, a computer’s col or map provi des i ndi ces where the pri mary red, green, and bl ue
val ues can be mi xed, as shown i n Figure 5−4 .
Figure 5−4 A Col or Map
A pai nter fi l l i ng i n a pai nt−by−number scene chooses a col or from the col or pal ette and fi l l s the
correspondi ng numbered regi ons wi th that col or. A computer stores the col or i ndex i n the bi tpl anes for
each pi xel . Then those bi tpl ane val ues reference the col or map, and the screen i s pai nted wi th the
correspondi ng red, green, and bl ue val ues from the col or map, as shown i n Figure 5−5 .
Figure 5−5 Usi ng a Col or Map to Pai nt a Pi cture
107
I n col or−i ndex mode, the number of si mul taneousl y avai l abl e col ors i s l i mi ted by the si ze of the col or
map and the number of bi tpl anes avai l abl e. The si ze of the col or map i s determi ned by the amount of
hardware dedi cated to i t. Typi cal si zes range from 256 (2
8
) to 4096 (2
12
). The si ze of the col or map i s a
power of 2, i ndexed by the number of bi tpl anes avai l abl e i n col or−i ndex mode. I f there are 2
n
i ndi ces i n
the col or map and m avai l abl e bi tpl anes, the number of usabl e entri es i s the smal l er of 2
n
and 2
m
.
Wi th RGBA mode, each pi xel ’s col or i s i ndependent of other pi xel s. However, i n col or−i ndex mode, each
pi xel wi th the same i ndex stored i n i ts bi tpl anes shares the same col or−map l ocati on. I f the contents of
an entry i n the col or map change, then al l pi xel s of that col or i ndex change thei r col or.
Choosing between RGBA and Color−Index Mode
You shoul d base your deci si on to use RGBA or col or−i ndex mode on what hardware i s avai l abl e and on
what your appl i cati on needs. For most systems, more col ors can be si mul taneousl y represented wi th
RGBA mode than wi th col or−i ndex mode. Al so, for several effects, such as shadi ng, l i ghti ng, texture
mappi ng, and fog, RGBA provi des more fl exi bi l i ty than col or−i ndex mode.
You mi ght prefer to use col or−i ndex mode i n the fol l owi ng cases:
• I f you’re porti ng an exi sti ng appl i cati on that makes si gni fi cant use of col or−i ndex mode, i t mi ght be
easi est to not change to RGBA mode.
• I f you have onl y a smal l number n of bi tpl anes avai l abl e and i f you need fewer than 2
n
di fferent
col ors, you shoul d consi der col or−i ndex mode.
• I f you have a l i mi ted number of bi tpl anes avai l abl e, RGBA mode mi ght produce noti ceabl y coarse
shadi ng. Col or−i ndex mode mi ght work better i f you have l i mi ted shadi ng requi rements (onl y
shades of gray, for exampl e).
• Col or−i ndex mode can be useful for vari ous tri cks, such as col or−map ani mati on and drawi ng i n
l ayers. See Chapter 13 for more i nformati on.
I n general , use RGBA mode: I t works wi th texture mappi ng and works better wi th l i ghti ng, shadi ng,
fog, anti al i asi ng, and bl endi ng.
Specifying a Color and a Shading Model
OpenGL mai ntai ns a current col or (i n RGBA mode) and a current col or i ndex (i n col or−i ndex mode).
Unl ess you’re usi ng a more compl i cated col ori ng model such as l i ghti ng or texture mappi ng, each object
i s drawn usi ng the current col or (or col or i ndex). Look at the fol l owi ng pseudocode sequence:
set_color(RED);
draw_item(A);
draw_item(B);
set_color(GREEN);
set_color(BLUE);
draw_item(C);
I tems A and B are drawn i n red, and i tem C i s drawn i n bl ue. The fourth l i ne, whi ch sets the current
col or to green, has no effect (except to waste a bi t of ti me). Wi th no l i ghti ng or texturi ng, when the
current col or i s set, al l i tems drawn afterward are drawn i n that col or unti l the current col or i s changed
to somethi ng el se.
Specifying a Color in RGBA Mode
I n RGBA mode, use the glColor*() command to sel ect a current col or.
voi d glColor3{b s i f d ub us ui }(TYPEr, TYPEg, TYPEb);
voi d glColor4{b s i f d ub us ui }(TYPEr, TYPEg, TYPEb, TYPEa);
108
voi d glColor3{b s i f d ub us ui }v (const TYPE*v);
voi d glColor4{b s i f d ub us ui }v (const TYPE*v);
Sets the current red, green, bl ue, and al pha val ues. Thi s command can have up to three suffi xes, whi ch
di fferenti ate vari ati ons of the parameters accepted. The fi rst suffi x i s ei ther 3 or 4, to i ndi cate whether
you suppl y an al pha val ue i n addi ti on to the red, green, and bl ue val ues. I f you don’t suppl y an al pha
val ue, i t’s automati cal l y set to 1.0. The second suffi x i ndi cates the data type for parameters: byte, short,
i nteger, fl oat, doubl e, unsi gned byte, unsi gned short, or unsi gned i nteger. The thi rd suffi x i s an opti onal
v, whi ch i ndi cates that the argument i s a poi nter to an array of val ues of the gi ven data type.
For the versi ons of glColor*() that accept fl oati ng−poi nt data types, the val ues shoul d typi cal l y range
between 0.0 and 1.0, the mi ni mum and maxi mum val ues that can be stored i n the framebuffer. (Val ues
ousi de the range [0,1] are cl amped to the range [0,1] when used di rectl y, but aren’t cl amped when used
to modi fy l i ghti ng materi al parameters.) Unsi gned−i nteger col or components, when speci fi ed, are
l i nearl y mapped to fl oati ng−poi nt val ues such that the l argest representabl e val ue maps to 1.0 (ful l
i ntensi ty), and zero maps to 0.0 (zero i ntensi ty). Si gned−i nteger col or components, when speci fi ed, are
l i nearl y mapped to fl oati ng−poi nt val ues such that the most posi ti ve representabl e val ue maps to 1.0,
and the most negati ve representabl e val ue maps to −1.0 (see Table 5−1 ). Fl oati ng−poi nt val ues are
mapped di rectl y. Nei ther fl oati ng−poi nt nor si gned−i nteger val ues are cl amped to the range [0,1] before
updati ng the current col or. However, col or components are cl amped to thi s range before they are
i nterpol ated or wri tten i nto a col or buffer.
SuffixData Type Minimum Value Min Value
Maps to
Maximum Value
b 1−byte integer −128 −1.0 127
s 2−byte integer −32,768 −1.0 32,767
i 4−byte integer −2,147,483,648 −1.0 2,147,483,647
ub unsigned 1−byte integer 0 0.0 255
us unsigned 2−byte integer 0 0.0 65,535
ui unsigned 4−byte integer 0 0.0 4,294,967,295
Table 5−1 Converti ng Col or Val ues to Fl oati ng−Poi nt Numbers
Specifying a Color in Color−Index Mode
I n col or−i ndex mode, use the glI ndex*() command to sel ect a si ngl e−val ued col or i ndex as the current
col or i ndex.
voi d glI ndex{si fd}(TYPE c);
voi d glI ndex{si fd}v(const TYPE *c);
Sets the current col or i ndex. The fi rst suffi x for thi s command i ndi cates the data type for parameters:
short, i nteger, fl oat, or doubl e. The second, opti onal suffi x i s v, whi ch i ndi cates that the argument i s an
array of val ues of the gi ven data type (the array contai ns onl y one val ue).
Advanced
The current i ndex i s stored as a fl oati ng−poi nt val ue. I nteger val ues are converted di rectl y to
fl oati ng−poi nt val ues, wi th no speci al mappi ng. I ndex val ues outsi de the representabl e range of the
col or−i ndex buffer aren’t cl amped. However, before an i ndex i s di thered (i f enabl ed) and wri tten to the
framebuffer, i t’s converted to fi xed−poi nt format. Any bi ts i n the i nteger porti on of the resul ti ng
fi xed−poi nt val ue that don’t correspond to bi ts i n the framebuffer are masked out.
Specifying a Shading Model
A l i ne or a fi l l ed pol ygon pri mi ti ve can be drawn wi th a si ngl e col or (fl at shadi ng) or wi th many
di fferent col ors (smooth shadi ng, al so cal l ed Gouraud shadi ng). You speci fy the desi red shadi ng
techni que wi th glShadeModel().
109
voi d glShadeModel (GLenum mode);
Sets the shadi ng model . The mode parameter can be ei ther GL_SMOOTH (the defaul t) or GL_FLAT.
Wi th fl at shadi ng, the col or of one vertex of a pri mi ti ve i s dupl i cated across al l the pri mi ti ve’s verti ces.
Wi th smooth shadi ng, the col or at each vertex i s treated i ndi vi dual l y. For a l i ne pri mi ti ve, the col ors
al ong the l i ne segment are i nterpol ated between the vertex col ors. For a pol ygon pri mi ti ve, the col ors
for the i nteri or of the pol ygon are i nterpol ated between the vertex col ors. Example 5−1 draws a
smooth−shaded tri angl e, as shown i n Figure J −11.
Example 5−1 Drawi ng a Smooth−Shaded Tri angl e: smooth.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
void myinit (void)
{
glShadeModel (GL_SMOOTH); /* GL_SMOOTH is the default */
}
void triangle(void)
{
glBegin (GL_TRIANGLES);
glColor3f (1.0, 0.0, 0.0);
glVertex2f (5.0, 5.0);
glColor3f (0.0, 1.0, 0.0);
glVertex2f (25.0, 5.0);
glColor3f (0.0, 0.0, 1.0);
glVertex2f (5.0, 25.0);
glEnd ();
}
void display(void)
{
glClear (GL_COLOR_BUFFER_BIT);
triangle ();
glFlush ();
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
gluOrtho2D (0.0, 30.0, 0.0,
30.0 * (GLfloat) h/(GLfloat) w);
else
gluOrtho2D (0.0, 30.0 * (GLfloat) w/(GLfloat) h, 0.0,
30.0);
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char** argv)
110
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
auxInitPosition (0, 0, 500, 500);
auxInitWindow (argv[0]);
myinit();
auxReshapeFunc (myReshape);
auxMainLoop(display);
}
Wi th smooth shadi ng, nei ghbori ng pi xel s have sl i ghtl y di fferent col or val ues. I n RGBA mode, adjacent
pi xel s wi th sl i ghtl y di fferent val ues l ook si mi l ar, so the col or changes across a pol ygon appear gradual .
I n col or−i ndex mode, adjacent pi xel s may reference di fferent l ocati ons i n the col or−i ndex tabl e, whi ch
may not have si mi l ar col ors at al l . Adjacent col or−i ndex entri es may contai n wi l dl y di fferent col ors, so a
smooth−shaded pol ygon i n col or−i ndex mode can l ook psychedel i c.
To avoi d thi s probl em, you have to create a col or ramp of smoothl y changi ng col ors among a conti guous
set of i ndi ces i n the col or map. Remember that l oadi ng col ors i nto a col or map i s performed through
your wi ndow system rather than OpenGL. For the moment, however, assume you have an
auxSetOneColor() routi ne that l oads a si ngl e i ndex i n the col or map wi th speci fi ed red, green, and bl ue
val ues. The fi rst argument for thi s routi ne i s the i ndex, and the others are the red, green, and bl ue
val ues. To l oad thi rty−two conti guous col or i ndi ces (from col or i ndex 16 to 47) wi th sl i ghtl y di fferi ng
shades of yel l ow, you mi ght cal l
for(i=0; i<32; i++){
auxSetOneColor(16+i, 1.0*(i/32.0), 1.0*(i/32.0), 0.0);
}
Now, i f you render smooth−shaded pol ygons that use onl y the col ors from i ndex 16 to 47, those pol ygons
have gradual l y di fferi ng shades of yel l ow.
Wi th fl at shadi ng, the col or of a si ngl e vertex defi nes the col or of an enti re pri mi ti ve. For a l i ne
segment, the col or of the l i ne i s the current col or when the second (endi ng) vertex i s speci fi ed. For a
pol ygon, the col or used i s the one that’s i n effect when a parti cul ar vertex i s speci fi ed, as shown i n
Table 5−2 . The tabl e counts verti ces and pol ygons starti ng from 1. OpenGL fol l ows these rul es
consi stentl y, but the best way to avoi d uncertai nty about how a fl at−shaded pri mi ti ve wi l l be drawn i s
to speci fy onl y one col or for the pri mi ti ve.
Type of Polygon Vertex Used to Select the Color for the ith Polygon
single polygon 1
triangle strip i+2
triangle fan i+2
independent triangle 3i
quad strip 2i+2
independent quad 4i
Table 5−2 How OpenGL Sel ects a Col or for the i th Fl at−Shaded Pol ygon
Chapter 6
Lighting
Chapter Objectives
After readi ng thi s chapter, you’l l be abl e to do the fol l owi ng:
• Understand how real −worl d l i ghti ng condi ti ons are approxi mated by OpenGL
• Render i l l umi nated objects by defi ni ng the desi red l i ght sources and l i ghti ng model
• Defi ne the materi al properti es of the objects bei ng i l l umi nated
111
• Mani pul ate the matri x stack to control the posi ti on of l i ght sources
As you saw i n Chapter 5 , OpenGL computes the col or of each pi xel i n a fi nal , di spl ayed scene that’s
hel d i n the framebuffer. Part of thi s computati on depends on what l i ghti ng i s used i n the scene and on
how objects i n the scene refl ect or absorb that l i ght. As an exampl e of thi s, recal l that the ocean has a
di fferent col or on a bri ght, sunny day than i t does on a gray, cl oudy day. The presence of sunl i ght or
cl ouds determi nes whether you see the ocean as bri ght turquoi se or murky gray−green. I n fact, most
objects don’t even l ook three−di mensi onal unti l they’re l i t. Figure 6−1 shows two versi ons of the exact
same scene (a si ngl e sphere), one wi th l i ghti ng and one wi thout.
Figure 6−1 A Li t and an Unl i t Sphere
As you can see, an unl i t sphere l ooks no di fferent from a two−di mensi onal di sk. Thi s demonstrates how
cri ti cal the i nteracti on between objects and l i ght i s i n creati ng a three−di mensi onal scene.
Wi th OpenGL, you can mani pul ate the l i ghti ng and objects i n a scene to create many di fferent ki nds of
effects. Thi s chapter expl ai ns how to control the l i ghti ng i n a scene. I t di scusses OpenGL’s conceptual
model of l i ghti ng, and i t descri bes i n detai l how to set the numerous i l l umi nati on parameters to achi eve
certai n effects. Toward the end of the chapter, the mathemati cal computati ons that determi ne how
l i ghti ng affects col or are presented.
Thi s chapter contai ns the fol l owi ng major secti ons:
• "Real−World and OpenGL Lighting"expl ai ns i n general terms how l i ght behaves i n the worl d
and how OpenGL model s thi s behavi or.
• "A Simple Example: Rendering a Lit Sphere"i ntroduces OpenGL’s l i ghti ng faci l i ty by
presenti ng a short program that renders a l i t sphere.
• "Creating Light Sources"expl ai ns how to defi ne and posi ti on l i ght sources.
• "Selecting a Lighting Model"di scusses the el ements of a l i ghti ng model and how to speci fy them.
• "Defining Material Properties"expl ai ns how to descri be the properti es of objects so that they
i nteract wi th l i ght i n a desi red way.
• "The Mathematics of Lighting"presents the mathemati cal cal cul ati ons used by OpenGL to
determi ne the effect of l i ghts i n a scene.
• "Lighting in Color−Index Mode"di scusses the di fferences between usi ng RGBA mode and
col or−i ndex mode for l i ghti ng.
112
Real−World and OpenGL Lighting
When you l ook at a physi cal surface, your eye’s percepti on of the col or depends on the di stri buti on of
photon energi es that arri ve and tri gger your cone cel l s, as descri bed i n "Color Perception." Those
photons come from a l i ght source or combi nati on of sources, some of whi ch are absorbed and some of
whi ch are refl ected by the surface. I n addi ti on, di fferent surfaces may have very di fferent properti es
some are shi ny, and preferenti al l y refl ect l i ght i n certai n di recti ons, whi l e others scatter i ncomi ng l i ght
equal l y i n al l di recti ons. Most surfaces are somewhere i n between.
OpenGL approxi mates l i ght and l i ghti ng as i f l i ght can be broken i nto red, green, and bl ue components.
Thus, the col or of l i ght sources i s characteri zed by the amount of red, green, and bl ue l i ght they emi t,
and the materi al of surfaces i s characteri zed by the percentage of the i ncomi ng red, green, and bl ue
components that are refl ected i n vari ous di recti ons. The OpenGL l i ghti ng equati ons are just an
approxi mati on, but one that works fai rl y wel l and can be computed rel ati vel y qui ckl y. I f you desi re a
more accurate (or just di fferent) l i ghti ng model , you have to do your own cal cul ati ons i n software. Such
software can be enormousl y compl ex, as a few hours of readi ng any opti cs textbook shoul d convi nce
you.
I n the OpenGL l i ghti ng model , the l i ght i n a scene comes from several l i ght sources that can
i ndi vi dual l y be turned on and off. Some l i ght comes from a parti cul ar di recti on or posi ti on, and some
l i ght i s general l y scattered about the scene. For exampl e, when you turn on a l i ght bul b i n a room, most
of the l i ght comes from the bul b, but some l i ght comes after bounci ng off one, two, three, or more wal l s.
Thi s bounced l i ght (cal l ed ambient) i s assumed to be so scattered that there i s no way to tel l i ts ori gi nal
di recti on, but i t di sappears i f a parti cul ar l i ght source i s turned off.
Fi nal l y, there mi ght be a general ambi ent l i ght i n the scene that comes from no parti cul ar source, as i f
i t had been scattered so many ti mes that i ts ori gi nal source i s i mpossi bl e to determi ne.
I n the OpenGL model , the l i ght sources have an effect onl y when there are surfaces that absorb and
refl ect l i ght. Each surface i s assumed to be composed of a materi al wi th vari ous properti es. A materi al
mi ght emi t i ts own l i ght (l i ke headl i ghts on an automobi l e), i t mi ght scatter some i ncomi ng l i ght i n al l
di recti ons, and i t mi ght refl ect some porti on of the i ncomi ng l i ght i n a preferenti al di recti on l i ke a
mi rror or shi ny surface.
The OpenGL l i ghti ng model consi ders the l i ghti ng to be di vi ded i nto four i ndependent components:
emi tted, ambi ent, di ffuse, and specul ar. Al l four components are computed i ndependentl y, and then
added together.
Emitted, Ambient, Diffuse, and Specular Light
Emitted l i ght i s the si mpl esti t ori gi nates from an object and i s unaffected by any l i ght sources.
The ambient component i s the l i ght from that source that’s been scattered so much by the envi ronment
that i ts di recti on i s i mpossi bl e to determi nei t seems to come from al l di recti ons. Backl i ghti ng i n a
room has a l arge ambi ent component, si nce most of the l i ght that reaches your eye has bounced off
many surfaces fi rst. A spotl i ght outdoors has a ti ny ambi ent component; most of the l i ght travel s i n the
same di recti on, and si nce you’re outdoors, very l i ttl e of the l i ght reaches your eye after bounci ng off
other objects. When ambi ent l i ght stri kes a surface, i t’s scattered equal l y i n al l di recti ons.
Diffusel i ght comes from one di recti on, so i t’s bri ghter i f i t comes squarel y down on a surface than i f i t
barel y gl ances off the surface. Once i t hi ts a surface, however, i t’s scattered equal l y i n al l di recti ons, so
i t appears equal l y bri ght, no matter where the eye i s l ocated. Any l i ght comi ng from a parti cul ar
posi ti on or di recti on probabl y has a di ffuse component.
Fi nal l y, specular l i ght comes from a parti cul ar di recti on, and i t tends to bounce off the surface i n a
preferred di recti on. A wel l −col l i mated l aser beam bounci ng off a hi gh−qual i ty mi rror produces al most
100 percent specul ar refl ecti on. Shi ny metal or pl asti c has a hi gh specul ar component, and chal k or
113
carpet has al most none. You can thi nk of specul ari ty as shi ni ness.
Al though a l i ght source del i vers a si ngl e di stri buti on of frequenci es, the ambi ent, di ffuse, and specul ar
components mi ght be di fferent. For exampl e, i f you have a whi te l i ght i n a room wi th red wal l s, the
scattered l i ght tends to be red, al though the l i ght di rectl y stri ki ng objects i s whi te. OpenGL al l ows you
to set the red, green, and bl ue val ues for each component of l i ght i ndependentl y.
Material Colors
The OpenGL l i ghti ng model makes the approxi mati on that a materi al ’s col or depends on the
percentages of the i ncomi ng red, green, and bl ue l i ght i t refl ects. For exampl e, a perfectl y red bal l
refl ects al l the i ncomi ng red l i ght and absorbs al l the green and bl ue l i ght that stri kes i t. I f you vi ew
such a bal l i n whi te l i ght (composed of equal amounts of red, green, and bl ue l i ght), al l the red i s
refl ected, and you see a red bal l . I f the bal l i s vi ewed i n pure red l i ght, i t al so appears to be red. I f,
however, the red bal l i s vi ewed i n pure green l i ght, i t appears bl ack (al l the green i s absorbed, and
there’s no i ncomi ng red, so no l i ght i s refl ected).
Li ke l i ghts, materi al s have di fferent ambi ent, di ffuse, and specul ar col ors, whi ch determi ne the
ambi ent, di ffuse, and specul ar refl ectances of the materi al . A materi al ’s ambi ent refl ectance i s
combi ned wi th the ambi ent component of each i ncomi ng l i ght source, the di ffuse refl ectance wi th the
l i ght’s di ffuse component, and si mi l arl y for the specul ar refl ectance and component. Ambi ent and
di ffuse refl ectances defi ne the col or of the materi al and are typi cal l y si mi l ar i f not i denti cal . Specul ar
refl ectance i s usual l y whi te or gray, so that specul ar hi ghl i ghts end up bei ng the col or of the l i ght
source’s specul ar i ntensi ty. I f you thi nk of a whi te l i ght shi ni ng on a shi ny red pl asti c sphere, most of
the sphere appears red, but the shi ny hi ghl i ght i s whi te.
RGB Values for Lights and Materials
The col or components speci fi ed for l i ghts mean somethi ng di fferent than for materi al s. For a l i ght, the
numbers correspond to a percentage of ful l i ntensi ty for each col or. I f the R, G, and B val ues for a l i ght’s
col or are al l 1.0, the l i ght i s the bri ghtest possi bl e whi te. I f the val ues are 0.5, the col or i s sti l l whi te, but
onl y at hal f i ntensi ty, so i t appears gray. I f R=G=1 and B=0 (ful l red and green wi th no bl ue), the l i ght
appears yel l ow.
For materi al s, the numbers correspond to the refl ected proporti ons of those col ors. So i f R=1, G=0.5,
and B=0 for a materi al , that materi al refl ects al l the i ncomi ng red l i ght, hal f the i ncomi ng green, and
none of the i ncomi ng bl ue l i ght. I n other words, i f an OpenGL l i ght has components (LR, LG, LB), and a
materi al has correspondi ng components (MR, MG, MB), then, i gnori ng al l other refl ecti vi ty effects, the
l i ght that arri ves at the eye i s gi ven by (LR*MR, LG*MG, LB*MB).
Si mi l arl y, i f you have two l i ghts, whi ch send (R1, G1, B1) and (R2, G2, B2) to the eye, OpenGL adds the
components, gi vi ng (R1+R2, G1+G2, B1+B2). I f any of the sums are greater than 1 (correspondi ng to a
col or bri ghter than the equi pment can di spl ay), the component i s cl amped to 1.
A Simple Example: Rendering a Lit Sphere
These are the steps requi red to add l i ghti ng to your scene:
1. Defi ne normal vectors for each vertex of al l the objects. These normal s determi ne the ori entati on of
the object rel ati ve to the l i ght sources.
2. Create, sel ect, and posi ti on one or more l i ght sources.
3. Create and sel ect a lighting model, whi ch defi nes the l evel of gl obal ambi ent l i ght and the effecti ve
l ocati on of the vi ewpoi nt (for the purposes of l i ghti ng cal cul ati ons).
4. Defi ne materi al properti es for the objects i n the scene.
114
Example 6−1accompl i shes these tasks. I t di spl ays a sphere i l l umi nated by a si ngl e l i ght source, as
shown earl i er i n Figure 6−1 .
Example 6−1 Drawi ng a Li t Sphere:
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
void myinit(void)
{
GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat mat_shininess[] = { 50.0 };
GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
auxSolidSphere(1.0);
glFlush();
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho (−1.5, 1.5, −1.5*(GLfloat)h/(GLfloat)w,
1.5*(GLfloat)h/(GLfloat)w, −10.0, 10.0);
else
glOrtho (−1.5*(GLfloat)w/(GLfloat)h,
1.5*(GLfloat)w/(GLfloat)h, −1.5, 1.5, −10.0, 10.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA | AUX_DEPTH);
auxInitPosition (0, 0, 500, 500);
auxInitWindow (argv[0]);
myinit();
auxReshapeFunc (myReshape);
115
auxMainLoop(display);
}
The l i ghti ng−rel ated cal l s are i n the myinit() command; they’re di scussed bri efl y i n the fol l owi ng
paragraphs and i n more detai l l ater i n the chapter. One thi ng to note about Example 6−1 i s that i t
uses RGBA col or mode, not col or−i ndex mode. OpenGL’s l i ghti ng cal cul ati on i s di fferent for the two
modes, and i n fact the l i ghti ng capabi l i ti es are more l i mi ted i n col or−i ndex mode. Thus, RGBA i s the
preferred mode when doi ng l i ghti ng, and al l the exampl es i n thi s chapter use i t. See "Lighting in
Color−Index Mode" for more i nformati on about l i ghti ng i n col or−i ndex mode.
Define Normal Vectors for Each Vertex of All the Objects
An object’s normal s determi ne i ts ori entati on rel ati ve to the l i ght sources. For each vertex, OpenGL
uses the assi gned normal to determi ne how much l i ght that parti cul ar vertex recei ves from each l i ght
source. I n thi s exampl e, the normal s for the sphere are defi ned as part of the auxSolidSphere() routi ne.
See "Normal Vectors" for more detai l s on how to defi ne normal s.
Create, Position, and Enable One or More Light Sources
Example 6−1uses onl y one, whi te l i ght source; i ts l ocati on i s speci fi ed by the glLightfv() cal l . Thi s
exampl e uses the defaul t col or for l i ght zero (GL_LI GHT0), whi ch i s whi te; i f you had wanted a
di fferentl y col ored l i ght, you’d use glLight*() to i ndi cate thi s. You can i ncl ude at l east ei ght di fferent
l i ght sources i n your scene of vari ous col ors; the defaul t col or of these other l i ghts i s bl ack. (The
parti cul ar i mpl ementati on of OpenGL you’re usi ng mi ght al l ow more than ei ght.) You can al so l ocate
the l i ghts wherever you desi reyou can posi ti on them near the scene, as a desk l amp woul d be, or an
i nfi ni te di stance away, l i ke the sun. I n addi ti on, you can control whether a l i ght produces a narrow,
focused beam or a wi der beam. Remember that each l i ght source adds si gni fi cantl y to the cal cul ati ons
needed to render the scene, so performance i s affected by the number of l i ghts i n the scene. See
"Creating Light Sources" for more i nformati on about how to create l i ghts wi th the desi red
characteri sti cs.
After you’ve defi ned the characteri sti cs of the l i ghts you want, you have to turn them on wi th the
glEnable() command. You al so need to cal l thi s command wi th GL_LI GHTI NG as a parameter to
prepare OpenGL to perform l i ghti ng cal cul ati ons. See "Enabling Lighting" for more i nformati on
about how to do thi s.
Select a Lighting Model
As you mi ght expect, the glLightModel*() command descri bes the parameters of a l i ghti ng model . I n
Example 6−1, the onl y el ement of the l i ghti ng model that’s defi ned expl i ci tl y i s the gl obal ambi ent
l i ght. The l i ghti ng model al so defi nes whether the vi ewer of the scene shoul d be consi dered to be an
i nfi ni te di stance away or l ocal to the scene, and whether l i ghti ng cal cul ati ons shoul d be performed
di fferentl y for the front and back surfaces of objects i n the scene. Example 6−1 uses the defaul t
setti ngs for these two aspects of the model an i nfi ni te vi ewer and one−si ded l i ghti ng. Usi ng a l ocal
vi ewer adds si gni fi cantl y to the compl exi ty of the cal cul ati ons that must be performed because OpenGL
must cal cul ate the angl e between the vi ewpoi nt and each object. Wi th an i nfi ni te vi ewer, however, the
angl e i s i gnored, and the resul ts are sl i ghtl y l ess real i sti c. Further, si nce i n thi s exampl e, the back
surface of the sphere i s never seen (i t’s the i nsi de of the sphere), one−si ded l i ghti ng i s suffi ci ent. The
secti on "Selecting a Lighting Model" descri bes the el ements of an OpenGL l i ghti ng model i n more
detai l .
Define Material Properties for the Objects in the Scene
An object’s materi al properti es determi ne how i t refl ects l i ght and therefore what materi al i t seems to
be made of. Because the i nteracti on between an object’s materi al surface and i nci dent l i ght i s compl ex,
speci fyi ng materi al properti es so that an object has a certai n desi red appearance i s an art. You can
116
speci fy a materi al ’s ambi ent, di ffuse, and specul ar col ors and how shi ny i t i s. I n thi s exampl e, onl y
these l ast two materi al properti esthe specul ar materi al col or and shi ni nessare expl i ci tl y speci fi ed
(wi th the glMaterialfv() cal l s). "Defining Material Properties" descri bes and gi ves exampl es of al l
the materi al −property parameters.
Some Important Notes
As you wri te your own l i ghti ng program, remember that you can use the defaul t val ues for some
l i ghti ng parameters; others need to be changed. Al so, don’t forget to enabl e whatever l i ghts you defi ne
and to enabl e l i ghti ng cal cul ati ons. Fi nal l y, remember that you mi ght be abl e to use di spl ay l i sts to
maxi mi ze effi ci ency as you change l i ghti ng condi ti ons; see "Display−List Design Philosophy."
Creating Light Sources
Li ght sources have a number of properti es, such as col or, posi ti on, and di recti on. The fol l owi ng secti ons
expl ai n how to control these properti es and what the resul ti ng l i ght l ooks l i ke. The command used to
speci fy al l properti es of l i ghts i s glLight*(); i t takes three arguments: to i denti fy the l i ght whose
property i s bei ng speci fi ed, the property, and the desi red val ue for that property.
voi d glLight{i f}[v](GLenum light, GLenum pname, TYPEparam);
Creates the l i ght speci fi ed by light, whi ch can be GL_LI GHT0, GL_LI GHT1, ... , or GL_LI GHT7. The
characteri sti c of the l i ght bei ng set i s defi ned by pname, whi ch speci fi es a named parameter (see Table
6−1). The param argument i ndi cates the val ues to whi ch the pnamecharacteri sti c i s set; i t’s a poi nter
to a group of val ues i f the vector versi on i s used, or the val ue i tsel f i f the nonvector versi on i s used. The
nonvector versi on can be used to set onl y si ngl e−val ued l i ght characteri sti cs.
Parameter Name Default Value Meaning
GL_AMBIENT (0.0, 0.0, 0.0, 1.0) ambient RGBA intensity of
light
GL_DIFFUSE (1.0, 1.0, 1.0, 1.0) diffuse RGBA intensity of light
GL_SPECULAR (1.0, 1.0, 1.0, 1.0) specular RGBA intensity of
light
GL_POSITION (0.0, 0.0, 1.0, 0.0) (x, y, z, w) position of light
GL_SPOT_DIRECTION (0.0, 0.0, −1.0) (x, y, z) direction of spotlight
GL_SPOT_EXPONENT 0.0 spotlight exponent
GL_SPOT_CUTOFF 180.0 spotlight cutoff angle
GL_CONSTANT_ATTENUATION 1.0 constant attenuation factor
GL_LINEAR_ATTENUATION 0.0 linear attenuation factor
GL_QUADRATIC_ATTENUATION 0.0 quadratic attenuation factor
Table 6−1 Defaul t Val ues for pname Parameter of gl Li ght*()
Note: The defaul t val ues l i sted for GL_DI FFUSE and GL_SPECULAR i n Table 6−1 appl y onl y to
GL_LI GHT0. For other l i ghts, the defaul t val ue i s (0.0, 0.0, 0.0, 1.0) for both GL_DI FFUSE and
GL_SPECULAR.
Here’s an exampl e of usi ng glLight*():
GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 1.0 };
GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
117
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
As you can see, arrays are defi ned for the parameter val ues, and glLightfv() i s cal l ed repeatedl y to set
the vari ous parameters. I n thi s exampl e, the fi rst three cal l s to glLightfv() are superfl uous, si nce
they’re bei ng used to speci fy the defaul t val ues for the GL_AMBI ENT, GL_DI FFUSE, and
GL_SPECULAR parameters.
Note: Remember to turn on each l i ght wi th glEnable(); see "Enabling Lighting" for more
i nformati on about how to do thi s.
Al l the parameters for glLight*() and thei r possi bl e val ues are expl ai ned i n the fol l owi ng secti ons.
These parameters i nteract wi th those that defi ne the overal l l i ghti ng model for a parti cul ar scene and
an object’s materi al properti es. See "Selecting a Lighting Model" and "Defining Material
Properties" for more i nformati on about these two topi cs. "The Mathematics of Lighting" expl ai ns
how al l these parameters i nteract mathemati cal l y.
Color
OpenGL al l ows you to associ ate three di fferent col or−rel ated parametersGL_AMBI ENT,
GL_DI FFUSE, and GL_SPECULARwi th any parti cul ar l i ght. The GL_AMBI ENT parameter refers
to the RGBA i ntensi ty of the ambi ent l i ght that a parti cul ar l i ght source adds to the scene. As you can
see i n Table 6−1 , by defaul t there i s no ambi ent l i ght si nce GL_AMBI ENT i s (0.0, 0.0, 0.0, 1.0). Thi s
val ue was used i n Example 6−1. I f thi s program had speci fi ed bl ue ambi ent l i ght
GLfloat light_ambient[] = { 0.0, 0.0, 1.0, 1.0};
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
the resul t woul d have been as shown i n the l eft part of Figure J −14.
The GL_DI FFUSE parameter probabl y most cl osel y correl ates wi th what you natural l y thi nk of as "the
col or of a l i ght." I t defi nes the RGBA col or of the di ffuse l i ght that a parti cul ar l i ght source adds to a
scene. By defaul t, GL_DI FFUSE i s (1.0, 1.0, 1.0, 1.0) for GL_LI GHT0, whi ch produces a bri ght, whi te
l i ght as shown i n Figure J −14. The defaul t val ue for any other l i ght (GL_LI GHT1, ... , GL_LI GHT7) i s
(0.0, 0.0, 0.0, 0.0).
The GL_SPECULAR parameter affects the col or of the specul ar hi ghl i ght on an object. Typi cal l y, a
real −worl d object such as a gl ass bottl e has a specul ar hi ghl i ght that’s the col or of the l i ght shi ni ng on i t
(whi ch i s often whi te). Therefore, i f you want to create a real i sti c effect, set the GL_SPECULAR
parameter to the same val ue as the GL_DI FFUSE parameter. By defaul t, GL_SPECULAR i s (1.0, 1.0,
1.0, 1.0) for GL_LI GHT0 and (0.0, 0.0, 0.0, 0.0) for any other l i ght.
Position and Attenuation
As previ ousl y menti oned, you can choose whether to have a l i ght source that’s treated as though i t’s
l ocated i nfi ni tel y far away from the scene or one that’s nearer to the scene. The fi rst type i s referred to
as an directional l i ght source; the effect of an i nfi ni te l ocati on i s that the rays of l i ght can be consi dered
paral l el by the ti me they reach an object. An exampl e of a real −worl d di recti onal l i ght source i s the sun.
The second type i s cal l ed a positional l i ght source, si nce i ts exact posi ti on wi thi n the scene determi nes
the effect i t has on a scene and, speci fi cal l y, the di recti on from whi ch the l i ght rays come. A desk l amp
i s an exampl e of a posi ti onal l i ght source. You can see the di fference between di recti onal and posi ti onal
l i ghts i n Figure J −16.
The l i ght used i n Example 6−1 i s a di recti onal one:
GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
118
As shown, you suppl y a vector of four val ues (x, y, z, w) for the GL_POSI TI ON parameter. I f the l ast
val ue, w, i s zero, the correspondi ng l i ght source i s a di recti onal one, and the (x, y, z) val ues descri be i ts
di recti on. Thi s di recti on i s transformed by the model vi ew matri x just as i t woul d be i f i t descri bed a
normal vector. By defaul t, GL_POSI TI ON i s (0, 0, 1, 0), whi ch defi nes a di recti onal l i ght that poi nts
al ong the negati ve z−axi s. (Note that nothi ng prevents you from creati ng a di recti onal l i ght wi th the
di recti on of (0, 0, 0), but such a l i ght won’t hel p you much.)
I f the w val ue i s nonzero, the l i ght i s posi ti onal , and the (x, y, z) val ues speci fy the l ocati on of the l i ght
i n homogeneous object coordi nates (see Appendix G ). Thi s l ocati on i s transformed by the model vi ew
matri x and stored i n eye coordi nates. See "Controlling a Light’s Position and Direction" for more
i nformati on about how to control the transformati on of the l i ght’s l ocati on. Al so, by defaul t, a posi ti onal
l i ght radi ates i n al l di recti ons, but you can restri ct i t to produci ng a cone of i l l umi nati on by defi ni ng the
l i ght as a spotl i ght. The next secti on, "Spotlights," expl ai ns how to defi ne a l i ght as a spotl i ght.
Note: Remember that the col ors across the face of a smooth−shaded pol ygon are determi ned by the
col ors cal cul ated for the verti ces. Because of thi s, you probabl y want to avoi d usi ng l arge
pol ygons wi th l ocal l i ghtsi f you l ocate the l i ght near the mi ddl e of the pol ygon, the verti ces
mi ght be too far away to recei ve much l i ght, so the whol e pol ygon wi l l l ook darker than you
i ntended. To avoi d thi s probl em, break up the l arge pol ygon i nto smal l er ones.
For real −worl d l i ghts, the i ntensi ty of l i ght decreases as di stance from the l i ght i ncreases. Si nce a
di recti onal l i ght i s i nfi ni tel y far away, i t doesn’t make sense to attenuate i ts i ntensi ty over di stance, so
attenuati on i s di sabl ed for a di recti onal l i ght. However, you mi ght want to attenuate the l i ght from a
posi ti onal l i ght. OpenGL attenuates a l i ght source by mul ti pl yi ng the contri buti on of that source by an
attenuati on factor:
where
d = di stance between the l i ght’s posi ti on and the vertex
k
c
= GL_CONSTANT_ATTENUATI ON
k
l
= GL_LI NEAR_ATTENUATI ON
k
q
= GL_QUADRATI C_ATTENUATI ON
By defaul t, k
c
i s 1.0 and both k
l
and k
q
are zero, but you can gi ve these parameters di fferent val ues:
glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 2.0);
glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 1.0);
glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.5);
Note that the ambi ent, di ffuse, and specul ar contri buti ons are al l attenuated. Onl y the emi ssi on and
gl obal ambi ent val ues aren’t attenuated.
Spotlights
119
As previ ousl y menti oned, you can have a posi ti onal l i ght source act as a spotl i ghtthat i s, by
restri cti ng the shape of the l i ght i t emi ts to a cone. To create a spotl i ght, you need to determi ne the
spread of the cone of l i ght you desi re. (Remember that si nce spotl i ghts are posi ti onal l i ghts, you al so
have to l ocate them where you want them. Agai n, note that nothi ng prevents you from creati ng a
di recti onal spotl i ght, but i t probabl y won’t gi ve you the resul t you want.) To speci fy the angl e between
the axi s of the cone and a ray al ong the edge of the cone, use the GL_SPOT_CUTOFF parameter. The
angl e of the cone at the apex i s then twi ce thi s val ue, as shown i n Figure 6−2 .
Figure 6−2 The GL_SPOT_CUTOFF Parameter
Note that no l i ght i s emi tted beyond the edges of the cone. By defaul t, the spotl i ght feature i s di sabl ed
because the GL_SPOT_CUTOFF parameter i s 180.0. Thi s val ue means that l i ght i s emi tted i n al l
di recti ons (the angl e at the cone’s apex i s 360 degrees, so i t i sn’t a cone at al l ). The val ue for
GL_SPOT_CUTOFF i s restri cted to bei ng wi thi n the range [0.0,90.0] (unl ess i t has the speci al val ue
180.0). The fol l owi ng l i ne sets the cutoff parameter to 45 degrees:
glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 45.0);
You al so need to speci fy a spotl i ght’s di recti on, whi ch determi nes the axi s of the cone of l i ght:
GLfloat spot_direction[] = { −1.0, −1.0, 0.0 };
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, spot_direction);
The di recti on i s speci fi ed i n homogeneous object coordi nates. By defaul t, the di recti on i s (0.0, 0.0, −1.0),
so i f you don’t expl i ci tl y set the val ue of GL_SPOT_DI RECTI ON, the l i ght poi nts down the negati ve z
−axi s. Al so, keep i n mi nd that a spotl i ght’s di recti on i s transformed by the model vi ew matri x just as
though i t were a normal vector, and the resul t i s stored i n eye coordi nates. (See "Controlling a
Light’s Position and Direction" for more i nformati on about such transformati ons.)
I n addi ti on to the spotl i ght’s cutoff angl e and di recti on, you can control the i ntensi ty di stri buti on of the
l i ght wi thi n the cone, i n two ways. Fi rst, you can set the attenuati on factor descri bed earl i er, whi ch i s
mul ti pl i ed by the l i ght’s i ntensi ty. You can al so set the GL_SPOT_EXPONENT parameter, whi ch i s by
defaul t zero, to control how concentrated the l i ght i s. The l i ght’s i ntensi ty i s hi ghest i n the center of the
cone. I t’s attenuated toward the edges of the cone by the cosi ne of the angl e between the di recti on of the
l i ght and the di recti on from the l i ght to the vertex bei ng l i ghted, rai sed to the power of the spot
exponent. Thus, hi gher spot exponents resul t i n a more focused l i ght source. See "The Mathematics of
Lighting" for more detai l s on the equati ons used to cal cul ate l i ght i ntensi ty.
120
Multiple Lights
As menti oned, you can have at l east ei ght l i ghts i n your scene (possi bl y more, dependi ng on your
OpenGL i mpl ementati on). Si nce OpenGL needs to perform cal cul ati ons to determi ne how much l i ght
each vertex recei ves from each l i ght source, i ncreasi ng the number of l i ghts adversel y affects
performance. The constants used to refer to the ei ght l i ghts are GL_LI GHT0, GL_LI GHT1,
GL_LI GHT2, GL_LI GHT3, and so on. I n the precedi ng di scussi ons, parameters rel ated to GL_LI GHT0
were set. I f you want an addi ti onal l i ght, you need to speci fy i ts parameters; al so, remember that the
defaul t val ues are di fferent for these other l i ghts than they are for GL_LI GHT0, as expl ai ned i n Table
6−1. The fol l owi ng l i nes of code defi ne a whi te attenuated spotl i ght:
GLfloat light1_ambient[] = { 0.2, 0.2, 0.2, 1.0 };
GLfloat light1_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat light1_specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat light1_position[] = { −2.0, 2.0, 1.0, 1.0 };
GLfloat spot_direction[] = { −1.0, −1.0, 0.0 };
glLightfv(GL_LIGHT1, GL_AMBIENT, light1_ambient);
glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse);
glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular);
glLightfv(GL_LIGHT1, GL_POSITION, light1_position);
glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, 1.5);
glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.5);
glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 0.2);
glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 45.0);
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, spot_direction);
glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 2.0);
glEnable(GL_LIGHT1);
I f these l i nes were added to Example 6−1, the sphere woul d be l i t wi th two l i ghts, one di recti onal and
one spotl i ght.
Try This
Try This
Modi fy Example 6−1:
• Change the l i ght to be a posi ti onal col ored l i ght rather than a di recti onal whi te one.
• Add an addi ti onal col ored spotl i ght. Hi nt: Use some of the code shown i n the precedi ng secti on.
• Measure how these two changes affect performance.
Controlling a Light’s Position and Direction
OpenGL treats the posi ti on and di recti on of a l i ght source just as i t treats the posi ti on of a geometri c
pri mi ti ve. I n other words, a l i ght source i s subject to the same matri x transformati ons as a pri mi ti ve.
More speci fi cal l y, when glLight*() i s cal l ed to speci fy the posi ti on or the di recti on of a l i ght source, the
posi ti on or di recti on i s transformed by the current model vi ew matri x and stored i n eye coordi nates.
Thi s means you can mani pul ate a l i ght source’s posi ti on or di recti on by changi ng the contents of the
model vi ew matri x stack. (The projecti on matri x has no effect on a l i ght’s posi ti on or di recti on.) Thi s
secti on expl ai ns how to achi eve three di fferent effects by changi ng the poi nt i n the program at whi ch
the l i ght posi ti on i s set, rel ati ve to model i ng or vi ewi ng transformati ons:
• A l i ght posi ti on that remai ns fi xed
• A l i ght that moves around a stati onary object
• A l i ght that moves al ong wi th the vi ewpoi nt
121
I n the si mpl est exampl e, as i n Example 6−1, the l i ght posi ti on remai ns fi xed. To achi eve thi s effect,
you need to set the l i ght posi ti on after whatever vi ewi ng and/or model i ng transformati on you use.
Here’s what the rel evant code from the myinit() and myReshape() routi nes mi ght l ook l i ke:
glViewport(0, 0, w, h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho (−1.5, 1.5, −1.5*h/w, 1.5*h/w, −10.0, 10.0);
else
glOrtho (−1.5*w/h, 1.5*w/h, −1.5, 1.5, −10.0, 10.0);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity();
/* later in myInit() */
GLfloat light_position[] = { 1.0, 1.0, 1.0, 1.0 };
glLightfv(GL_LIGHT0, GL_POSITION, position);
As you can see, the vi ewport and projecti on matri ces are establ i shed fi rst. Then, the i denti ty matri x i s
l oaded as the model vi ew matri x, after whi ch the l i ght posi ti on i s set. Si nce the i denti ty matri x i s used,
the ori gi nal l y speci fi ed l i ght posi ti on (1.0, 1.0, 1.0) i sn’t changed by bei ng mul ti pl i ed by the model vi ew
matri x. Then, si nce nei ther the l i ght posi ti on nor the model vi ew matri x i s modi fi ed after thi s poi nt, the
l i ght remai ns poi nti ng at (1.0, 1.0, 1.0).
Now suppose you want to rotate or transl ate the l i ght posi ti on so that the l i ght moves rel ati ve to a
stati onary object. One way to do thi s i s to set the l i ght posi ti on after the model i ng transformati on,
whi ch i s i tsel f changed speci fi cal l y to modi fy the l i ght posi ti on. You can begi n wi th the same seri es of
cal l s i n an init() routi ne earl y i n the program. Then, probabl y wi thi n an event l oop, you need to perform
the desi red model i ng transformati on (on the model vi ew stack) and reset the l i ght posi ti on. Here’s what
such code mi ght l ook l i ke:
void display(GLint spin)
{
GLfloat light_position[] = { 0.0, 0.0, 1.5, 1.0 };
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glTranslatef(0.0, 0.0, −5.0);
glPushMatrix();
glRotated((GLdouble) spin, 1.0, 0.0, 0.0);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glPopMatrix();
auxSolidTorus();
glPopMatrix();
glFlush();
}
Thi s display() command causes the scene to be redrawn wi th the l i ght rotated spin degrees around a
stati onary torus. Note the two pai rs of glPushMatrix() and glPopMatrix() cal l s, whi ch are used to i sol ate
the vi ewi ng and model i ng transformati ons, al l of whi ch occur on the model vi ew stack. Si nce i n thi s
exampl e the vi ewpoi nt remai ns constant, the current matri x i s pushed down the stack and then the
desi red vi ewi ng transformati on i s l oaded wi th glTranslatef(). The matri x stack i s pushed agai n before
the model i ng transformati on glRotated() i s speci fi ed. Then the l i ght posi ti on i s set i n the new, rotated
coordi nate system so that the l i ght i tsel f appears to be rotated from i ts previ ous posi ti on. (Remember
that the l i ght posi ti on i s stored i n eye coordi nates, whi ch are obtai ned after transformati on by the
model vi ew matri x.) After the rotated matri x i s popped off the stack, the torus i s drawn.
122
To create a l i ght that moves al ong wi th the vi ewpoi nt, you need to set the l i ght posi ti on before the
vi ewi ng transformati on. Then, the vi ewi ng transformati on affects both the l i ght and the vi ewpoi nt i n
the same way. For thi s exampl e, l et’s use a sl i ghtl y di fferent set of cal l s i n the myinit() routi ne:
GLfloat light_position() = { 0.0, 0.0, 1.0, 1.0 };
glViewport(0, 0, w−1, h−1);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(40.0, (GLfloat) w/(GLfloat) h, 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
Then, the display() routi ne that’s cal l ed from the event l oop to redraw the scene mi ght l ook l i ke thi s:
void display(GLint spin)
{
glClear(GL_COLOR_BUFFER_MASK | GL_DEPTH_BUFFER_MASK);
glPushMatrix();
glTranslatef (0.0, 0.0, −5.0);
glRotatef ((GLfloat) spin, 1.0, 0.0, 0.0);
auxSolidTorus();
glPopMatrix();
glFlush();
}
When the l i ghted torus i s redrawn, both the l i ght posi ti on and the vi ewpoi nt are moved spin degrees.
Even though you haven’t respeci fi ed the l i ght posi ti on, the l i ght moves because the eye coordi nate
system has changed.
Try This
Try This
Modi fy Example 6−2:
• Make the l i ght transl ate past the object i nstead of rotati ng around i t. Hi nt: Use glTranslated()
rather than the fi rst glRotated() i n display(), and choose an appropri ate val ue to use i nstead of spin.
• Change the attenuati on so that the l i ght decreases i n i ntensi ty as i t’s moved away from the object.
Hi nt: Add cal l s to glLight*() to set the desi red attenuati on parameters.
Example 6−2 Movi ng a Li ght wi th Model i ng Transformati ons: movel i ght.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
static int spin = 0;
void movelight (AUX_EVENTREC *event)
{
spin = (spin + 30) % 360;
}
void myinit (void)
{
glEnable(GL_LIGHTING);
123
glEnable(GL_LIGHT0);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
}
void display(void)
{
GLfloat position[] = { 0.0, 0.0, 1.5, 1.0 };
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix ();
glTranslatef (0.0, 0.0, −5.0);
glPushMatrix ();
glRotated ((GLdouble) spin, 1.0, 0.0, 0.0);
glRotated (0.0, 1.0, 0.0, 0.0);
glLightfv (GL_LIGHT0, GL_POSITION, position);
glTranslated (0.0, 0.0, 1.5);
glDisable (GL_LIGHTING);
glColor3f (0.0, 1.0, 1.0);
auxWireCube (0.1);
glEnable (GL_LIGHTING);
glPopMatrix ();
auxSolidTorus (0.275, 0.85);
glPopMatrix ();
glFlush ();
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(40.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA | AUX_DEPTH);
auxInitPosition (0, 0, 500, 500);
auxInitWindow (argv[0]);
myinit();
auxMouseFunc (AUX_LEFTBUTTON, AUX_MOUSEDOWN, movelight);
auxReshapeFunc (myReshape);
auxMainLoop(display);
}
Selecting a Lighting Model
124
OpenGL’s noti on of a l i ghti ng model has three components:
• The gl obal ambi ent l i ght i ntensi ty
• Whether the vi ewpoi nt posi ti on i s l ocal to the scene or whether i t shoul d be consi dered to be an
i nfi ni te di stance away
• Whether l i ghti ng cal cul ati ons shoul d be performed di fferentl y for both the front and back faces of
objects
Thi s secti on expl ai ns how to speci fy a l i ghti ng model . I t al so di scusses how to enabl e l i ghti ngthat i s,
how to tel l OpenGL that you want l i ghti ng cal cul ati ons performed.
Global Ambient Light
As di scussed earl i er, each l i ght source can contri bute ambi ent l i ght to a scene. I n addi ti on, there can be
other ambi ent l i ght that’s not from any parti cul ar source. To speci fy the RGBA i ntensi ty of such gl obal
ambi ent l i ght, use the GL_LI GHT_MODEL_AMBI ENT parameter as fol l ows:
GLfloat lmodel_ambient[] = { 0.2, 0.2, 0.2, 1.0 };
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
I n thi s exampl e, the val ues used for lmodel_ambient are the defaul t val ues for
GL_LI GHT_MODEL_AMBI ENT. Si nce these numbers yi el d a smal l amount of whi te ambi ent l i ght,
even i f you don’t add a speci fi c l i ght source to your scene, you can sti l l see the objects i n the scene.
Figure J −18 shows the effect of di fferent amounts of gl obal ambi ent l i ght.
Local or Infinite Viewpoint
The l ocati on of the vi ewpoi nt affects the cal cul ati ons for hi ghl i ghts produced by specul ar refl ectance.
More speci fi cal l y, the i ntensi ty of the hi ghl i ght at a parti cul ar vertex depends on the normal at that
vertex, the di recti on from the vertex to the l i ght source, and the di recti on from the vertex to the
vi ewpoi nt. Keep i n mi nd that the vi ewpoi nt i sn’t actual l y bei ng moved by cal l s to l i ghti ng commands
(you need to change the projecti on transformati on, as descri bed i n "Projection Transformations");
i nstead, di fferent assumpti ons are made for the l i ghti ng cal cul ati ons as i f the vi ewpoi nt were moved.
Wi th an i nfi ni te vi ewpoi nt, the di recti on between i t and any vertex i n the scene remai ns constant. A
l ocal vi ewpoi nt tends to yi el d more real i sti c resul ts, but si nce the di recti on has to be cal cul ated for each
vertex, overal l performance i s decreased wi th a l ocal vi ewpoi nt. By defaul t, an i nfi ni te vi ewpoi nt i s
assumed. Here’s how to change to a l ocal vi ewpoi nt:
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
Thi s cal l pl aces the vi ewpoi nt at (0, 0, 0) i n eye coordi nates. To swi tch back to an i nfi ni te vi ewpoi nt,
pass i n GL_FALSE as the argument.
Two−sided Lighting
Li ghti ng cal cul ati ons are performed for al l pol ygons, whether they’re front−faci ng or back−faci ng. Si nce
you usual l y set up l i ghti ng condi ti ons wi th the front−faci ng pol ygons i n mi nd, however, the
back−faci ng ones typi cal l y aren’t correctl y i l l umi nated. I n Example 6−1 where the object i s a sphere,
onl y the front faces are ever seen, si nce they’re the ones on the outsi de of the sphere. So, i n thi s case, i t
doesn’t matter what the back−faci ng pol ygons l ook l i ke. I f the sphere was goi ng to be cut away so that
i ts i nsi de surface woul d be vi si bl e, however, you mi ght want to have the i nsi de surface be ful l y l i t
accordi ng to the l i ghti ng condi ti ons you’ve defi ned; you mi ght al so want to suppl y a di fferent materi al
descri pti on for the back faces. When you turn on two−si ded l i ghti ng, as fol l ows
glLightModeli(LIGHT_MODEL_TWO_SIDE, GL_TRUE);
OpenGL reverses the surface normal s for back−faci ng pol ygons; typi cal l y, thi s means that the surface
normal s of vi si bl e back− and front−faci ng pol ygons face the vi ewer, rather than poi nti ng away. As a
125
normal s of vi si bl e back− and front−faci ng pol ygons face the vi ewer, rather than poi nti ng away. As a
resul t, al l pol ygons are i l l umnated correctl y.
To turn two−si ded l i ghti ng off, pass i n GL_FALSE as the argument i n the precedi ng cal l . See
"Defining Material Properties" for i nformati on about how to suppl y materi al properti es for both
faces. You can al so control whi ch faces OpenGL consi ders to be front−faci ng wi th the command
glFrontFace(). See "Reversing and Culling Polygon Faces" for more i nformati on about thi s
command.
Enabling Lighting
Wi th OpenGL, you need to expl i ci tl y enabl e (or di sabl e) l i ghti ng. I f l i ghti ng i sn’t enabl ed, the current
col or i s si mpl y mapped onto the current vertex, and no cal cul ati ons concerni ng normal s, l i ght sources,
the l i ghti ng model , and materi al properti es are performed. Here’s how to enabl e l i ghti ng:
glEnable(GL_LIGHTING);
To di sabl e l i ghti ng, cal l glDisable() wi th GL_LI GHTI NG as the argument.
You al so need to expl i ci tl y enabl e each l i ght source that you defi ne, after you’ve speci fi ed the
parameters for that source. Example 6−1 uses onl y one l i ght, GL_LI GHT0:
glEnable(GL_LIGHT0);
Defining Material Properties
You’ve seen how to create l i ght sources wi th certai n characteri sti cs and how to defi ne the desi red
l i ghti ng model . Thi s secti on descri bes how to defi ne the materi al properti es of the objects i n the scene:
the ambi ent, di ffuse, and specul ar col ors, the shi ni ness, and the col or of any emi tted l i ght. The
equati ons used i n the l i ghti ng and materi al −property cal cul ati ons are descri bed i n "The Mathematics
of Lighting." Most of the materi al properti es are conceptual l y si mi l ar to ones you’ve al ready used to
create l i ght sources. The mechani sm for setti ng them i s si mi l ar, except that the command used i s cal l ed
glMaterial*().
voi d glMaterial{i f}[v](GLenum face, GLenum pname, TYPEparam);
Speci fi es a current materi al property for use i n l i ghti ng cal cul ati ons. The face parameter can be
GL_FRONT, GL_BACK, or GL_FRONT_AND_BACK to i ndi cate whi ch face of the object the materi al
shoul d be appl i ed to. The parti cul ar materi al property bei ng set i s i denti fi ed by pname and the desi red
val ues for that property are gi ven by param, whi ch i s ei ther a poi nter to a group of val ues (i f the vector
versi on i s used) or the actual val ue (i f the nonvector versi on i s used). The nonvector versi on works onl y
for setti ng GL_SHI NI NESS. The possi bl e val ues for pname are shown i n Table 6−2 . Note that
GL_AMBI ENT_AND_DI FFUSE al l ows you to set both the ambi ent and di ffuse materi al col ors
si mul taneousl y to the same RGBA val ue.
Parameter Name Default Value Meaning
GL_AMBIENT (0.2, 0.2, 0.2, 1.0) ambient color of material
GL_DIFFUSE (0.8, 0.8, 0.8, 1.0) diffuse color of material
GL_AMBIENT_AND_DIFFUSE ambient and diffuse color of
material
GL_SPECULAR (0.0, 0.0, 0.0, 1.0) specular color of material
GL_SHININESS 0.0 specular exponent
GL_EMISSION (0.0, 0.0, 0.0, 1.0) emissive color of material
GL_COLOR_INDEXES (0,1,1) ambient, diffuse, and specular
color indices
Table 6−2 Defaul t Val ues for pname Parameter of gl Materi al *()
126
As di scussed i n "Selecting a Lighting Model," you can choose to have l i ghti ng cal cul ati ons
performed di fferentl y for the front− and back−faci ng pol ygons of objects. I f the back faces mi ght i ndeed
be seen, you can suppl y di fferent materi al properti es for the front and the back surfaces by usi ng the
faceparameter of glMaterial*(). See Figure J −19 for an exampl e of an object drawn wi th di fferent
i nsi de and outsi de materi al properti es.
To gi ve you an i dea of the possi bl e effects you can achi eve by mani pul ati ng materi al properti es, see
Figure J −21. Thi s fi gure shows the same object drawn wi th several di fferent sets of materi al
properti es. The same l i ght source and l i ghti ng model are used for the enti re fi gure. The secti ons that
fol l ow di scuss the speci fi c properti es used to draw each of these spheres.
Note that most of the materi al properti es set wi th glMaterial*() are (R, G, B, A) col ors. Regardl ess of
what al pha val ues are suppl i ed for other parameters, the al pha val ue at any parti cul ar vertex i s the
di ffuse−materi al al pha val ue (that i s, the al pha val ue gi ven to GL_DI FFUSE wi th the glMaterial*()
command, as descri bed i n the next secti on. (See "Blending" for a compl ete di scussi on of al pha val ues.)
Al so, none of the RGBA materi al properti es appl y i n col or−i ndex mode; see "Lighting in Color−Index
Mode" for more i nformati on about what parameters are rel evant i n col or−i ndex mode.
Diffuse and Ambient Reflection
The GL_DI FFUSE and GL_AMBI ENT parameters set wi th glMaterial*() affect the col or of the di ffuse
and ambi ent l i ght refl ected by an object. Di ffuse refl ectance pl ays the most i mportant rol e i n
determi ni ng what you percei ve the col or of an object to be. I t’s affected by the col or of the i nci dent
di ffuse l i ght and the angl e of the i nci dent l i ght rel ati ve to the normal di recti on. (I t’s most i ntense where
the i nci dent l i ght fal l s perpendi cul ar to the surface.) The posi ti on of the vi ewpoi nt doesn’t affect di ffuse
refl ectance at al l .
Ambi ent refl ectance affects the overal l col or of the object. Because di ffuse refl ectance i s bri ghtest where
an object i s di rectl y i l l umi nated, ambi ent refl ectance i s most noti ceabl e where an object recei ves no
di rect i l l umi nati on. An object’s total ambi ent refl ectance i s affected by the gl obal ambi ent l i ght and
ambi ent l i ght from i ndi vi dual l i ght sources. Li ke di ffuse refl ectance, ambi ent refl ectance i sn’t affected
by the posi ti on of the vi ewpoi nt.
For real −worl d objects, di ffuse and ambi ent refl ectance are normal l y the same col or. For thi s reason,
OpenGL provi des you wi th a conveni ent way of assi gni ng the same val ue to both si mul taneousl y wi th
glMaterial*():
GLfloat mat_amb_diff[] = { 0.1, 0.5, 0.8, 1.0 };
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE,
mat_amb_diff);
I n thi s exampl e, the RGBA col or (0.1, 0.5, 0.8, 1.0)a deep bl ue col orrepresents the current ambi ent
and di ffuse refl ectance for both the front− and back−faci ng pol ygons.
I n Figure J −21, the fi rst row of spheres has no ambi ent refl ectance (0.0, 0.0, 0.0, 0.0), and the second
row has a si gni fi cant amount of i t (0.7, 0.7, 0.7, 1.0).
Specular Reflection
Specul ar refl ecti on from an object produces hi ghl i ghts. Unl i ke ambi ent and di ffuse refl ecti on, the
amount of specul ar refl ecti on seen by a vi ewer does depend on the l ocati on of the vi ewpoi nti t’s
bri ghtest al ong the di rect angl e of refl ecti on. To see thi s, i magi ne l ooki ng at a metal l i c bal l outdoors i n
the sunl i ght. As you move your head, the hi ghl i ght created by the sunl i ght moves wi th you to some
extent. However, i f you move your head too much, you l ose the hi ghl i ght enti rel y.
OpenGL al l ows you to set the RGBA col or of a specul ar hi ghl i ght (wi th GL_SPECULAR) and to control
the si ze and bri ghtness of the hi ghl i ght (wi th GL_SHI NI NESS). You can assi gn a number i n the range
of [0.0, 128.0] to GL_SHI NI NESSthe hi gher the val ue, the smal l er and bri ghter (more focused) the
hi ghl i ght. See "The Mathematics of Lighting" for the detai l s of how specul ar hi ghl i ghts are
127
cal cul ated.
I n Figure J −21, the spheres i n the fi rst col umn have no specul ar refl ecti on. I n the second col umn,
GL_SPECULAR and GL_SHI NI NESS are assi gned val ues as fol l ows:
GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat low_shininess[] = { 5.0 };
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, low_shininess);
I n the thi rd col umn, the GL_SHI NI NESS parameter i s i ncreased to 100.0.
Emission
By speci fyi ng an RGBA col or for GL_EMI SSI ON, you can make an object appear to be gi vi ng off l i ght of
that col or. Si nce most real −worl d objects (except l i ghts) don’t emi t l i ght, you’l l probabl y use thi s feature
mostl y to si mul ate l amps and other l i ght sources i n a scene. I n Figure J −21, the spheres i n the fourth
col umn have a greeni sh val ue for GL_EMI SSI ON:
GLfloat mat_emission[] = {0.3, 0.2, 0.2, 0.0};
glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission);
Noti ce that the spheres appear to be sl i ghtl y gl owi ng; however, they’re not actual l y acti ng as l i ght
sources. You woul d need to create a l i ght source and posi ti on i t at the same l ocati on as the sphere to
create that effect.
Changing Material Properties
Example 6−1uses the same materi al properti es for al l verti ces of the onl y object i n the scene (the
sphere). I n other si tuati ons, you mi ght want to assi gn di fferent materi al properti es for di fferent
verti ces on the same object. More l i kel y, you have more than one object i n the scene, and each object
has di fferent materi al properti es. For exampl e, the code that produced Figure J −21 has to draw ei ght
di fferent objects (al l spheres), each wi th di fferent materi al properti es. Example 6−3 shows some of
the code i n the display() routi ne.
Example 6−3 Usi ng Di fferent Materi al Properti es: materi al .c
GLfloat no_mat[] = { 0.0, 0.0, 0.0, 1.0 };
GLfloat mat_ambient[] = { 0.7, 0.7, 0.7, 1.0 };
GLfloat mat_ambient_color[] = { 0.8, 0.8, 0.2, 1.0 };
GLfloat mat_diffuse[] = { 0.1, 0.5, 0.8, 1.0 };
GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat no_shininess[] = { 0.0 };
GLfloat low_shininess[] = { 5.0 };
GLfloat high_shininess[] = { 100.0 };
GLfloat mat_emission[] = {0.3, 0.2, 0.2, 0.0};
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* draw sphere in first row, first column
* diffuse reflection only; no ambient or specular
*/
glPushMatrix();
glTranslatef (−3.75, 3.0, 0.0);
glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat);
glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess);
128
glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
auxSolidSphere();
glPopMatrix();
/* draw sphere in first row, second column
* diffuse and specular reflection; low shininess; no ambient
*/
glPushMatrix();
glTranslatef (−1.25, 3.0, 0.0);
glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, low_shininess);
glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
auxSolidSphere();
glPopMatrix();
/* draw sphere in first row, third column
* diffuse and specular reflection; high shininess; no ambient
*/
glPushMatrix();
glTranslatef (1.25, 3.0, 0.0);
glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);
glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
auxSolidSphere();
glPopMatrix();
/* draw sphere in first row, fourth column
* diffuse refl.; emission; no ambient or specular reflection
*/
glPushMatrix();
glTranslatef (3.75, 3.0, 0.0);
glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat);
glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess);
glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission);
auxSolidSphere();
glPopMatrix();
As you can see, glMaterialfv() i s cal l ed repeatedl y to set the desi red materi al property for each sphere.
Note that i t’s cal l ed onl y to change a property that needs to be changed. The second and thi rd spheres
use the same ambi ent and di ffuse properti es as the fi rst sphere, for exampl e, so these properti es aren’t
reset. Si nce glMaterial*() has a performance cost associ ated wi th i ts use, i t’s best to mi ni mi ze
materi al −property changes.
Another techni que for mi ni mi zi ng performance costs associ ated wi th changi ng materi al properti es i s to
use glColorMaterial().
voi d glColorMaterial(GLenum face, GLenum mode);
Causes the materi al property (or properti es) speci fi ed by modeof the speci fi ed materi al face (or faces)
speci fi ed by faceto track the val ue of the current col or at al l ti mes. A change to the current col or (usi ng
129
glColor*()) i mmedi atel y updates the speci fi ed materi al properti es. The faceparameter can be
GL_FRONT, GL_BACK, or GL_FRONT_AND_BACK (the defaul t). The modeparameter can be
GL_AMBI ENT, GL_DI FFUSE, GL_AMBI ENT_AND_DI FFUSE (the defaul t), GL_SPECULAR, or
GL_EMI SSI ON.
Note that glColorMaterial() speci fi es two i ndependent val ues: the fi rst speci fi es whi ch face or faces are
updated, and the second speci fi es whi ch materi al property or properti es of those faces are updated.
OpenGL does not mai ntai n separate modevari abl es for each face.
After cal l i ng glColorMaterial(), you need to cal l glEnable() wi th GL_COLOR_MATERI AL as the
parameter. Then, you can change the current col or usi ng glColor*() (or other materi al properti es, usi ng
glMaterial*()) as needed as you draw:
glColorMaterial(GL_FRONT, GL_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
glColor3f(0.2, 0.5, 0.8);
/* draw some objects here */
glColor3f(0.9, 0.0, 0.2);
/* draw other objects here */
glDisable(GL_COLOR_MATERIAL);
You shoul d use glColorMaterial() whenever you need to change a si ngl e materi al parameter for most
verti ces i n your scene. I f you need to change more than one materi al parameter, as was the case for
Figure J −21, use glMaterial*(). When you don’t need the capabi l i ti es of glColorMaterial() anymore, be
sure to di sabl e i t, so that you don’t get undesi red materi al properti es and so that you don’t i ncur the
performance cost associ ated wi th i t. The performance val ue i n usi ng glColorMaterial() vari es,
dependi ng on your OpenGL i mpl ementati on. Some i mpl ementati ons may be abl e to opti mi ze the vertex
routi nes so that they can qui ckl y update materi al properti es based on the current col or.
Example 6−4shows an i nteracti ve program that uses glColorMaterial() to change materi al
parameters. Pressi ng each of the three mouse buttons changes the col or of the di ffuse refl ecti on.
Example 6−4 Usi ng gl Col orMateri al (): col ormat.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
GLfloat diffuseMaterial[4] = { 0.5, 0.5, 0.5, 1.0 };
void myinit(void)
{
GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };
glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuseMaterial);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialf(GL_FRONT, GL_SHININESS, 25.0);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glColorMaterial(GL_FRONT, GL_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
130
}
void changeRedDiffuse (AUX_EVENTREC *event)
{
diffuseMaterial[0] += 0.1;
if (diffuseMaterial[0] > 1.0)
diffuseMaterial[0] = 0.0;
glColor4fv(diffuseMaterial);
}
void changeGreenDiffuse (AUX_EVENTREC *event)
{
diffuseMaterial[1] += 0.1;
if (diffuseMaterial[1] > 1.0)
diffuseMaterial[1] = 0.0;
glColor4fv(diffuseMaterial);
}
void changeBlueDiffuse (AUX_EVENTREC *event)
{
diffuseMaterial[2] += 0.1;
if (diffuseMaterial[2] > 1.0)
diffuseMaterial[2] = 0.0;
glColor4fv(diffuseMaterial);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
auxSolidSphere(1.0);
glFlush();
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho (−1.5, 1.5, −1.5*(GLfloat)h/(GLfloat)w,
1.5*(GLfloat)h/(GLfloat)w, −10.0, 10.0);
else
glOrtho (−1.5*(GLfloat)w/(GLfloat)h,
1.5*(GLfloat)w/(GLfloat)h, −1.5, 1.5, −10.0, 10.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA | AUX_DEPTH);
auxInitPosition (0, 0, 500, 500);
auxInitWindow (argv[0]);
131
myinit();
auxMouseFunc(AUX_LEFTBUTTON, AUX_MOUSEDOWN,
changeRedDiffuse);
auxMouseFunc(AUX_MIDDLEBUTTON, AUX_MOUSEDOWN,
changeGreenDiffuse);
auxMouseFunc(AUX_RIGHTBUTTON, AUX_MOUSEDOWN,
changeBlueDiffuse);
auxReshapeFunc(myReshape);
auxMainLoop(display);
}
Try This
Try This
Modi fy Example 6−3:
• Change the gl obal ambi ent l i ght i n the scene. Hi nt: Al ter the val ue of the
GL_LI GHT_MODEL_AMBI ENT parameter.
• Change the di ffuse, ambi ent, and specul ar refl ecti on parameters, the shi ni ness exponent, and the
emi ssi on col or. Hi nt: Use the glMaterial*() command, but avoi d maki ng excessi ve cal l s.
• Use two−si ded materi al s and add an arbi trary cl i ppi ng pl ane (see "Additional Clipping Planes")
so you can see the i nsi de and outsi de of a row or col umn of spheres. Hi nt: Turn on two−si ded
l i ghti ng wi th GL_LI GHT_MODEL_TWO_SI DE, set the desi red materi al properti es, and add a
cl i ppi ng pl ane.
• Remove al l the glMaterialfv() cal l s, and use the more effi ci ent glColorMaterial() cal l s to achi eve the
same l i ghti ng.
The Mathematics of Lighting
Advanced
Thi s secti on presents the equati ons used by OpenGL to perform l i ghti ng cal cul ati ons to determi ne
col ors when i n RGBA mode. (You can fi nd the correspondi ng cal cul ati ons for col or−i ndex mode i n "The
Mathematics of Color−Index Mode Lighting.") You don’t need to read thi s secti on i f you’re wi l l i ng
to experi ment to obtai n the l i ghti ng condi ti ons you want. Even after readi ng thi s secti on, you’l l
probabl y have to experi ment, but you’l l have a better i dea of how the val ues of parameters affect a
vertex’s col or. Remember that i f l i ghti ng i s not enabl ed, the col or of a vertex i s si mpl y the current col or;
i f i t i s enabl ed, the l i ghti ng computati ons descri bed here are carri ed out i n eye coordi nates.
I n the fol l owi ng equati ons, mathemati cal operati ons are performed separatel y on the R, G, and B
components. Thus, for exampl e, when three terms are shown as added together, the R val ues, the G
val ues, and the B val ues for each term are separatel y added to form the fi nal RGB col or (R
1
+R
2
+R
3
, G
1
+G
2
+G
3
, B
1
+B
2
+B
3
). When three terms are mul ti pl i ed, the cal cul ati on i s (R
1
R
2
R
3
, G
1
G
2
G
3
, B
1
B
2
B
3
).
(Remember that the fi nal A or al pha component at a vertex i s equal to the materi al ’s di ffuse al pha
val ue at that vertex.)
The col or produced by l i ghti ng a vertex i s computed as fol l ows:
vertex col or = the materi al emi ssi on at that vertex + the gl obal ambi ent l i ght scal ed by the
materi al ’s ambi ent property at that vertex + the ambi ent, di ffuse, and specul ar contri buti ons from
al l the l i ght sources, properl y attenuated
After l i ghti ng cal cul ati ons are performed, the col or val ues are cl amped (i n RGBA mode) to the range
[0,1].
Note that OpenGL’s l i ghti ng cal cul ati ons don’t take i nto account the possi bi l i ty of one object bl ocki ng
l i ght from another, so shadows aren’t automati cal l y created. (See "Shadows" for a techni que to create
132
shadows.) Al so keep i n mi nd that wi th OpenGL, i l l umi nated objects don’t radi ate l i ght onto other
objects.
Material Emission
The materi al emi ssi on term i s the si mpl est. I t’s the RGB val ue assi gned to the GL_EMI SSI ON
parameter.
Scaled Global Ambient Light
The second term i s computed by mul ti pl yi ng the gl obal ambi ent l i ght (as defi ned by the
GL_LI GHT_MODEL_AMBI ENT parameter) by the materi al ’s ambi ent property (GL_AMBI ENT’s
val ues as assi gned wi th glMaterial*()):
ambi ent
l i ght model
* ambi ent
materi al
Each of the R, G, and B val ues for these two parameters are mul ti pl i ed separatel y to compute the fi nal
RGB val ue for thi s term: (R
1
R
2
, G
1
G
2
, B
1
B
2
).
Contributions from Light Sources
Each l i ght source may contri bute to a vertex’s col or, and these contri buti ons are added together. The
equati on for computi ng each l i ght source’s contri buti on i s as fol l ows:
contri buti on = attenuati on factor * spotl i ght effect *
(ambi ent term + di ffuse term + specul ar term)
Attenuation Factor
The attenuation factor was descri bed i n "Position and Attenuation":
attenuati on factor =
where
d = di stance between the l i ght’s posi ti on and the vertex
k
c
= GL_CONSTANT_ATTENUATI ON
k
l
= GL_LI NEAR_ATTENUATI ON
k
q
= GL_QUADRATI C_ATTENUATI ON
I f the l i ght i s a di recti onal one, the attenuati on factor i s 1.
Spotlight Effect
The spotlight effect eval uates to one of three possi bl e val ues, dependi ng on whether the l i ght i s actual l y
a spotl i ght and whether the vertex l i es i nsi de or outsi de the cone of i l l umi nati on produced by the
133
spotl i ght:
• 1 i f the l i ght i sn’t a spotl i ght (GL_SPOT_CUTOFF i s 180.0).
• 0 i f the l i ght i s a spotl i ght but the vertex l i es outsi de the cone of i l l umi nati on produced by the
spotl i ght.
• (max {v x d, 0 })
GL_SPOT_EXPONENT
where:
v = (v
x
, v
y
, v
z
) i s the uni t vector that poi nts from the spotl i ght (GL_POSI TI ON) to the vertex.
d = (d
x
, d
y
, d
z
) i s the spotl i ght’s di recti on (GL_SPOT_DI RECTI ON), assumi ng the l i ght i s a
spotl i ght and the vertex l i es i nsi de the cone of i l l umi nati on produced by the spotl i ght.
The dot product of the two vectors v and d vari es as the cosi ne of the angl e between them; hence,
objects di rectl y i n l i ne get maxi mum i l l umi nati on, and objects off the axi s have thei r i l l umi nati on
drop as the cosi ne of the angl e.
To determi ne whether a parti cul ar vertex l i es wi thi n the cone of i l l umi nati on, OpenGL eval uates (max
{v x d , 0 }) where v and d are as defi ned above. I f thi s val ue i s l ess than the cosi ne of the spotl i ght’s
cutoff angl e (GL_SPOT_CUTOFF), then the vertex l i es outsi de the cone; otherwi se, i t’s i nsi de the cone.
Ambient Term
The ambi ent term i s si mpl y the ambi ent col or of the l i ght scal ed by the ambi ent materi al property:
ambi ent
l i ght
*ambi ent
materi al
Diffuse Term
The di ffuse term needs to take i nto account whether l i ght fal l s di rectl y on the vertex, the di ffuse col or of
the l i ght, and the di ffuse materi al property:
(max {l · n , 0 }) * di ffuse
l i ght
* di ffuse
materi al
where:
l = (l
x
, l
y
, l
z
) i s the uni t vector that poi nts from the vertex to the l i ght posi ti on (GL_POSI TI ON).
n = (n
x
, n
y
, n
z
) i s the uni t normal vector at the vertex.
Specular Term
The specul ar term al so depends on whether l i ght fal l s di rectl y on the vertex. I f l · n i s l ess than or equal
to zero, there i s no specul ar component at the vertex. (I f i t’s l ess than zero, the l i ght i s on the wrong si de
of the surface.) I f there’s a specul ar component, i t depends on the fol l owi ng:
• The uni t normal vector at the vertex (n
x
, n
y
, n
z
).
• The sum of the two uni t vectors that poi nt between (1) the vertex and the l i ght posi ti on and (2) the
vertex and the vi ewpoi nt (assumi ng that GL_LI GHT_MODEL_LOCAL_VI EWER i s true; i f i t’s not
true, the vector (0, 0, 1) i s used as the second vector i n the sum). Thi s vector sum i s normal i zed (by
di vi di ng each component by the magni tude of the vector) to yi el d s = (s
x
, s
y
, s
z
).
• The specul ar exponent (GL_SHI NI NESS).
• The specul ar col or of the l i ght (GL_SPECULAR
l i ght
).
• The specul ar property of the materi al (GL_SPECULAR
materi al )
.
Usi ng these defi ni ti ons, here’s how OpenGL cal cul ates the specul ar term:
(max {s x n , 0})
shi ni ness
* specul ar
l i ght
* specul ar
materi al
However, i f 1 x n = 0, the specul ar term i s 0.
Putting It All Together
Usi ng the defi ni ti ons of terms descri bed i n the precedi ng paragraphs, the fol l owi ng represents the
enti re l i ghti ng cal cul ati on i n RGBA mode.
vertex col or = emi ssi on
materi al
+
134
ambi ent
l i ght model
* ambi ent
materi al
+
[ ambi ent
l i ght
*ambi ent
materi al
+
(max {1 x n , 0 }) * di ffuse
l i ght
* di ffuse
materi al
+
(max {s x n ,0})
shi ni ness
* specul ar
l i ght
* specul ar
materi al
]
i
Lighting in Color−Index Mode
I n col or−i ndex mode, the parameters compri si ng RGBA val ues ei ther have no effect or have a speci al
i nterpretati on. Si nce i t’s much harder to achi eve certai n effects i n col or−i ndex mode, you shoul d use
RGBA whenever possi bl e. I n fact, the onl y l i ght−source, l i ghti ng−model , or materi al parameters i n an
RGBA form that are used i n col or i ndex mode are the l i ght−source parameters GL_DI FFUSE and
GL_SPECULAR and the materi al parameter GL_SHI NI NESS. These parameters (d
l
and s
l
,
respecti vel y) are used to compute col or−i ndex di ffuse and specul ar l i ght i ntensi ti es (d
ci
and s
ci
) as
fol l ows:
d
ci
= 0.30 R(d
l
) + 0.59 G(d
l
) + 0.11 B(d
l
)
s
ci
= 0.3 R(s
l
) + 0.59 G(s
l
) + 0.11 B(s
l
)
where R(x), G(x), and B(x) refer to the red, green, and bl ue components, respecti vel y, of col or x. The
wei ghti ng val ues 0.30, 0.59, and 0.11 refl ect the "perceptual " wei ghts that red, green, and bl ue have for
your eyeyour eye i s most sensi ti ve to green and l east sensi ti ve to bl ue.
To speci fy materi al col ors i n col or−i ndex mode, use glMaterial*() wi th the speci al parameter
GL_COLOR_I NDEXES, as fol l ows:
GLfloat mat_colormap[] = { 16.0, 47.0, 79.0 };
glMaterialfv(GL_FRONT, GL_COLOR_INDEXES, mat_colormap);
The three numbers suppl i ed for GL_COLOR_I NDEXES speci fy the col or i ndi ces for the ambi ent,
di ffuse, and specul ar materi al col ors, respecti vel y. I n other words, OpenGL regards the col or associ ated
wi th the fi rst i ndex (16.0 i n thi s exampl e) as the pure ambi ent col or, wi th the second i ndex (47.0) as the
pure di ffuse col or, and wi th the thi rd i ndex (79.0) as the pure specul ar col or. (By defaul t, the ambi ent
col or i ndex i s 0.0, and the di ffuse and specul ar col or i ndi ces are both 1.0. Note that glColorMaterial()
has no effect on col or−i ndex l i ghti ng.)
As i t draws a scene, OpenGL uses col ors associ ated wi th i ndi ces i n between these numbers to shade
objects i n the scene. Therefore, you must bui l d a col or ramp between the i ndi cated i ndi ces (i n thi s
exampl e, between i ndi ces 16 and 47, and then between 47 and and 79). Often, the col or ramp i s bui l t
smoothl y, but you mi ght want to use other formul ati ons to achi eve di fferent effects. Here’s an exampl e
of a smooth col or ramp that starts wi th a bl ack ambi ent col or and goes through a magenta di ffuse col or
to a whi te specul ar col or:
for (i = 0; i < 32; i++) {
135
auxSetOneColor (16 + i, 1.0 * (i/32.0), 0.0, 1.0 * (i/32.0));
auxSetOneColor (48 + i, 1.0, 1.0 * (i/32.0), 1.0);
}
The auxi l i ary l i brary command auxSetOneColor() takes four arguments. I t associ ates the col or i ndex
i ndi cated by the fi rst argument to the RGB tri pl et speci fi ed by the l ast three arguments. When i = 0, the
col or i ndex 16 i s assi gned the RGB val ue (0.0, 0.0, 0.0), or bl ack. The col or ramp bui l ds smoothl y up to
the di ffuse materi al col or at i ndex 47 (when i = 31), whi ch i s assi gned the pure magenta RGB val ue
(1.0, 0.0, 1.0). The second l oop bui l ds the ramp between the magenta di ffuse col or and the whi te (1.0,
1.0, 1.0) specul ar col or (i ndex 79). Figure J −20 shows the resul t of usi ng thi s col or ramp wi th a si ngl e
l i ghted sphere.
The Mathematics of Color−Index Mode Lighting
Advanced
As you mi ght expect, si nce the al l owabl e parameters are di fferent for col or−i ndex mode than for RGBA
mode, the cal cul ati ons are di fferent as wel l . Si nce there’s no materi al emi ssi on and no ambi ent l i ght,
the onl y terms of i nterest from the RGBA equati ons are the di ffuse and specul ar contri buti ons from the
l i ght sources and the shi ni ness. Even these need to be modi fi ed, however, as expl ai ned bel ow.
Begi n wi th the di ffuse and specul ar terms from the RGBA equati ons. I n the di ffuse term, i nstead of
di ffuse
l i ght
* di ffuse
materi al
, substi tute d
ci
as defi ned i n the previ ous secti on for col or−i ndex mode.
Si mi l arl y, i n the specul ar term, i nstead of specul ar
l i ght
* specul ar
materi al
, use s
ci
as defi ned i n the
previ ous secti on. (Cal cul ate the attenuati on, spotl i ght effect, and al l other components of these terms as
before.) Cal l these modi fi ed di ffuse and specul ar terms d and s, respecti vel y. Now l et s’ = mi n{s, 1 }, and
then compute
c = a
m
+ d(1−s’)(d
m
−a
m
) + s’(s
m
−a
m
)
where a
m
, d
m
, and s
m
are the ambi ent, di ffuse, and specul ar materi al i ndexes speci fi ed usi ng
GL_COLOR_I NDEXES. The fi nal col or i ndex i s
c’ = mi n {c, s
m
}
After l i ghti ng cal cul ati ons are performed, the col or−i ndex val ues are converted to fi xed−poi nt (wi th an
unspeci fi ed number of bi ts to the ri ght of the bi nary poi nt). Then the i nteger porti on i s masked (bi twi se
ANDed) wi th 2
n
−1, where n i s the number of bi ts i n a col or i n the col or−i ndex buffer.
Chapter 7
Blending, Antialiasing, and Fog
Chapter Objectives
After readi ng thi s chapter, you’l l be abl e to do the fol l owi ng:
• Bl end col ors to achi eve such effects as maki ng objects appear transl ucent
• Smooth jagged edges of l i nes and pol ygons wi th anti al i asi ng
• Create scenes wi th real i sti c atmospheri c effects
The precedi ng chapters have gi ven you the basi c i nformati on you need to create a computer−graphi cs
scene; you’ve l earned how to do the fol l owi ng:
• Draw geometri c shapes
• Transform them so that they can be vi ewed from whatever perspecti ve you wi sh
• Use di spl ay l i sts to maxi mi ze your program’s effi ci ency
• Speci fy how the geometri c shapes i n your scene shoul d be col ored and shaded
• Add l i ghts and i ndi cate how they shoul d affect the shapes i n your scene
Now you’re ready to get a l i ttl e fanci er. Thi s chapter di scusses three techni ques that can add extra
136
detai l and pol i sh to your scene. None of these techni ques i s hard to usei n fact, i t’s probabl y harder to
expl ai n them than to use them. Each of these techni ques i s descri bed i n i ts own major secti on:
• "Blending"tel l s you how to speci fy a bl endi ng functi on that combi nes col or val ues from a source
and a desti nati on. The fi nal effect i s that parts of your scene appear transl ucent.
• "Antialiasing"expl ai ns thi s rel ati vel y subtl e techni que that al ters col ors so that the edges of
poi nts, l i nes, and pol ygons appear smooth rather than angul ar and jagged.
• "Fog"descri bes how to create the i l l usi on of depth by computi ng the col or val ues of an object based
on di stance from the vi ewpoi nt. Thus, objects that are far away appear to fade i nto the background,
just as they do i n real l i fe.
Blending
You’ve al ready seen al pha val ues (al pha i s the A i n RGBA), but they’ve al ways been 1.0, and they
haven’t been di scussed. Al pha val ues are speci fi ed wi th glColor*(), when usi ng glClearColor() to speci fy
a cl eari ng col or, and when speci fyi ng certai n l i ghti ng parameters such as a materi al property or
l i ght−source i ntensi ty. As you l earned i n Chapter 5 , the pi xel s on a moni tor screen emi t red, green,
and bl ue l i ght, whi ch i s control l ed by the red, green, and bl ue col or val ues. So how does an al pha val ue
affect what gets drawn i n a wi ndow on the screen? When bl endi ng i s enabl ed, the al pha val ue i s used to
combi ne the col or val ue of the fragment bei ng processed wi th that of the pi xel al ready stored i n the
framebuffer. Bl endi ng occurs after your scene has been rasteri zed and converted to fragments, but just
before the fi nal pi xel s are drawn i n the framebuffer. Al pha val ues can al so be used i n the al pha test to
accept or reject a fragment based on i ts al pha val ue. See Chapter 10 for more i nformati on about thi s
process.
Wi thout bl endi ng, each new fragment overwri tes any exi sti ng col or val ues i n the framebuffer, as
though the fragment i s opaque. Wi th bl endi ng, you can control how much of the exi sti ng col or val ue
shoul d be combi ned wi th the new fragment’s val ue. Thus, you can use al pha bl endi ng to create a
transl ucent fragment, one that l ets some of the previ ousl y stored col or val ue "show through." Col or
bl endi ng l i es at the heart of techni ques such as transparency, di gi tal composi ti ng, and pai nti ng.
Note: Al pha val ues aren’t speci fi ed i n col or−i ndex mode. Thus, bl endi ng operati ons aren’t performed
i n col or−i ndex mode
The most natural way for you to thi nk of bl endi ng operati ons i s to vi ew the RGB components of a
fragment as representi ng i ts col or, and the al pha component as representi ng opaci ty. Thus,
transparent or transl ucent surfaces have l ower opaci ty than opaque ones. For exampl e, i f you’re
vi ewi ng an object through green gl ass, the col or you see i s partl y green from the gl ass and partl y the
col or of the object. The percentage vari es dependi ng on the transmi ssi on properti es of the gl ass: I f the
gl ass transmi ts 80 percent of the l i ght that stri kes i t (that i s, has an opaci ty of 20 percent), the col or you
see i s a combi nati on of 20 percent gl ass col or and 80 percent of the col or of the object behi nd i t. You can
easi l y i magi ne si tuati ons wi th mul ti pl e transl ucent surfaces. I f you l ook at an automobi l e, for i nstance,
i ts i nteri or has one pi ece of gl ass between i t and your vi ewpoi nt; some objects behi nd the automobi l e
are vi si bl e through two pi eces of gl ass.
The Source and Destination Factors
Duri ng bl endi ng, col or val ues of the i ncomi ng fragment (the source) are combi ned wi th the col or val ues
of the correspondi ng currentl y stored pi xel (the destination) i n a two−stage process. Fi rst, you speci fy
how to compute source and desti nati on factors. These factors are RGBA quadrupl ets that are
mul ti pl i ed by each component of the R, G, B, and A val ues i n the source and desti nati on, respecti vel y.
Then, the correspondi ng components i n the two sets of RGBA quadrupl ets are added. To show thi s
mathemati cal l y, l et the source and desti nati on bl endi ng factors be (S
r
, S
g
, S
b
, S
a
) and (D
r
, D
g
, D
b
, D
a
),
respecti vel y, and the RGBA val ues of the source and desti nati on be i ndi cated wi th a subscri pt of s or d.
Then, the fi nal , bl ended RGBA val ues are gi ven by
137
(R
s
S
r
+R
d
D
r
, G
s
S
g
+G
d
D
g
, B
s
S
b
+B
d
D
b
, A
s
S
a
+A
d
D
a
)
Each component of thi s quadrupl et i s eventual l y cl amped to [0,1].
Now l et’s l ook at how the source and desti nati on bl endi ng factors are generated. You use glBlendFunc()
to suppl y two constants: one that speci fi es how the source factor shoul d be computed, and one that
i ndi cates how the desti nati on factor shoul d be computed. Al so, to have bl endi ng take effect, you need to
enabl e i t:
glEnable(GL_BLEND);
Use glDisable() wi th GL_BLEND to di sabl e bl endi ng. Al so, note that usi ng the constants GL_ONE
(source) and GL_ZERO (desti nati on) gi ves the same resul ts as when bl endi ng i s di sabl ed; these val ues
are the defaul t.
voi d glBlendFunc(GLenum sfactor, GLenum dfactor)
Control s how col or val ues i n the fragment bei ng processed (the source) are combi ned wi th those al ready
stored i n the framebuffer (the desti nati on). The argument sfactor i ndi cates how to compute a source
bl endi ng factor; dfactor i ndi cates how to compute a desti nati on bl endi ng factor. The possi bl e val ues for
these arguments are expl ai ned i n Table 7−1 . The bl end factors are assumed to l i e i n the range [0,1];
after the col or val ues i n the source and desti nati on are combi ned, they’re cl amped to the range [0,1].
Note: I n Table 7−1 , the RGBA val ues of the source and desti nati on are i ndi cated wi th the subscri pts
s and d, respecti vel y. Al so, di vi si on of an RGBA quadrupl et by a scal ar means di vi di ng each
component by that val ue. Si mi l arl y, subtracti on of quadrupl ets means subtracti ng them
componentwi se. The Rel evant Factor col umn i ndi cates whether the correspondi ng constant can
be used to speci fy the source or desti nati on bl end factor.
Constant Relevant Factor Computed Blend Factor
GL_ZERO source or destination (0, 0, 0, 0)
GL_ONE source or destination (1, 1, 1, 1)
GL_DST_COLOR source (R
d
, G
d
, B
d
, A
d
)
GL_SRC_COLOR destination (R
s
, G
s
, B
s
, A
s
)
GL_ONE_MINUS_DST_COLOR source (1, 1, 1, 1)−(R
d
, G
d
, B
d
, A
d
)
GL_ONE_MINUS_SRC_COLOR destination (1, 1, 1, 1)−(R
s
, G
s
, B
s
, A
s
)
GL_SRC_ALPHA source or destination (A
s
, A
s
, A
s
, A
s
)
GL_ONE_MINUS_SRC_ALPH A source or destination (1, 1, 1, 1)−(A
s
, A
s
, A
s
, A
s
)
GL_DST_ALPHA source or destination (A
d
, A
d
, A
d
, A
d
)
GL_ONE_MINUS_DST_ALPH A source or destination (1, 1, 1, 1)−(A
d
, A
d
, A
d
, A
d
)
GL_SRC_ALPHA_SATURATE source (f, f, f, 1); f=min(As, 1−Ad)
Table 7−1 Source and Desti nati on Bl endi ng Factors
Sample Uses of Blending
Not al l of the combi nati ons of source and desti nati on factors make sense. The majori ty of appl i cati ons
use a smal l number of combi nati ons. The fol l owi ng paragraphs descri be typi cal uses for parti cul ar
combi nati ons of the source and desti nati on factors. Some of these exampl es use onl y the i ncomi ng al pha
val ue, so they work even when al pha val ues aren’t stored i n the framebuffer. Al so, note that often
there’s more than one way to achi eve some of these effects.
1. One way to draw a pi cture composed hal f of one i mage and hal f of another, equal l y bl ended, i s to set
the source factor to GL_ONE, draw the fi rst i mage, then set the source and desti nati on factors to
GL_SRC_ALPHA, and draw the second i mage wi th al pha equal to 0.5. I f the pi cture i s supposed to
be bl ended wi th 0.75 of the fi rst i mage and 0.25 of the second, draw the fi rst i mage as before, and
draw the second wi th an al pha of 0.25, but wi th GL_SRC_ALPHA (source) and
GL_ONE_MI NUS_SRC_ALPHA (desti nati on). Thi s pai r of factors probabl y represents the most
138
commonl y used bl endi ng operati on.
2. To bl end three di fferent i mages equal l y, set the desti nati on factor to GL_ONE and the source factor
to GL_SRC_ALPHA. Draw each of the i mages wi th an al pha equal to 0.3333333. Wi th thi s
techni que, each i mage i s onl y one−thi rd of i ts ori gi nal bri ghtness, whi ch i s noti ceabl e where the
i mages don’t overl ap.
3. Suppose you’re wri ti ng a pai nt program, and you want to have a brush that gradual l y adds col or so
that each brush stroke bl ends i n a l i ttl e more col or wi th whatever i s currentl y i n the i mage (say 10
percent col or wi th 90 percent i mage on each pass). To do thi s, draw the i mage of the brush wi th
al pha of 10 percent and use GL_SRC_ALPHA (source) and GL_ONE_MI NUS_SRC_ALPHA
(desti nati on). (Note that you can vary the al phas across the brush to make the brush add more of
i ts col or i n the mi ddl e and l ess on the edges, for an anti al i ased brush shape. See "Antialiasing.")
Si mi l arl y, erasers can be i mpl emented by setti ng the eraser col or to the background col or.
4. The bl endi ng functi ons that use the source or desti nati on col orsGL_DST_COLOR or
GL_ONE_MI NUS_DST_COLOR for the source factor and GL_SRC_COLOR or
GL_ONE_MI NUS_SRC_COLOR for the desti nati on factoreffecti vel y al l ow you to modul ate each
col or component i ndi vi dual l y. Thi s operati on i s equi val ent to appl yi ng a si mpl e fi l terfor exampl e,
mul ti pl yi ng the red component by 80 percent, the green component by 40 percent, and the bl ue
component by 72 percent woul d si mul ate vi ewi ng the scene through a photographi c fi l ter that
bl ocks 20 percent of red l i ght, 60 percent of green, and 28 percent of bl ue.
5. Suppose you want to draw a pi cture composed of three transl ucent surfaces, some obscuri ng others
and al l over a sol i d background. Assume the farthest surface transmi ts 80 percent of the col or
behi nd i t, the next transmi ts 40 percent, and the cl osest transmi ts 90 percent. To compose thi s
pi cture, draw the background fi rst wi th the defaul t source and desti nati on factors, and then change
the bl endi ng factors to GL_SRC_ALPHA (source) and GL_ONE_MI NUS_SRC_ALPHA
(desti nati on). Next, draw the farthest surface wi th an al pha of 0.2, then the mi ddl e surface wi th an
al pha of 0.6, and fi nal l y the cl osest surface wi th an al pha of 0.1.
Advanced
6. I f your system has al pha pl anes, you can render objects one at a ti me (i ncl udi ng thei r al pha val ues),
read them back, and then perform i nteresti ng matti ng or composi ti ng operati ons wi th the ful l y
rendered objects. See "Composi ti ng 3D Rendered I mages" by Tom Duff, SI GGRAPH 1985
Proceedi ngs, p. 41−44, for exampl es of thi s techni que. Note that objects used for pi cture
composi ti on can come from any sourcethey can be rendered usi ng OpenGL commands, rendered
usi ng techni ques such as ray−traci ng or radi osi ty that are i mpl emented i n another graphi cs
l i brary, or obtai ned by scanni ng i n exi sti ng i mages.
Advanced
7. You can create the effect of a nonrectangul ar raster i mage by assi gni ng di fferent al pha val ues to
i ndi vi dual fragments i n the i mage. Assi gn an al pha of 0 to each "i nvi si bl e" fragment, and an al pha
of 1.0 to each opaque fragment. For exampl e, you can draw a pol ygon i n the shape of a tree and
appl y a texture map of fol i age; the vi ewer can see through parts of the rectangul ar texture that
aren’t part of the tree i f you’ve assi gned them al pha val ues of 0. Thi s method, someti mes cal l ed
billboarding, i s much faster than creati ng the tree out of three−di mensi onal pol ygons. An exampl e
of thi s techni que i s shown i n Figure 7−1 : The tree i s a si ngl e rectangul ar pol ygon that can be
rotated about the center of the trunk, as shown by the outl i nes, so that i t’s al ways faci ng the
vi ewer. See "Modulating and Blending" for more i nformati on about bl endi ng textures.
139
Figure 7−1 Creati ng a Nonrectangul ar Raster I mage
A Blending Example
Example 7−1draws four overl appi ng col ored rectangl eseach wi th an al pha of 0.75so that the
l ower l eft and upper ri ght quadrants of the wi ndow are covered twi ce. I n these two quadrants, the
col ors are bl ended i n di fferent orders usi ng source and desti nati on bl endi ng factors of
GL_SRC_ALPHA and GL_ONE_MI NUS_SRC_ALPHA: I n the l ower l eft quadrant, cyan i s bl ended
wi th the ori gi nal yel l ow; i n the upper ri ght quadrant, yel l ow i s bl ended wi th the ori gi nal cyan. The
140
other quadrants are drawn wi th unbl ended col ors.
Example 7−1 A Bl endi ng Exampl e: al pha.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
void myinit(void)
{
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glShadeModel(GL_FLAT);
glClearColor(0.0, 0.0, 0.0, 0.0);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor4f(1.0, 1.0, 0.0, 0.75);
glRectf(0.0, 0.0, 0.5, 1.0);
glColor4f(0.0, 1.0, 1.0, 0.75);
glRectf(0.0, 0.0, 1.0, 0.5);
/* draw colored polygons in reverse order in upper right */
glColor4f (0.0, 1.0, 1.0, 0.75);
glRectf (0.5, 0.5, 1.0, 1.0);
glColor4f (1.0, 1.0, 0.0, 0.75);
glRectf (0.5, 0.5, 1.0, 1.0);
glFlush();
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
gluOrtho2D (0.0, 1.0, 0.0, 1.0*(GLfloat)h/(GLfloat)w);
else
gluOrtho2D (0.0, 1.0*(GLfloat)w/(GLfloat)h, 0.0, 1.0);
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
auxInitPosition (0, 0, 500, 500);
auxInitWindow (argv[0]);
myinit();
141
auxReshapeFunc (myReshape);
auxMainLoop(display);
}
As you probabl y expected, the order i n whi ch the rectangl es are drawn affects the resul ti ng col ors. I n
the l ower l eft quadrant, the cyan rectangl e becomes the source fragment that’s bl ended wi th the yel l ow
rectangl e, whi ch i s al ready i n the framebuffer and thus i s the desti nati on. I n the upper ri ght quadrant,
the yel l ow rectangl e i s the source and the cyan one the desti nati on. Because the al pha val ues are al l
0.75, the actual bl endi ng factors become 0.75 for the source and 1.0 − 0.75 = 0.25 for the desti nati on. I n
other words, the source rectangl e i s somewhat transl ucent, but i t has more effect on the fi nal col or than
the desti nati on rectangl e. As a resul t, the l ower l eft quadrant i s l i ght cyan, and the upper l eft one i s
l i ght yel l ow. I f you do the ari thmeti c, you’l l fi nd that the l ower l eft RGB col or i s (0.25, 1.0, 0.75) and the
upper ri ght col or i s (0.75, 1.0, 0.25).
Three−Dimensional Blending with the Depth Buffer
As you saw i n the previ ous exampl e, the order i n whi ch pol ygons are drawn greatl y affects the bl ended
resul t. When drawi ng three−di mensi onal transl ucent objects, you can get di fferent appearances
dependi ng on whether you draw the pol ygons from back to front or from front to back. You al so need to
consi der the effect of the depth buffer when determi ni ng the correct order. The depth buffer (someti mes
cal l ed the z−buffer) i s usual l y used for hi dden−surface el i mi nati on. (See Chapter 10 for a detai l ed
di scussi on of the depth buffer.) I t keeps track of the di stance between the vi ewpoi nt and the porti on of
the object occupyi ng a gi ven pi xel i n a wi ndow on the screen; when another candi date col or arri ves for
that pi xel , i t’s drawn onl y i f i ts object i s cl oser to the vi ewpoi nt, i n whi ch case i ts depth val ue i s stored
i n the depth buffer. Wi th thi s method, obscured (or hi dden) porti ons of surfaces aren’t necessari l y
drawn and therefore aren’t used for bl endi ng.
Typi cal l y, you want to render both opaque and transl ucent objects i n the same scene, and you want to
use the depth buffer to perform hi dden−surface removal for objects that l i e behi nd the opaque objects.
I f an opaque object hi des ei ther a transl ucent object or another opaque object, you want the depth
buffer to el i mi nate the more di stant object. I f the transl ucent object i s cl oser, however, you want to
bl end i t wi th the opaque object. You can general l y fi gure out the correct order to draw the pol ygons i f
everythi ng i n the scene i s stati onary, but the probl em can easi l y become too hard i f ei ther the vi ewpoi nt
or the object i s movi ng.
The sol uti on i s to enabl e depth−bufferi ng but make the depth buffer read−onl y whi l e drawi ng the
transl ucent objects. Fi rst you draw al l the opaque objects, wi th the depth buffer i n normal operati on.
Then, you preserve these depth val ues by maki ng the depth buffer read−onl y. When the transl ucent
objects are drawn, thei r depth val ues are sti l l compared to the val ues establ i shed by the opaque objects,
so they aren’t drawn i f they’re behi nd the opaque ones. I f they’re cl oser to the vi ewpoi nt, however, they
don’t el i mi nate the opaque objects, si nce the depth−buffer val ues can’t change. I nstead, they’re bl ended
wi th the opaque objects. To control whether the depth buffer i s wri tabl e, use glDepthMask(); i f you pass
GL_FALSE as the argument, the buffer becomes read−onl y, whereas GL_TRUE restores the normal ,
wri tabl e operati on.
Example 7−2demonstrates how to use thi s method to draw opaque and transl ucent
three−di mensi onal objects. I n the program, pressi ng the l eft mouse button cal l s toggleviewpoint(),
whi ch changes the vi ewpoi nt posi ti on, and thus the orderi ng of an opaque torus and a transl ucent
cyl i nder. Keep i n mi nd that thi s sol uti on i s exact onl y when no pi xel i n the framebuffer i s drawn more
than once by a transparent object. I f transparent objects overl ap, resul ti ng i n mul ti pl e bl ended
renderi ngs to i ndi vi dual pi xel s, thi s sol uti on i s onl y a useful approxi mati on to the correct (sorted)
resul t.
Example 7−2 Three−Di mensi onal Bl endi ng: al pha3D.c
#include <GL/gl.h>
#include <GL/glu.h>
142
#include <GL/glu.h>
#include "aux.h"
void myinit(void)
{
GLfloat mat_ambient[] = { 0.0, 0.0, 0.0, 0.15 };
GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 0.15 };
GLfloat mat_shininess[] = { 15.0 };
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
}
GLboolean eyePosition = GL_FALSE;
void toggleEye(AUX_EVENTREC *event)
{
if (eyePosition)
eyePosition = GL_FALSE;
else
eyePosition = GL_TRUE;
}
void display(void)
{
GLfloat position[] = { 0.0, 0.0, 1.0, 1.0 };
GLfloat mat_torus[] = { 0.75, 0.75, 0.0, 1.0 };
GLfloat mat_cylinder[] = { 0.0, 0.75, 0.75, 0.15 };
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLightfv(GL_LIGHT0, GL_POSITION, position);
glPushMatrix();
if (eyePosition)
gluLookAt(0.0, 0.0, 9.0, 0.0, 0.0, 0.0, 0.0,
1.0, 0.0);
else
gluLookAt(0.0, 0.0, −9.0, 0.0, 0.0, 0.0, 0.0,
1.0, 0.0);
glPushMatrix();
glTranslatef(0.0, 0.0, 1.0);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_torus);
auxSolidTorus(0.275, 0.85);
glPopMatrix();
glEnable(GL_BLEND);
glDepthMask(GL_FALSE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_cylinder);
glTranslatef(0.0, 0.0, −1.0);
143
glTranslatef(0.0, 0.0, −1.0);
auxSolidCylinder(1.0, 2.0);
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
glPopMatrix();
glFlush();
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(30.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc, char** argv)
{
auxInitDisplayMode(AUX_SINGLE | AUX_RGBA | AUX_DEPTH);
auxInitPosition(0, 0, 500, 500);
auxInitWindow(argv[0]);
auxMouseFunc(AUX_LEFTBUTTON, AUX_MOUSEDOWN, toggleEye);
myinit();
auxReshapeFunc(myReshape);
auxMainLoop(display);
}
Antialiasing
You mi ght have noti ced i n some of your OpenGL pi ctures that l i nes, especi al l y nearl y hori zontal or
nearl y verti cal ones, appear jagged. These jaggi es appear because the i deal l i ne i s approxi mated by a
seri es of pi xel s that must l i e on the pi xel gri d. The jaggedness i s cal l ed al i asi ng, and thi s secti on
descri bes anti al i asi ng techni ques to reduce i t. Figure 7−2 shows two i ntersecti ng l i nes, both al i ased
and anti al i ased. The pi ctures have been magni fi ed to show the effect
144
Figure 7−2 Al i ased and Anti al i ased Li nes
Figure 7−2 shows how a di agonal l i ne one pi xel wi de covers more of some pi xel squares than others. I n
fact, when performi ng anti al i asi ng, OpenGL cal cul ates a coverageval ue for each fragment based on the
fracti on of the pi xel square on the screen that i t woul d cover. The fi gure shows these coverage val ues
for the l i ne. I n RGBA mode, OpenGL mul ti pl i es the fragment’s al pha val ue by i ts coverage. You can
then use the resul ti ng al pha val ue to bl end the fragment wi th the correspondi ng pi xel al ready i n the
framebuffer. I n col or−i ndex mode, OpenGL sets the l east si gni fi cant 4 bi ts of the col or i ndex based on
the fragment’s coverage (0000 for no coverage and 1111 for compl ete coverage). I t’s up to you to l oad
your col or map and appl y i t appropri atel y to take advantage of thi s coverage i nformati on.
Figure 7−3 Determi ni ng Coverage Val ues
145
The detai l s of cal cul ati ng coverage val ues are compl ex, di ffi cul t to speci fy i n general , and i n fact may
vary sl i ghtl y dependi ng on your parti cul ar i mpl ementati on of OpenGL. You can use the glHint()
command to exerci se some control over the trade−off between i mage qual i ty and speed, but not al l
i mpl ementati ons wi l l take the hi nt.
voi d glHint(GLenum target, GLenum hint);
Control s certai n aspects of OpenGL behavi or. The target parameter i ndi cates whi ch behavi or i s to be
control l ed; i ts possi bl e val ues are shown i n Table 7−2 . The hint parameter can be GL_FASTEST to
i ndi cate that the most effi ci ent opti on shoul d be chosen, GL_NI CEST to i ndi cate the hi ghest−qual i ty
opti on, or GL_DONT_CARE to i ndi cate no preference. The i nterpretati on of hi nts i s
i mpl ementati on−dependent; an i mpl ementati on can i gnore them enti rel y.
For more i nformati on about the rel evant topi cs, see "Antialiasing" for the detai l s on sampl i ng and
"Fog" for detai l s on fog. The GL_PERSPECTI VE_CORRECTI ON_HI NT parameter refers to how col or
val ues and texture coordi nates are i nterpol ated across a pri mi ti ve: ei ther l i nearl y i n screen space (a
rel ati vel y si mpl e cal cul ati on) or i n a perspecti ve−correct manner (whi ch requi res more computati on).
Often, systems perform l i near col or i nterpol ati on because the resul ts, whi l e not techni cal l y correct, are
vi sual l y acceptabl e; textures, however, i n most cases requi re perspecti ve−correct i nterpol ati on to be
vi sual l y acceptabl e. Thus, an i mpl ementati on can choose to use thi s parameter to control the method
used for i nterpol ati on. Perspecti ve projecti on i s di scussed i n Chapter 3 , col or i s di scussed i n Chapter
5, and texture mappi ng i s di scussed i n Chapter 9 .
Parameter Meaning
GL_POINT_SMOOTH_HINT,
GL_LINE_SMOOTH_HINT,
GL_POLYGON_SMOOTH_HINT
Specify the desired sampling quality of points,
lines, or polygons during antialiasing operations
GL_FOG_HINT Specifies whether fog calculations are done per
pixel (GL_NICEST) or per vertex (GL_FASTEST)
GL_PERSPECTIVE_CORRECTION_HINT Specifies the desired quality of color and
texture−coordinate interpolation
Table 7−2 Val ues for Use wi th gl Hi nt() and Thei r Meani ng
Antialiasing Points or Lines
To anti al i as poi nts or l i nes, you need to turn on anti al i asi ng wi th glEnable(), passi ng i n
GL_POI NT_SMOOTH or GL_LI NE_SMOOTH, as appropri ate. You mi ght al so want to provi de a
qual i ty hi nt wi th glHint(). (Remember that you can set the si ze of a poi nt or the wi dth of a l i ne. You can
al so sti ppl e a l i ne. See Chapter 2 .) Next, fol l ow the procedures descri bed i n one of the fol l owi ng
secti ons, dependi ng on whether you’re i n RGBA or col or−i ndex mode.
In RGBA Mode
I n RGBA mode, you need to enabl e bl endi ng. The bl endi ng factors you most l i kel y want to use are
GL_SRC_ALPHA (source) and GL_ONE_MI NUS_SRC_ALPHA (desti nati on). Al ternati vel y, you can
use GL_ONE for the desti nati on factor to make l i nes a l i ttl e bri ghter where they i ntersect. Now you’re
ready to draw whatever poi nts or l i nes you want anti al i ased. The anti al i ased effect i s most noti ceabl e i f
you use a fai rl y hi gh al pha val ue. Remember that si nce you’re performi ng bl endi ng, you mi ght need to
consi der the renderi ng order as descri bed i n "Three−Dimensional Blending with the Depth
Buffer"; i n most cases, however, the orderi ng can be i gnored wi thout si gni fi cant adverse effects.
Example 7−3 i ni ti al i zes the necessary modes for anti al i asi ng and then draws a wi reframe
i cosahedron. Note that the depth buffer i sn’t enabl ed i n thi s exampl e.
Example 7−3 An Anti al i ased Wi reframe I cosahedron: anti .c
#include <GL/gl.h>
146
#include <GL/glu.h>
#include "aux.h"
void myinit(void)
{
GLfloat values[2];
glGetFloatv(GL_LINE_WIDTH_GRANULARITY, values);
printf("GL_LINE_WIDTH_GRANULARITY value is %3.1f\n",
values[0]);
glGetFloatv(GL_LINE_WIDTH_RANGE, values);
printf("GL_LINE_WIDTH_RANGE values are %3.1f %3.1f\n",
values[0], values[1]);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
glLineWidth(1.5);
glShadeModel(GL_FLAT);
glClearColor(0.0, 0.0, 0.0, 0.0);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor4f(1.0, 1.0, 1.0, 1.0);
auxWireIcosahedron(1.0);
glFlush();
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, (GLfloat) w/(GLfloat) h, 3.0, 5.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, −4.0);
}
int main(int argc, char** argv)
{
auxInitDisplayMode(AUX_SINGLE | AUX_RGBA | AUX_DEPTH);
auxInitPosition(0, 0, 400, 400);
auxInitWindow(argv[0]);
myinit();
auxReshapeFunc(myReshape);
147
auxMainLoop(display);
}
In Color−Index Mode
The tri cky part about anti al i asi ng i n col or−i ndex mode i s l oadi ng and usi ng the col or map. Si nce the
l ast 4 bi ts of the col or i ndex i ndi cate the coverage val ue, you need to l oad si xteen conti guous i ndi ces
wi th a col or ramp from the background col or to the object’s col or. (The ramp has to start wi th an i ndex
val ue that’s a mul ti pl e of 16.) Then, you cl ear the col or buffer to the fi rst of the si xteen col ors i n the
ramp and draw your poi nts or l i nes usi ng col ors i n the ramp. Example 7−4 demonstrates how to
construct the col or ramp to draw an anti al i ased wi reframe i cosahedron i n col or−i ndex mode. I n thi s
exampl e, the col or ramp starts at i ndex 32 and contai ns shades of gray.
Example 7−4 Anti al i asi ng i n Col or−I ndex Mode: anti i ndex.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
#define RAMPSIZE 16
#define RAMPSTART 32
void myinit(void)
{
int i;
for (i = 0; i < RAMPSIZE; i++) {
GLfloat shade;
shade = (GLfloat) i/(GLfloat) RAMPSIZE;
auxSetOneColor(RAMPSTART+(GLint)i, shade, shade, shade);
}
glEnable (GL_LINE_SMOOTH);
glHint (GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
glLineWidth (1.5);
glClearIndex ((GLfloat) RAMPSTART);
glShadeModel(GL_FLAT);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glIndexi(RAMPSTART);
auxWireIcosahedron(1.0);
glFlush();
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective (45.0, (GLfloat) w/(GLfloat) h, 3.0, 5.0);
148
glMatrixMode(GL_MODELVIEW);
glLoadIdentity ();
glTranslatef (0.0, 0.0, −4.0);
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_INDEX | AUX_DEPTH);
auxInitPosition (0, 0, 400, 400);
auxInitWindow (argv[0]);
myinit();
auxReshapeFunc (myReshape);
auxMainLoop(display);
}
Si nce the col or ramp goes from the background col or to the object’s col or, the anti al i ased object l ooks
correct onl y when i t’s drawn on top of the background. I f the anti al i ased object i s drawn on top of
another object, pl aces where the objects i ntersect wi l l have the wrong col ors, unl ess you’ve constructed
your col or ramps taki ng thi s i nto consi derati on. To get the best resul t, use the depth buffer to ensure
that the pi xel col ors correspond to the "nearest" objects. I n RGBA mode, however, the col ors of both
objects are bl ended, so the resul ts l ook more natural . Thus, you typi cal l y don’t use the depth buffer
when renderi ng a scene consi sti ng of anti al i ased poi nts and l i nes.
Advanced
The tri ck descri bed i n "Three−Dimensional Blending with the Depth Buffer" can al so be used to
mi x anti al i ased poi nts and l i nes wi th al i ased, depth−buffered pol ygons. To do thi s, draw the pol ygons
fi rst, then make the depth buffer read−onl y and draw the poi nts and l i nes. The poi nts and l i nes wi l l
i ntersect ni cel y wi th each other but wi l l be obscured by nearer pol ygons.
Try This
Try This
• Take a previ ous program, such as the robot arm or sol ar system program descri bed i n "Examples
of Composing Several Transformations" and draw wi reframe objects wi th anti al i asi ng. Try i t
wi th ei ther RGBA or col or−i ndex mode. Al so try di fferent l i ne wi dths or poi nt si zes to see thei r
effects.
Antialiasing Polygons
Anti al i asi ng the edges of fi l l ed pol ygons i s si mi l ar to anti al i asi ng poi nts and l i nes. When di fferent
pol ygons have overl appi ng edges, you need to bl end the col or val ues appropri atel y. You can ei ther use
the method descri bed i n thi s secti on, or you can use the accumul ati on buffer to perform anti al i asi ng for
your enti re scene. Usi ng the accumul ati on buffer, whi ch i s descri bed i n Chapter 10, i s easi er from
your poi nt of vi ew, but i t’s much more computati on−i ntensi ve and therefore sl ower. However, as you’l l
see, the method descri bed here i s rather cumbersome
Note: I f you draw your pol ygons as poi nts at the verti ces or as outl i nesthat i s, by passi ng
GL_POI NT or GL_LI NE to glPolygonMode()poi nt or l i ne anti al i asi ng i s appl i ed, i f enabl ed as
descri bed earl i er. The rest of thi s secti on addresses pol ygon anti al i asi ng when you’re usi ng
GL_FI LL as the pol ygon mode.
I n theory, you can anti al i as pol ygons i n ei ther RGBA or col or−i ndex mode. However, object
i ntersecti ons affect pol ygon anti al i asi ng more than they affect poi nt or l i ne anti al i asi ng, so renderi ng
149
i ntersecti ons affect pol ygon anti al i asi ng more than they affect poi nt or l i ne anti al i asi ng, so renderi ng
order and bl endi ng accuracy become more cri ti cal . I n fact, they’re so cri ti cal that i f you’re anti al i asi ng
more than one pol ygon, you need to order the pol ygons from front to back and then use glBlendFunc()
wi th GL_SRC_ALPHA_SATURATE for the source factor and GL_ONE for the desti nati on factor. Thus,
anti al i asi ng pol ygons i n col or−i ndex mode normal l y i sn’t practi cal .
To anti al i as pol ygons i n RGBA mode, you use the al pha val ue to represent coverage val ues of pol ygon
edges. You need to enabl e pol ygon anti al i asi ng by passi ng GL_POLYGON_SMOOTH to glEnable().
Thi s causes pi xel s on the edges of the pol ygon to be assi gned fracti onal al pha val ues based on thei r
coverage, as though they were l i nes bei ng anti al i ased. Al so, i f you desi re, you can suppl y a val ue for
GL_POLYGON_SMOOTH_HI NT.
Now you need to bl end overl appi ng edges appropri atel y. Fi rst, turn off the depth buffer so that you
have control over how overl appi ng pi xel s are drawn. Then set the bl endi ng factors to
GL_SRC_ALPHA_SATURATE (source) and GL_ONE (desti nati on). Wi th thi s speci al i zed bl endi ng
functi on, the fi nal col or i s the sum of the desti nati on col or and the scal ed source col or; the scal e factor i s
the smal l er of ei ther the i ncomi ng source al pha val ue or one mi nus the desti nati on al pha val ue. Thi s
means that for a pi xel wi th a l arge al pha val ue, successi ve i ncomi ng pi xel s have l i ttl e effect on the fi nal
col or because one mi nus the desti nati on al pha i s al most zero. Wi th thi s method, a pi xel on the edge of a
pol ygon mi ght be bl ended eventual l y wi th the col ors from another pol ygon that’s drawn l ater. Fi nal l y,
you need to sort al l the pol ygons i n your scene so that they’re ordered from front to back before drawi ng
them.
Example 7−5shows how to anti al i as fi l l ed pol ygons; cl i cki ng the l eft mouse button toggl es the
anti al i asi ng on and off. Note that backward−faci ng pol ygons are cul l ed and that the al pha val ues i n the
col or buffer are cl eared to zero before any drawi ng. (Your col or buffer must store al pha val ues for thi s
techni que to work correctl y.)
Example 7−5 Anti al i asi ng Fi l l ed Pol ygons: anti pol y.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
GLboolean polySmooth;
void myinit(void)
{
GLfloat mat_ambient[] = { 0.0, 0.0, 0.0, 1.00 };
GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.00 };
GLfloat mat_shininess[] = { 15.0 };
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
glEnable (GL_LIGHTING);
glEnable (GL_LIGHT0);
glEnable (GL_BLEND);
glCullFace (GL_BACK);
glEnable (GL_CULL_FACE);
glEnable (GL_POLYGON_SMOOTH);
polySmooth = GL_TRUE;
glClearColor (0.0, 0.0, 0.0, 0.0);
}
150
void toggleSmooth (AUX_EVENTREC *event)
{
if (polySmooth) {
polySmooth = GL_FALSE;
glDisable (GL_BLEND);
glDisable (GL_POLYGON_SMOOTH);
glEnable (GL_DEPTH_TEST);
}
else {
polySmooth = GL_TRUE;
glEnable (GL_BLEND);
glEnable (GL_POLYGON_SMOOTH);
glDisable (GL_DEPTH_TEST);
}
}
void display(void)
{
GLfloat position[] = { 0.0, 0.0, 1.0, 0.0 };
GLfloat mat_cube1[] = { 0.75, 0.75, 0.0, 1.0 };
GLfloat mat_cube2[] = { 0.0, 0.75, 0.75, 1.0 };
if (polySmooth)
glClear (GL_COLOR_BUFFER_BIT);
else
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix ();
glTranslatef (0.0, 0.0, −8.0);
glLightfv (GL_LIGHT0, GL_POSITION, position);
glBlendFunc (GL_SRC_ALPHA_SATURATE, GL_ONE);
glPushMatrix ();
glRotatef (30.0, 1.0, 0.0, 0.0);
glRotatef (60.0, 0.0, 1.0, 0.0);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_cube1);
auxSolidCube (1.0, 1.0, 1.0);
glPopMatrix ();
glTranslatef (0.0, 0.0, −2.0);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_cube2);
glRotatef (30.0, 0.0, 1.0, 0.0);
glRotatef (60.0, 1.0, 0.0, 0.0);
auxSolidCube (1.0);
glPopMatrix ();
glFlush ();
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
151
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(30.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA | AUX_DEPTH);
auxInitPosition (0, 0, 200, 200);
auxInitWindow (argv[0]);
auxMouseFunc (AUX_LEFTBUTTON, AUX_MOUSEDOWN, toggleSmooth);
myinit();
auxReshapeFunc (myReshape);
auxMainLoop(display);
}
Fog
Computer i mages someti mes seem unreal i sti cal l y sharp and wel l −defi ned. Anti al i asi ng makes an
object appear more real i sti c by smoothi ng i ts edges. Addi ti onal l y, you can make an enti re i mage appear
more natural by addi ng fog, whi ch makes objects fade i nto the di stance. Fog i s a general term that
descri bes si mi l ar forms of atmospheri c effects; i t can be used to si mul ate haze, mi st, smoke, or
pol l uti on. Fog i s essenti al i n vi sual −si mul ati on appl i cati ons, where l i mi ted vi si bi l i ty needs to be
approxi mated. I t’s often i ncorporated i nto fl i ght−si mul ator di spl ays.
When fog i s enabl ed, objects that are farther from the vi ewpoi nt begi n to fade i nto the fog col or. You
can control the densi ty of the fog, whi ch determi nes the rate at whi ch objects fade as the di stance
i ncreases, as wel l as the fog’s col or. Fog i s avai l abl e i n both RGBA and col or−i ndex modes, al though the
cal cul ati ons are sl i ghtl y di fferent i n the two modes. Si nce fog i s appl i ed after matri x transformati ons,
l i ghti ng, and texturi ng are performed, i t affects transformed, l i t, and textured objects. Note that wi th
l arge si mul ati on programs, fog can i mprove performance, si nce you can choose not to draw objects that
are too fogged to be vi si bl e.
Using Fog
Usi ng fog i s easy. You enabl e i t by passi ng GL_FOG to glEnable(), and you choose the col or and the
equati on that control s the densi ty wi th glFog*(). I f you want, you can suppl y a val ue for
GL_FOG_HI NT wi th glHint(), as descri bed on Table 7−2 . Example 7−6 draws fi ve red teapots, each
at a di fferent di stance from the vi ewpoi nt. Pressi ng the l eft mouse button sel ects among the three
di fferent fog equati ons, whi ch are descri bed i n the next secti on.
Example 7−6 Fi ve Fogged Teapots i n RGBA Mode: fog.c
#include <GL/gl.h>
#include <GL/glu.h>
#include <math.h>
#include "aux.h"
GLint fogMode;
void cycleFog (AUX_EVENTREC *event)
{
152
if (fogMode == GL_EXP) {
fogMode = GL_EXP2;
printf ("Fog mode is GL_EXP2\n");
}
else if (fogMode == GL_EXP2) {
fogMode = GL_LINEAR;
printf ("Fog mode is GL_LINEAR\n");
glFogf (GL_FOG_START, 1.0);
glFogf (GL_FOG_END, 5.0);
}
else if (fogMode == GL_LINEAR) {
fogMode = GL_EXP;
printf ("Fog mode is GL_EXP\n");
}
glFogi (GL_FOG_MODE, fogMode);
}
void myinit(void)
{
GLfloat position[] = { 0.0, 3.0, 3.0, 0.0 };
GLfloat local_view[] = { 0.0 };
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glLightfv(GL_LIGHT0, GL_POSITION, position);
glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, local_view);
glFrontFace (GL_CW);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_AUTO_NORMAL);
glEnable(GL_NORMALIZE);
glEnable(GL_FOG);
{
GLfloat density;
GLfloat fogColor[4] = {0.5, 0.5, 0.5, 1.0};
fogMode = GL_EXP;
glFogi (GL_FOG_MODE, fogMode);
glFogfv (GL_FOG_COLOR, fogColor);
glFogf (GL_FOG_DENSITY, 0.35);
glHint (GL_FOG_HINT, GL_DONT_CARE);
glClearColor(0.5, 0.5, 0.5, 1.0);
}
}
void renderRedTeapot (GLfloat x, GLfloat y, GLfloat z)
{
float mat[3];
glPushMatrix();
glTranslatef (x, y, z);
mat[0] = 0.1745; mat[1] = 0.01175; mat[2] = 0.01175;
glMaterialfv (GL_FRONT, GL_AMBIENT, mat);
mat[0] = 0.61424; mat[1] = 0.04136; mat[2] = 0.04136;
153
glMaterialfv (GL_FRONT, GL_DIFFUSE, mat);
mat[0] = 0.727811; mat[1] = 0.626959; mat[2] = 0.626959;
glMaterialfv (GL_FRONT, GL_SPECULAR, mat);
glMaterialf (GL_FRONT, GL_SHININESS, 0.6*128.0);
auxSolidTeapot(1.0);
glPopMatrix();
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
renderRedTeapot (−4.0, −0.5, −1.0);
renderRedTeapot (−2.0, −0.5, −2.0);
renderRedTeapot (0.0, −0.5, −3.0);
renderRedTeapot (2.0, −0.5, −4.0);
renderRedTeapot (4.0, −0.5, −5.0);
glFlush();
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= (h*3))
glOrtho (−6.0, 6.0, −2.0*((GLfloat) h*3)/(GLfloat) w,
2.0*((GLfloat) h*3)/(GLfloat) w, 0.0, 10.0);
else
glOrtho (−6.0*(GLfloat) w/((GLfloat) h*3),
6.0*(GLfloat) w/((GLfloat) h*3), −2.0, 2.0, 0.0, 10.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity ();
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA | AUX_DEPTH);
auxInitPosition (0, 0, 450, 150);
auxInitWindow (argv[0]);
auxMouseFunc (AUX_LEFTBUTTON, AUX_MOUSEDOWN, cycleFog);
myinit();
auxReshapeFunc (myReshape);
auxMainLoop(display);
}
Fog Equations
Fog bl ends a fog col or wi th an i ncomi ng fragment’s col or usi ng a fog bl endi ng factor. Thi s factor, f, i s
computed wi th one of these three equati ons and then cl amped to the range [0,1].
154
where z i s the eye−coordi nate di stance between the vi ewpoi nt and the fragment center. The val ues for
density, start, and end are al l speci fi ed wi th glFog*(). The f factor i s used di fferentl y, dependi ng on
whether you’re i n RGBA mode or col or−i ndex mode, as expl ai ned i n the next subsecti ons.
voi d glFog{i f}{v}(GLenum pname, TYPE param);
Sets the parameters and functi on for cal cul ati ng fog. I f pnamei s GL_FOG_MODE, then param i s ei ther
GL_EXP (the defaul t), GL_EXP2, or GL_LI NEAR to sel ect one of the three fog factors. I f pnamei s
GL_FOG_DENSI TY, GL_FOG_START, or GL_FOG_END, then param i s (or poi nts to, wi th the vector
versi on of the command) a val ue for density, start, or end i n the equati ons. (The defaul t val ues are 1, 0,
and 1, respecti vel y.) I n RGBA mode, pnamecan be GL_FOG_COLOR, i n whi ch case param poi nts to
four val ues that speci fy the fog’s RGBA col or val ues. The correspondi ng val ue for pnamei n col or−i ndex
mode i s GL_FOG_I NDEX, for whi ch param i s a si ngl e val ue speci fyi ng the fog’s col or i ndex.
Figure 7−4 pl ots the fog−densi ty equati ons for vari ous val ues of the parameters. You can use l i near fog
to achi eve a depth−cui ng effect, as shown i n Figure J −2.
Figure 7−4 Fog−Densi ty Equati ons
Fog in RGBA Mode
155
I n RGBA mode, the fog factor f i s used as fol l ows to cal cul ate the fi nal fogged col or:
C = f C
i
+ (1 − f ) C
f
where C
i
represents the i ncomi ng fragment’s RGBA val ues and C
f
the fog−col or val ues assi gned wi th
GL_FOG_COLOR.
Fog in Color−Index Mode
I n col or−i ndex mode, the fi nal fogged col or i ndex i s computed as fol l ows:
I = I
i
+ (1 − f ) I
f
where I
i
i s the i ncomi ng fragment’s col or i ndex and I
f
i s the fog’s col or i ndex as speci fi ed wi th
GL_FOG_I NDEX.
To use fog i n col or−i ndex mode, you have to l oad appropri ate val ues i n a col or ramp. The fi rst col or i n
the ramp i s the col or of the object wi thout fog, and the l ast col or i n the ramp i s the col or of the
compl etel y fogged object. You probabl y want to use glClearI ndex() to i ni ti al i ze the background col or
i ndex so that i t corresponds to the l ast col or i n the ramp; thi s way, total l y fogged objects bl end i nto the
background. Si mi l arl y, before objects are drawn, you shoul d cal l glI ndex*() and pass i n the i ndex of the
fi rst col or i n the ramp (the unfogged col or). Fi nal l y, to appl y fog to di fferent col ored objects i n the scene,
you need to create several col or ramps, and cal l glI ndex*() before each object i s drawn to set the current
col or i ndex to the start of each col or ramp. Example 7−7 i l l ustrates how to i ni ti al i ze appropri ate
condi ti ons and then appl y fog i n col or−i ndex mode.
Example 7−7 Usi ng Fog i n Col or−I ndex Mode: fogi ndex.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
#define NUMCOLORS 32
#define RAMPSTART 16
void myinit(void)
{
int i;
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
for (i = 0; i < NUMCOLORS; i++) {
GLfloat shade;
shade = (GLfloat) (NUMCOLORS−i)/(GLfloat) NUMCOLORS;
auxSetOneColor (16 + i, shade, shade, shade);
}
glEnable(GL_FOG);
glFogi (GL_FOG_MODE, GL_LINEAR);
glFogi (GL_FOG_INDEX, NUMCOLORS);
glFogf (GL_FOG_START, 0.0);
glFogf (GL_FOG_END, 4.0);
glHint (GL_FOG_HINT, GL_NICEST);
glClearIndex((GLfloat) (NUMCOLORS+RAMPSTART−1));
}
void display(void)
156
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix ();
glTranslatef (−1.0, −1.0, −1.0);
glRotatef (−90.0, 1.0, 0.0, 0.0);
glIndexi (RAMPSTART);
auxSolidCone(1.0, 2.0);
glPopMatrix ();
glPushMatrix ();
glTranslatef (0.0, −1.0, −2.25);
glRotatef (−90.0, 1.0, 0.0, 0.0);
glIndexi (RAMPSTART);
auxSolidCone(1.0, 2.0);
glPopMatrix ();
glPushMatrix ();
glTranslatef (1.0, −1.0, −3.5);
glRotatef (−90.0, 1.0, 0.0, 0.0);
glIndexi (RAMPSTART);
auxSolidCone(1.0, 2.0);
glPopMatrix ();
glFlush();
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho (−2.0, 2.0, −2.0*(GLfloat)h/(GLfloat)w,
2.0*(GLfloat)h/(GLfloat)w, 0.0, 10.0);
else
glOrtho (−2.0*(GLfloat)w/(GLfloat)h,
2.0*(GLfloat)w/(GLfloat)h, −2.0, 2.0, 0.0, 10.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity ();
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_INDEX | AUX_DEPTH);
auxInitPosition (0, 0, 200, 200);
auxInitWindow (argv[0]);
myinit();
auxReshapeFunc (myReshape);
auxMainLoop(display);
}
Chapter 8
Drawing Pixels, Bitmaps, Fonts, and Images
157
Chapter Objectives
After readi ng thi s chapter, you’l l be abl e to do the fol l owi ng:
• Posi ti on and draw bi tmapped data
• Read pi xel data (bi tmaps and i mages) from the framebuffer i nto processor memory and from
memory i nto the framebuffer
• Copy pi xel data from one buffer to another, or to another l ocati on i n the same buffer
• Magni fy or reduce an i mage as i t’s wri tten to the framebuffer
• Control pi xel −data formatti ng and perform other transformati ons as the data i s moved to and from
the framebuffer
So far, most of the di scussi on i n thi s gui de has concerned the renderi ng of geometri c datapoi nts,
l i nes, and pol ygons. Two other i mportant cl asses of data that can be rendered by OpenGL are the
fol l owi ng:
• Bi tmaps, typi cal l y used for characters i n fonts
• I mage data, whi ch mi ght have been scanned i n or cal cul ated
Both bi tmaps and i mage data take the form of rectangul ar arrays of pi xel s. One di fference between
them i s that a bi tmap consi sts of a si ngl e bi t of i nformati on about each pi xel , and i mage data typi cal l y
i ncl udes several pi eces of data per pi xel (the compl ete red, green, bl ue, and al pha col or components, for
exampl e). Al so, bi tmaps are l i ke masks i n that they’re used to overl ay another i mage, but i mage data
si mpl y overwri tes or i s bl ended wi th whatever data mi ght have exi sted previ ousl y.
Thi s chapter descri bes how to read pi xel data (bi tmaps and i mages) from the framebuffer i nto processor
memory (and vi ce versa), and how to copy pi xel data from one buffer to another, or wi thi n a si ngl e
buffer to another posi ti on. Thi s chapter contai ns the fol l owi ng major secti ons:
• "Bitmaps and Fonts"descri bes the commands for posi ti oni ng and drawi ng bi tmapped data. Such
data may descri be a font.
• "Images"presents the basi c i nformati on about readi ng and copyi ng pi xel data. I t al so expl ai ns how
to magni fy or reduce an i mage as i t’s wri tten to the framebuffer.
• "Storing, Transforming, and Mapping Pixels"covers al l the detai l s of how pi xel data i s stored
i n memory and how to transform i t as i t’s moved i nto or out of memory.
I n most cases, the necessary pi xel operati ons are si mpl e, so the fi rst two secti ons mi ght be al l you need
to read for your appl i cati on. However, pi xel mani pul ati on can be compl exthere are many ways to
store pi xel data i n memory, and you can appl y any of several transformati ons to pi xel s as they’re moved
to and from the framebuffer. These detai l s are the subject of the thi rd secti on of thi s chapter; most
l i kel y, you’l l want to read thi s secti on onl y when you actual l y need to make use of the i nformati on.
Bitmaps and Fonts
A bi tmap i s a rectangul ar array of 0s and 1s that serves as a drawi ng mask for a correspondi ng
rectangul ar porti on of the wi ndow. Suppose you’re drawi ng a bi tmap and that the current col or i s red.
Everywhere there’s a 1 i n the bi tmap, the correspondi ng pi xel i s repl aced by a red pi xel (or combi ned
wi th the red pi xel , dependi ng on whi ch per−fragment operati ons are i n effect; see "Testing and
Operating on Fragments"). I f there’s a 0 i n the bi tmap, the contents of the pi xel are unaffected. The
most common use for bi tmaps i s for drawi ng characters on the screen.
OpenGL provi des onl y the l owest l evel of support for drawi ng stri ngs of characters and mani pul ati ng
fonts. The commands glRasterPos*() and glBitmap() posi ti on and draw a si ngl e bi tmap on the screen. I n
addi ti on, through the di spl ay−l i st mechani sm, you can use a sequence of character codes to i ndex i nto a
correspondi ng seri es of bi tmaps representi ng those characters. See Chapter 4 for more i nformati on
about di spl ay l i sts. You’l l have to wri te your own routi nes to provi de any other support you need for
mani pul ati ng bi tmaps, fonts, and stri ngs of characters.
As an exampl e, consi der Example 8−1, whi ch draws the character F three ti mes on the screen.
Figure 8−1 shows the F as a bi tmap and i ts correspondi ng bi tmap data.
158
Figure 8−1 A Bi tmapped F and I ts Data
Example 8−1 Drawi ng a Bi tmapped Character: drawf.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
GLubyte rasters[24] = {
0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00,
0xc0, 0x00, 0xff, 0x00, 0xff, 0x00, 0xc0, 0x00,
0xc0, 0x00, 0xc0, 0x00, 0xff, 0xc0, 0xff, 0xc0};
void myinit(void)
{
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glClearColor(0.0, 0.0, 0.0, 0.0);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
glRasterPos2i (20.5, 20.5);
glBitmap(10, 12, 0.0, 0.0, 12.0, 0.0, rasters);
glBitmap(10, 12, 0.0, 0.0, 12.0, 0.0, rasters);
glBitmap(10, 12, 0.0, 0.0, 12.0, 0.0, rasters);
glFlush();
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, w, 0, h, −1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char** argv)
{
auxInitDisplayMode(AUX_SINGLE | AUX_RGBA);
auxInitPosition(0, 0, 500, 500);
auxInitWindow(argv[0]);
myinit();
auxReshapeFunc(myReshape);
auxMainLoop(display);
}
I n Figure 8−1 , note that the vi si bl e part of the F character i s at most 10 bi ts wi de. Bi tmap data i s
al ways stored i n chunks that are mul ti pl es of 8 bi ts, but the wi dth of the actual bi tmap doesn’t have to
be a mul ti pl e of 8. The bi ts maki ng up a bi tmap are drawn starti ng from the l ower l eft corner: Fi rst, the
159
bottom row i s drawn, then the next row above i t, and so on. As you can tel l from the code, the bi tmap i s
stored i n memory i n thi s orderthe array of rasters begi ns wi th 0xc0, 0x00, 0xc0, 0x00 for the bottom
two rows of the F and conti nues to 0xff, 0xc0, 0xff, 0xc0 for the top two rows.
The commands of i nterest i n thi s exampl e are glRasterPos2i() and glBitmap(); they’re di scussed i n
detai l i n the next secti on. For now, i gnore the cal l to glPixelStorei(); i t descri bes how the bi tmap data i s
stored i n computer memory. Thi s topi c i s di scussed i n "Controlling Pixel−Storage Modes."
The Current Raster Position
The current raster posi ti on i s the ori gi n where the next bi tmap (or i mage) i s to be drawn. I n the F
exampl e, the raster posi ti on was set usi ng glRasterPos*() to (20, 20), whi ch i s where the l ower l eft
corner of the F was drawn:
glRasterPos2i(20, 20);
voi d glRasterPos{234}{si fd}{v}(TYPE x, TYPE y, TYPE z, TYPE w);
Sets the current raster posi ti on. The x, y, z, and w arguments speci fy the coordi nates of the raster
posi ti on. I f glRasterPos2*() i s used, z i s i mpl i ci tl y set to zero and w i s i mpl i ci tl y set to one; si mi l arl y,
wi th glRasterPos3*(), w i s set to one.
The coordi nates of the raster posi ti on are transformed to screen coordi nates i n exactl y the same way as
coordi nates suppl i ed wi th a glVertex*() command (that i s, wi th the model vi ew and perspecti ve
matri ces). After transformati on, they ei ther defi ne a val i d spot i n the wi ndow on the screen, or they’re
cl i pped out because the transformed coordi nates l i e outsi de the vi ewport. I f the transformed poi nt i s
cl i pped out, the current raster posi ti on i s i nval i d.
To obtai n the current raster posi ti on, you can use the query command glGetFloatv() wi th
GL_CURRENT_RASTER_POSI TI ON as the fi rst argument. The second argument shoul d be a poi nter
to an al l ocated array that can hol d the (x, y, z, w) val ues as fl oati ng−poi nt numbers. Cal l
glGetBooleanv() wi th GL_CURRENT_RASTER_POSI TI ON_VALI D as the fi rst argument to determi ne
whether the current raster posi ti on i s val i d.
Drawing the Bitmap
Once you’ve set the desi red raster posi ti on, you probabl y want to use the glBitmap() command to draw
the data.
voi d glBitmap(GLsi zei width, GLsi zei height, GLfl oat x
bo
, GLfl oat y
bo
, GLfl oat x
bi
, GLfl oat y
bi
, const
GLubyte *bitmap);
Draws the bi tmap speci fi ed by bitmap, whi ch i s a poi nter to the bi tmap i mage. The ori gi n of the bi tmap
i s pl aced at the most recentl y defi ned current raster posi ti on. I f the current raster posi ti on i s i nval i d,
nothi ng i s drawn, and the raster posi ti on remai ns i nval i d. The width and height arguments i ndi cate the
wi dth and hei ght, i n pi xel s, of the bi tmap. The wi dth need not be a mul ti pl e of 8, al though the data i s
stored i n unsi gned characters of 8 bi ts each. (I n the F exampl e, i t woul dn’t matter i f there were garbage
bi ts i n the data beyond the tenth bi t; si nce glBitmap() was cal l ed wi th a wi dth of 10, onl y 10 bi ts of the
row are rendered.) Use x
bo
and y
bo
to defi ne the ori gi n of the bi tmap (posi ti ve val ues move the ori gi n up
and to the ri ght; negati ve val ues move i t down and to the l eft); x
bi
and y
bi
i ndi cate the x and y
i ncrements that are added to the raster posi ti on after the bi tmap i s rasteri zed (see Figure 8−2 ).
160
Figure 8−2 A Bi tmap and I ts Associ ated Parameters
Al l owi ng the ori gi n of the bi tmap to be pl aced arbi trari l y makes i t easy for characters to extend bel ow
the ori gi n (typi cal l y used for characters wi th descenders, such as g, j, and y), or to extend beyond the
l eft of the ori gi n (used for vari ous swash characters, whi ch have extended fl ouri shes, or for characters
i n fonts that l ean to the l eft).
After the bi tmap i s drawn, the current raster posi ti on i s advanced by x
bi
and y
bi
i n the x− and y
−di recti ons, respecti vel y. For standard Lati n fonts, y
bi
i s typi cal l y 0.0 and x
bi
i s posi ti ve (si nce
successi ve characters are drawn from l eft to ri ght). For Hebrew, where characters go from ri ght to l eft,
the x
bi
val ues woul d typi cal l y be negati ve. Fonts that draw successi ve characters verti cal l y i n col umns
woul d use zero for x
bi
and nonzero val ues for y
bi
. I n Figure 8−2 , each ti me the F i s drawn, the current
raster posi ti on advances by 12 pi xel s, al l owi ng a 2−pi xel space between successi ve characters.
Si nce x
bo
, y
bo
, x
bi
, and y
bi
are fl oati ng−poi nt val ues, characters need not be an i ntegral number of
pi xel s wi de. Actual characters are drawn on exact pi xel boundari es, but the current raster posi ti on i s
kept i n fl oati ng poi nt so that each character i s drawn as cl ose as possi bl e to where i t bel ongs. For
exampl e, i f the code i n the F exampl e was modi fi ed so that x
bi
i s 11.5 i nstead of 12, and i f more
characters were drawn, the space between l etters woul d al ternate between one and two pi xel s, gi vi ng
the best approxi mati on to the requested 1.5−pi xel space. Note that bi tmaps can’t be used for rotatabl e
fonts because the bi tmap i s al ways drawn al i gned to the x and y framebuffer axes.
Fonts and Display Lists
Di spl ay l i sts are di scussed i n general terms i n Chapter 4 . However, a few of the di spl ay−l i st
management commands have speci al rel evance for drawi ng stri ngs of characters. As you read thi s
secti on, keep i n mi nd that the i deas presented here appl y equal l y wel l to characters that are drawn
usi ng bi tmap data as wel l as those drawn usi ng geometri c pri mi ti ves (poi nts, l i nes, and pol ygons).
"Executing Multiple Display Lists" presents an exampl e of a geometri c font.
A font typi cal l y consi sts of a set of characters, where each character has an i denti fyi ng number (usual l y
the ASCI I code), and a drawi ng method. For a standard ASCI I character set, the capi tal l etter A i s
number 65, B i s 66, and so on. The stri ng "DAB" woul d be represented by the three i ndi ces 68, 65, 66.
I n the si mpl est approach, di spl ay−l i st number 65 woul d draw an A, number 66 woul d draw a B, and so
on. Then, to draw the stri ng 68, 65, 66, just execute the correspondi ng di spl ay l i sts.
You can use the command glCallLists() i n just thi s way.
void glCallLists(GLsizei n, GLenum type, const GLvoid *lists);
161
The fi rst argument, n, i ndi cates the number of characters to be drawn, typei s usual l y GL_BYTE, and
lists i s an array of character codes.
Si nce many appl i cati ons need to draw character stri ngs i n mul ti pl e fonts and si zes, thi s si mpl est
approach i sn’t conveni ent. I nstead, you’d l i ke to use 65 as A no matter what font i s currentl y acti ve.
You coul d force font 1 to encode A, B, and C as 1065, 1066, 1067, and font 2 as 2065, 2066, 2067, but
then any numbers l arger than 256 woul d no l onger fi t i n an 8−bi t byte. A better sol uti on i s to add an
offset to every entry i n the stri ng and to choose the di spl ay l i st. I n thi s case, font 1 has A, B, and C
represented by 1065, 1066, and 1067, and i n font 2, they mi ght be 2065, 2066, and 2067. Then to draw
characters i n font 1, set the offset to 1000 and draw di spl ay l i sts 65, 66, and 67. To draw that same
stri ng i n font 2, set the offset to 2000 and draw the same l i sts.
Wi th thi s approach, use the command glListBase() to set the offset. For the precedi ng exampl es, i t
shoul d be cal l ed wi th 1000 or 2000 as the (onl y) argument. Now what you need i s a conti guous l i st of
unused di spl ay−l i st numbers, whi ch you can obtai n from glGenLists().
GLuint glGenLists(GLsizei range);
Thi s functi on returns a bl ock of rangedi spl ay−l i st i denti fi ers. The returned l i sts are al l marked as
"used" even though they’re empty, so that subsequent cal l s to glGenLists() never return the same l i sts
(unl ess you’ve expl i ci tl y del eted them previ ousl y). Thus, i f you use 4 as the argument and i f
glGenLists() returns 81, you can use di spl ay−l i st i denti fi ers 81, 82, 83, and 84 for your characters. I f
glGenLists() can’t fi nd a bl ock of unused i denti fi ers of the requested l ength, i t returns 0. (Note that the
command glDeleteLists() makes i t easy to del ete al l the l i sts associ ated wi th a font i n a si ngl e
operati on.)
Most Ameri can and European fonts have a smal l number of characters (fewer than 256), so i t’s easy to
represent each character wi th a di fferent code that can be stored i n a si ngl e byte. Asi an fonts, among
others, may requi re much l arger character sets, so a byte−per−character encodi ng i s i mpossi bl e.
OpenGL al l ows stri ngs to be composed of one−, two−, three−, or four−byte characters through the type
parameter i n glCallLists(). Thi s parameter can have any of the fol l owi ng val ues:
GL_BYTE GL_UNSI GNED_BYTE
GL_SHORT GL_UNSI GNED_SHORT
GL_I NT GL_UNSI GNED_I NT
GL_FLOAT GL_2_BYTES
GL_3_BYTES GL_4_BYTES
See "Executing Multiple Display Lists" for more i nformati on about these val ues.
Defining and Using a Complete Font
The sampl e program i n thi s secti on defi nes a compl ete raster font usi ng the glBitmap() command and
the di spl ay−l i st mechani sm descri bed i n the previ ous secti on. A compl ete ASCI I font i s defi ned where
each character i s the same wi dth (al though thi s i s by no means necessary). The code i s si mi l ar to the F
exampl e, except that ni nety−fi ve di fferent bi tmaps are used (one for each of the pri ntabl e ASCI I
characters, i ncl udi ng the space character), and each i s a si ngl e command wi thi n a di spl ay l i st. Each
di spl ay−l i st i denti fi er i s equal to the ASCI I code for that character, and al l have the same offset added
to them. Example 8−2 produces the output shown i n Figure 8−3 .
162
Figure 8−3 A Compl ete Font Defi ni ti on
Example 8−2 Defi ni ng a Compl ete Font: font.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
GLubyte rasters[][13] = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},

{0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18},

{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36},

{0x00, 0x00, 0x00, 0x66, 0x66, 0xff, 0x66, 0x66, 0xff, 0x66, 0x66, 0x00, 0x00},

{0x00, 0x00, 0x18, 0x7e, 0xff, 0x1b, 0x1f, 0x7e, 0xf8, 0xd8, 0xff, 0x7e, 0x18},

{0x00, 0x00, 0x0e, 0x1b, 0xdb, 0x6e, 0x30, 0x18, 0x0c, 0x76, 0xdb, 0xd8, 0x70},

{0x00, 0x00, 0x7f, 0xc6, 0xcf, 0xd8, 0x70, 0x70, 0xd8, 0xcc, 0xcc, 0x6c, 0x38},

{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1c, 0x0c, 0x0e},

{0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c},

{0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30},

{0x00, 0x00, 0x00, 0x00, 0x99, 0x5a, 0x3c, 0xff, 0x3c, 0x5a, 0x99, 0x00, 0x00},

{0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00},

{0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},

{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00},

{0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},

163
{0x00, 0x60, 0x60, 0x30, 0x30, 0x18, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x03, 0x03},

{0x00, 0x00, 0x3c, 0x66, 0xc3, 0xe3, 0xf3, 0xdb, 0xcf, 0xc7, 0xc3, 0x66, 0x3c},

{0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x38, 0x18},

{0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0xe7, 0x7e},

{0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0x07, 0x03, 0x03, 0xe7, 0x7e},

{0x00, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xcc, 0x6c, 0x3c, 0x1c, 0x0c},

{0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xff},

{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e},

{0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x03, 0x03, 0xff},

{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e},

{0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x03, 0x7f, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e},

{0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00},

{0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x00},

{0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06},

{0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00},

{0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60},

{0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x0c, 0x06, 0x03, 0xc3, 0xc3, 0x7e},

{0x00, 0x00, 0x3f, 0x60, 0xcf, 0xdb, 0xd3, 0xdd, 0xc3, 0x7e, 0x00, 0x00, 0x00},

{0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18},

{0x00, 0x00, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe},

{0x00, 0x00, 0x7e, 0xe7, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e},

{0x00, 0x00, 0xfc, 0xce, 0xc7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc7, 0xce, 0xfc},

{0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xff},

{0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xff},

{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e},

{0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3},

{0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e},

164
{0x00, 0x00, 0x7c, 0xee, 0xc6, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06},

{0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xe0, 0xf0, 0xd8, 0xcc, 0xc6, 0xc3},

{0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0},

{0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xff, 0xff, 0xe7, 0xc3},

{0x00, 0x00, 0xc7, 0xc7, 0xcf, 0xcf, 0xdf, 0xdb, 0xfb, 0xf3, 0xf3, 0xe3, 0xe3},

{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xe7, 0x7e},

{0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe},

{0x00, 0x00, 0x3f, 0x6e, 0xdf, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c},

{0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe},

{0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0xe0, 0xc0, 0xc0, 0xe7, 0x7e},

{0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff},

{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3},

{0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3},

{0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3},

{0x00, 0x00, 0xc3, 0x66, 0x66, 0x3c, 0x3c, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3},

{0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3},

{0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x7e, 0x0c, 0x06, 0x03, 0x03, 0xff},

{0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c},

{0x00, 0x03, 0x03, 0x06, 0x06, 0x0c, 0x0c, 0x18, 0x18, 0x30, 0x30, 0x60, 0x60},

{0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c},

{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18},

{0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},

{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x30, 0x70},

{0x00, 0x00, 0x7f, 0xc3, 0xc3, 0x7f, 0x03, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00},

{0x00, 0x00, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0},

{0x00, 0x00, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00},

{0x00, 0x00, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x03, 0x03, 0x03, 0x03, 0x03},

165
{0x00, 0x00, 0x7f, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00},

{0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x33, 0x1e},

{0x7e, 0xc3, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00},

{0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0},

{0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00},

{0x38, 0x6c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x0c, 0x00},

{0x00, 0x00, 0xc6, 0xcc, 0xf8, 0xf0, 0xd8, 0xcc, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0},

{0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78},

{0x00, 0x00, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xfe, 0x00, 0x00, 0x00, 0x00},

{0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xfc, 0x00, 0x00, 0x00, 0x00},

{0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00},

{0xc0, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0x00, 0x00, 0x00, 0x00},

{0x03, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x00, 0x00, 0x00, 0x00},

{0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xfe, 0x00, 0x00, 0x00, 0x00},

{0x00, 0x00, 0xfe, 0x03, 0x03, 0x7e, 0xc0, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00},

{0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x00},

{0x00, 0x00, 0x7e, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00},

{0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00},

{0x00, 0x00, 0xc3, 0xe7, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00},

{0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00},

{0xc0, 0x60, 0x60, 0x30, 0x18, 0x3c, 0x66, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00},

{0x00, 0x00, 0xff, 0x60, 0x30, 0x18, 0x0c, 0x06, 0xff, 0x00, 0x00, 0x00, 0x00},

{0x00, 0x00, 0x0f, 0x18, 0x18, 0x18, 0x38, 0xf0, 0x38, 0x18, 0x18, 0x18, 0x0f},

{0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18},

{0x00, 0x00, 0xf0, 0x18, 0x18, 0x18, 0x1c, 0x0f, 0x1c, 0x18, 0x18, 0x18, 0xf0},

{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x8f, 0xf1, 0x60, 0x00, 0x00, 0x00}
};
GLuint fontOffset;
166
void makeRasterFont(void)
{
GLuint i;
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
fontOffset = glGenLists (128);
for (i = 32; i < 127; i++) {
glNewList(i+fontOffset, GL_COMPILE);
glBitmap(8, 13, 0.0, 2.0, 10.0, 0.0, rasters[i−32]);
glEndList();
}
}
void myinit(void)
{
glShadeModel (GL_FLAT);
makeRasterFont();
}
void printString(char *s)
{
glPushAttrib (GL_LIST_BIT);
glListBase(fontOffset);
glCallLists(strlen(s), GL_UNSIGNED_BYTE, (GLubyte *) s);
glPopAttrib ();
}
void display(void)
{
GLfloat white[3] = { 1.0, 1.0, 1.0 };
int i, j;
char teststring[33];
glClear(GL_COLOR_BUFFER_BIT);
glColor3fv(white);
for (i = 32; i < 127; i += 32) {
glRasterPos2i(20, 200 − 18*i/32);
for (j = 0; j < 32; j++)
teststring[j] = (char) (i+j);
teststring[32] = 0;
printString(teststring);
}
glRasterPos2i(20, 100);
printString("The quick brown fox jumps");
glRasterPos2i(20, 82);
printString("over a lazy dog.");
glFlush ();
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho (0.0, w, 0.0, h, −1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
167
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
auxInitPosition (0, 0, 500, 500);
auxInitWindow (argv[0]);
myinit();
auxReshapeFunc (myReshape);
auxMainLoop(display);
}
Images
An i mage i s si mi l ar to a bi tmap, but i nstead of contai ni ng onl y a si ngl e bi t for each pi xel i n a
rectangul ar regi on of the screen, an i mage can contai n much more i nformati on. For exampl e, an i mage
can contai n the compl ete (R, G, B, A) quadrupl e stored at each pi xel . I mages can come from several
sources, such as:
• A photograph that’s di gi ti zed wi th a scanner
• An i mage that was fi rst generated on the screen by a graphi cs program usi ng the graphi cs
hardware and then read back, pi xel by pi xel
• A software program that generated the i mage i n memory pi xel by pi xel
The i mages you normal l y thi nk of as pi ctures come from the col or buffers. However, you can read or
wri te rectangul ar regi ons of pi xel data from or to the depth buffer or the stenci l buffer. See Chapter 10
for an expl anati on of these other buffers.
I n addi ti on to si mpl y bei ng di spl ayed on the screen, i mages can be used for texture maps, i n whi ch case
they’re essenti al l y pasted onto pol ygons that are rendered on the screen i n the normal way. See
Chapter 9 for more i nformati on about thi s techni que.
Reading, Writing, and Copying Pixel Data
OpenGL provi des three basi c commands that mani pul ate i mage data:
• glReadPixels()Reads a rectangul ar array of pi xel s from the framebuffer and stores the data i n
processor memory.
• glDrawPixels()Wri tes a rectangul ar array of pi xel s i nto the framebuffer from data kept i n
processor memory.
• glCopyPixels()Copi es a rectangul ar array of pi xel s from one part of the framebuffer to another.
Thi s command behaves somethi ng l i ke a cal l to glReadPixels() fol l owed by a cal l to glDrawPixels(),
but the data i s never wri tten i nto processor memory.
The basi c i deas behi nd these commands are si mpl e, but compl exi ty ari ses because there are many
ki nds of framebuffer data, many ways to store pi xel i nformati on i n computer memory, and vari ous data
conversi ons that can be performed duri ng the readi ng, wri ti ng, and copyi ng operati ons. Al l these
possi bi l i ti es transl ate to many di fferent modes of operati on. I f al l your program does i s copy i mages on
the screen, or read them i nto memory temporari l y so that they can be copi ed out l ater, you can i gnore
most of these modes. However, i f you want your program to modi fy the data whi l e i t’s i n memoryfor
exampl e, i f you have an i mage stored i n one format but the wi ndow requi res a di fferent formator i f
you want to save i mage data to a fi l e for future restorati on i n another sessi on or on another ki nd of
machi ne wi th si gni fi cantl y di fferent graphi cal capabi l i ti es, you have to understand the vari ous modes.
The rest of thi s secti on descri bes the basi c commands i n detai l . "Storing, Transforming, and
Mapping Pixels" di scusses the detai l s of pi xel −storage modes, pi xel −transfer operati ons, and
168
pi xel −mappi ng operati ons.
voi d glReadPixels(GLi nt x, GLi nt y, GLsi zei width, GLsi zei height, GLenum format, GLenum type,
GLvoi d *pixels);
Reads pi xel data from the framebuffer rectangl e whose l ower l eft corner i s at (x, y) and whose
di mensi ons are width and height, and stores i t i n the array poi nted to by pixels. format i ndi cates the
ki nd of pi xel data el ements that are read (an i ndex val ue or an R, G, B, or A component val ue, as l i sted
i n Table 8−1 ), and typei ndi cates the data type of each el ement (see Table 8−2 ).
Name Kind of Pixel Data
GL_COLOR_INDEX A single color index
GL_RGB A red color component, followed by a green color component,
followed by a blue color component
GL_RGBA A red color component, followed by a green color component,
followed by a blue color component, followed by an alpha color
component
GL_RED A single red color component
GL_GREEN A single green color component
GL_BLUE A single blue color component
GL_ALPHA A single alpha color component
GL_LUMINANCE A single luminance component
GL_LUMINANCE_ALPHA A luminance component followed by an alpha color component
GL_STENCIL_INDEX A single stencil index
GL_DEPTH_COMPONENT A single depth component
Table 8−1 Pi xel Formats for Use wi th gl ReadPi xel s() or gl DrawPi xel s()
voi d glDrawPixels(GLsi zei width, GLsi zei height, GLenum format, GLenum type, const GLvoi d *pixels);
Draws a rectangl e of pi xel data wi th di mensi ons width and height. The pi xel rectangl e i s drawn wi th i ts
l ower l eft corner at the current raster posi ti on. The format and typeparameters have the same meani ng
as wi th glReadPixels(). The array poi nted to by pixels contai ns the pi xel data to be drawn. I f the current
raster posi ti on i s i nval i d, nothi ng i s drawn, and i t remai ns i nval i d.
Remember that, dependi ng on the format, anywhere from one to four el ements are read or wri tten. For
exampl e, i f the format i s GL_RGBA, and you’re readi ng i nto 32−bi t i ntegers (that i s, i f type= GL_I NT),
then every pi xel read requi res 16 bytes of storage (4 components × 4 bytes/compenents).
Name Data Type
GL_UNSIGNED_BYTE unsigned 8−bit integer
GL_BYTE signed 8−bit integer
GL_BITMAP single bits in unsigned 8−bit integers
GL_UNSIGNED_SHORT unsigned 16−bit integer
GL_SHORT signed 16−bit integer
GL_UNSIGNED_INT unsigned 32−bit integer
GL_INT 32−bit integer
GL_FLOAT single−precision floating point
Table 8−2 Data Types for gl ReadPi xel s() or gl DrawPi xel s()
Each el ement of the saved i mage i s stored i n memory as i ndi cated by Table 8−2 . I f the el ement
represents a conti nuous val ue, such as a red, green, bl ue, or l umi nance component, each val ue i s scal ed
to fi t i nto the number of bi ts avai l abl e. For exampl e, the red component i s a fl oati ng−poi nt val ue
between 0.0 and 1.0. I f i t needs to be packed i nto an unsi gned byte, onl y 8 bi ts of preci si on are kept,
even i f more bi ts are al l ocated to the red component i n the framebuffer. GL_UNSI GNED_SHORT and
GL_UNSI GNED_I NT gi ve 16 and 32 bi ts of preci si on, respecti vel y. The normal (si gned) versi ons of
GL_BYTE, GL_SHORT, and GL_I NT have 7, 15, and 31 bi ts of preci si on, si nce the negati ve val ues are
typi cal l y not used.
169
I f the el ement i s an i ndex (a col or i ndex or a stenci l i ndex, for exampl e), and the type i s not GL_FLOAT,
the val ue i s si mpl y masked agai nst the avai l abl e bi ts i n the type. The si gned versi onsGL_BYTE,
GL_SHORT, and GL_I NThave masks wi th one fewer bi t. For exampl e, i f a col or i ndex i s to be stored
i n a si gned 8−bi t i nteger, i t’s fi rst masked agai nst 0xff, a mask contai ni ng seven 1s. I f the type i s
GL_FLOAT, the i ndex i s si mpl y converted i nto a si ngl e−preci si on fl oati ng−poi nt number (for exampl e,
the i ndex 17 i s converted to the fl oat 17.0).
voi d glCopyPixels(GLi nt x, GLi nt y, GLsi zei width, GLsi zei height, GLenum type);
Copi es pi xel data from the framebuffer rectangl e whose l ower l eft corner i s at (x, y) and whose
di mensi ons are width and height. The data i s copi ed to a new posi ti on whose l ower l eft corner i s gi ven
by the current raster posi ti on. The typeparameter i s ei ther GL_COLOR, GL_STENCI L, or
GL_DEPTH. glCopyPixels() behaves much l i ke a glReadPixels() fol l owed by a glDrawPixels(), wi th the
fol l owi ng transl ati on for the typeto format parameter:
• I f typei s GL_DEPTH or GL_STENCI L, then GL_DEPTH_COMPONENT or GL_STENCI L_I NDEX
i s used, respecti vel y.
• I f GL_COLOR i s speci fi ed, GL_RGBA or GL_COLOR_I NDEX i s used, dependi ng on whether the
system i s i n RGBA or col or−i ndex mode.
glCopyPixels() appl i es al l the pi xel transformati ons, transfer functi ons, and so on duri ng what woul d be
the glReadPixels() acti vi ty. The resul ti ng data i s wri tten as i t woul d be by glDrawPixels(), but the
transformati ons aren’t appl i ed a second ti me. Note that there’s no need for a format or data parameter
for glCopyPixels(), si nce the data i s never copi ed i nto processor memory. For al l three functi ons, the
exact conversi ons of the data goi ng to or from the framebuffer depend on the modes i n effect at the
ti me. See the next secti on for detai l s.
Magnifying or Reducing an Image
Normal l y, each pi xel i n an i mage i s wri tten to a si ngl e pi xel on the screen. However, you can arbi trari l y
magni fy or reduce an i mage by usi ng glPixelZoom().
voi d glPixelZoom(GLfl oat zoom
x
, GLfl oat zoom
y
);
Sets the magni fi cati on or reducti on factors for pi xel −wri te operati ons, i n the x−and y−di mensi ons. By
defaul t, zoom
x
and zoom
y
are 1.0. I f they’re both 2.0, each i mage pi xel i s drawn to 4 screen pi xel s. Note
that fracti onal magni fi cati on or reducti on factors are al l owed, as are negati ve factors.
Advanced
Duri ng rasteri zati on, each i mage pi xel i s treated as a zoom
x
×zoom
y
quadri l ateral , and fragments are
generated for al l the pi xel s whose centers l i e wi thi n the quadri l ateral . More speci fi cal l y, l et (x
rp
, y
rp
) be
the current raster posi ti on. I f a parti cul ar group of el ements (i ndex or components) i s the nth i n a row
and bel ongs to the mth col umn, consi der the regi on i n wi ndow coordi nates bounded by the rectangl e
wi th corners at
(x
rp
+ zoom
x
n, y
rp
+ zoom
y
m) and (x
rp
+ zoom
x
(n+1), y
rp
+ zoom
y
(m+1))
Any fragments whose centers l i e i nsi de thi s rectangl e (or on i ts bottom or l eft boundari es) are produced
i n correspondence wi th thi s parti cul ar group of el ements.
Storing, Transforming, and Mapping Pixels
Thi s secti on di scusses the detai l s of the pi xel −storage and −transfer modes, i ncl udi ng how to set up an
arbi trary mappi ng to convert pi xel data as i t’s transferred. Remember that you need to use these modes
onl y i f you need to convert pi xel data from one format to another.
Overview of the Pixel Modes
170
An i mage stored i n memory has between one and four chunks of data, cal l ed elements, for each pi xel i n
a rectangul ar porti on of the screen. The data mi ght consi st of just the col or i ndex or the l umi nance
(l umi nance i s the possi bl y wei ghted sum of the red, green, and bl ue val ues), or i t mi ght consi st of the
red, green, bl ue, and al pha components for each pi xel . The possi bl e arrangements of pi xel data, or
formats, determi ne the number of el ements stored for each pi xel and thei r order.
Some el ements (such as a col or i ndex or a stenci l i ndex) are i ntegers, and others (such as the red, green,
bl ue, and al pha components, or the depth component) are fl oati ng−poi nt val ues, typi cal l y rangi ng
between 0.0 and 1.0. Fl oati ng−poi nt components are usual l y stored i n your bi tpl anes i n fi xed−poi nt
wi th l ower resol uti on than a ful l fl oati ng−poi nt number woul d requi re (typi cal l y 8 bi ts are used for col or
components, for exampl e). The exact number of bi ts used to represent the components depends on the
parti cul ar hardware bei ng used. Thus, i t’s often wasteful to store each component as a ful l 32−bi t
fl oati ng−poi nt number, especi al l y si nce i mages can easi l y contai n a mi l l i on pi xel s.
El ements can be stored i n memory as vari ous data types, rangi ng from 8−bi t bytes to 32−bi t i ntegers or
fl oati ng−poi nt numbers. OpenGL expl i ci tl y defi nes the conversi on of each component i n each format to
each of the possi bl e data types. Keep i n mi nd that you can l ose data i f you try to store a hi gh−resol uti on
component i n a type represented by a smal l number of bi ts.
I mage data i s typi cal l y stored i n processor memory i n rectangul ar two− or three−di mensi onal arrays.
Often, you want to di spl ay or store a subi mage that corresponds to a subrectangl e of the array. I n
addi ti on, you mi ght need to take i nto account that di fferent machi nes have di fferent byte−orderi ng
conventi ons. Fi nal l y, some machi nes have hardware that i s far more effi ci ent at movi ng data to and
from the framebuffer i f the data i s al i gned on two−byte, four−byte, or ei ght−byte boundari es i n
processor memory. For such machi nes, you probabl y want to control the byte al i gnment. Al l the i ssues
rai sed i n thi s paragraph are control l ed as pi xel −storage modes; you speci fy these modes usi ng the
command glPixelStore*(), whi ch you’ve seen used i n a coupl e of exampl e programs.
As i mage data i s transferred from memory i nto the framebuffer, or from the framebuffer i nto memory,
OpenGL can perform several operati ons on i t. For exampl e, the ranges of components can be al tered
normal l y, the red component i s between 0.0 and 1.0, but you mi ght prefer to keep i t i n some other
range, or perhaps the data you’re usi ng from a di fferent graphi cs system stores the red component i n a
di fferent range. You can even create maps to perform arbi trary conversi on of col or i ndi ces or col or
components duri ng pi xel transfer. Conversi ons such as these performed duri ng the transfer of pi xel s to
and from the framebuffer are cal l ed pi xel −transfer modes. Not too surpri si ngl y, they’re control l ed wi th
the glPixelTransfer*() and glPixelMap*() commands.
Other modes that can be control l ed i ncl ude the framebuffer from whi ch pi xel s are read, and any
magni fi cati on that’s to be performed on pi xel s as they are wri tten to the framebuffer.
Fi nal l y, be aware that al though the col or, depth, and stenci l buffers have many si mi l ari ti es, they don’t
behave i denti cal l y, and a few of the modes have speci al cases for speci al buffers. Al l the mode detai l s
are covered i n the secti ons that fol l ow, i ncl udi ng al l the speci al cases.
Controlling Pixel−Storage Modes
Al l the possi bl e pi xel −storage modes are control l ed wi th the glPixelStore*() command. Typi cal l y,
several successi ve cal l s are made wi th thi s command to set several parameter val ues.
voi d glPixelStore{i f}(GLenum pname, TYPEparam);
Sets the pi xel −storage modes, whi ch affect the operati on of glDrawPixels*(), glReadPixels*(), glBitmap()
, glPolygonStipple(), glTexI mage1D(), glTexI mage2D(), and glGetTexI mage(). The possi bl e parameter
names for pnameare shown i n Table 8−3 , al ong wi th thei r data type, i ni ti al val ue, and val i d range of
val ues. The GL_UNPACK* parameters control how data i s unpacked from memory by glDrawPixels*(),
glBitmap(), glPolygonStipple(), glTexI mage1D(), and glTexI mage2D(). The GL_PACK* parameters
control how data i s packed i nto memory by glReadPixels*() and glGetTexI mage().
171
Parameter Name Type Initial Value Valid Range
GL_UNPACK_SWAP_BYTES,
GL_PACK_SWAP_BYTES
GLboolean FALSE TRUE/FALSE
GL_UNPACK_LSB_FIRST,
GL_PACK_LSB_FIRST
GLboolean FALSE TRUE/FALSE
GL_UNPACK_ROW_LENGTH,
GL_PACK_ROW_LENGTH
GLint 0 any nonnegative
integer
GL_UNPACK_SKIP_ROWS,
GL_PACK_SKIP_ROWS
GLint 0 any nonnegative
integer
GL_UNPACK_SKIP_PIXELS,
GL_PACK_SKIP_PIXELS
GLint 0 any nonnegative
integer
GL_UNPACK_ALIGNMENT,
GL_PACK_ALIGNMENT
GLint 4 1, 2, 4, 8
Table 8−3 Parameters for Use wi th gl Pi xel Store()
Si nce the correspondi ng parameters for packi ng and unpacki ng have the same meani ngs, they’re
di scussed together i n the rest of thi s secti on and referred to wi thout the GL_PACK or GL_UNPACK
prefi x. For exampl e, *SWAP_BYTES refers to GL_PACK_SWAP_BYTES and
GL_UNPACK_SWAP_BYTES.
I f the *SWAP_BYTES parameter i s FALSE (the defaul t), the orderi ng of the bytes i n memory i s
whatever i s nati ve for the OpenGL cl i ent; otherwi se, the bytes are reversed. The byte reversal appl i es
to any si ze el ement.
Note: As l ong as your OpenGL appl i cati on doesn’t share i mages wi th other machi nes, you can i gnore
the i ssue of byte orderi ng. I f your appl i cati on must render an OpenGL i mage that was created
on a di fferent machi ne, and the "endi anness" of the two machi nes di ffers, byte orderi ng can be
swapped usi ng *SWAP_BYTES.
The *LSB_FI RST parameter appl i es when drawi ng or readi ng 1−bi t i mages or bi tmaps, for whi ch a
si ngl e bi t of data i s saved or restored for each pi xel . I f *LSB_FI RST i s FALSE (the defaul t), the bi ts are
taken from the bytes starti ng wi th the most si gni fi cant bi t; otherwi se, they’re taken i n the opposi te
order. For exampl e, i f *LSB_FI RST i s FALSE, and the byte i n questi on i s 0x31, the bi ts, i n order, are
{0, 0, 1, 1, 0, 0, 0, 1}. I f *LSB_FI RST i s TRUE, the order i s {1, 0, 0, 0, 1, 1, 0, 0}.
Someti mes you want to draw or read onl y a subrectangl e of the enti re rectangl e of i mage data that’s
stored i n memory. I f the rectangl e i n memory i s l arger than the subrectangl e that’s bei ng drawn or
read, you need to speci fy the actual l ength of the l arger rectangl e wi th *ROW_LENGTH. I f
*ROW_LENGTH i s zero (whi ch i t i s by defaul t), the row l ength i s understood to be the same as the
wi dth that’s speci fi ed wi th glReadPixels*(), glDrawPixels*(), or glCopyPixels(). You al so need to speci fy
the number of rows and pi xel s to ski p before starti ng to copy the data for the subrectangl e. These
numbers are set usi ng the parameters *SKI P_ROWS and *SKI P_PI XELS, as shown i n Figure 8−4 .
By defaul t, both parameters are 0, so you start at the l ower l eft corner.
172
Figure 8−4 The *SKI P_ROWS, *SKI P_PI XELS, and *ROW_LENGTH Parameters
Often, a parti cul ar machi ne’s hardware i s opti mi zed for movi ng pi xel data to and from memory i f the
data i s saved i n memory wi th a parti cul ar byte al i gnment. For exampl e, i n a machi ne wi th 32−bi t
words, hardware can often retri eve data much faster i f i t’s i ni ti al l y al i gned on a 32−bi t boundary,
whi ch typi cal l y has an address that i s a mul ti pl e of 4. Li kewi se, 64−bi t archi tectures mi ght work better
when the data i s al i gned to ei ght−byte boundari es. On some machi nes, however, byte al i gnment makes
no di fference.
As an exampl e, suppose your machi ne works better wi th pi xel data al i gned to a four−byte boundary.
I mages are most effi ci entl y saved by forci ng the data for each row of the i mage to begi n on a four−byte
boundary. I f the i mage i s 5 pi xel s wi de, and each pi xel consi sts of one byte each of red, green, and bl ue
i nformati on, a row requi res 5 × 3 = 15 bytes of data. Maxi mum di spl ay effi ci ency can be achi eved i f the
fi rst row, and each successi ve row, begi ns on a four−byte boundary, so there i s one byte of waste i n the
memory storage for each row. I f your data i s stored l i ke thi s, set the *ALI GNMENT parameter
appropri atel y (to 4, i n thi s case).
I f *ALI GNMENT i s set to 1, the next avai l abl e byte i s used. I f i t’s 2, at the end of each row, a byte i s
ski pped i f necessary, so that the fi rst byte of the next row has an address that’s a mul ti pl e of 2. I n the
case of bi tmaps (or one−bi t i mages) where a si ngl e bi t i s saved for each pi xel , the same byte al i gnment
works, al though you have to count i ndi vi dual bi ts. For exampl e, i f you’re savi ng a si ngl e bi t per pi xel ,
the row l ength i s 75, and the al i gnment i s 4, each row requi res 75/8, or 9 3/8 bytes. Si nce 12 i s the
smal l est mul ti pl e of 4 that i s bi gger than 9 3/8, twel ve bytes of memory are used for each row.
Pixel−Transfer Operations
You can perform vari ous operati ons on pi xel s as they’re transferred from and to the framebuffer. The
conti nuous components, i ncl udi ng the red, green, bl ue, al pha, and depth components, can have an
173
affi ne transformati on appl i ed. I n addi ti on, after transformati on, these componentsas wel l as the
col or−i ndex and stenci l val uescan be transformed by an arbi trary tabl e l ookup.
Some of the pi xel −transfer functi on characteri sti cs are set wi th glPixelTransfer*(). The other
characteri sti cs are speci fi ed wi th glPixelMap*(), whi ch i s descri bed i n the next secti on.
voi d glPixelTransfer{i f}(GLenum pname, TYPEparam);
Sets pi xel −transfer modes that affect the operati on of glDrawPixels*(), glReadPixels*(), glCopyPixels(),
glTexI mage1D(), glTexI mage2D(), and glGetTexI mage(). The parameter pnamemust be one of those
l i sted i n the fi rst col umn of Table 8−4 , and i ts val ue, param, must be i n the val i d range shown.
Parameter Name Type Initial Value Valid Range
GL_MAP_COLOR GLboolean FALSE TRUE/FALSE
GL_MAP_STENCIL GLboolean FALSE TRUE/FALSE
GL_INDEX_SHIFT GLint 0 (−∞, ∞)
GL_INDEX_OFFSET GLint 0 (−∞, ∞)
GL_RED_SCALE GLfloat 1.0 (−∞, ∞)
GL_GREEN_SCALE GLfloat 1.0 (−∞, ∞)
GL_BLUE_SCALE GLfloat 1.0 (−∞, ∞)
GL_ALPHA_SCALE GLfloat 1.0 (−∞, ∞)
GL_DEPTH_SCALE GLfloat 1.0 (−∞, ∞)
GL_RED_BIAS GLfloat 0 (−∞, ∞)
GL_GREEN_BIAS GLfloat 0 (−∞, ∞)
GL_BLUE_BIAS GLfloat 0 (−∞, ∞)
GL_ALPHA_BIAS GLfloat 0 (−∞, ∞)
GL_DEPTH_BIAS GLfloat 0 (−∞, ∞)
Table 8−4 Parameters for Use wi th gl Pi xel Transfer*()
I f the GL_MAP_COLOR or GL_MAP_STENCI L parameter i s TRUE, then mappi ng i s enabl ed. See the
next secti on to l earn how the mappi ng i s done and how to change the contents of the maps. Al l the
other parameters di rectl y affect the pi xel component val ues.
The pi xel conversi ons performed when goi ng from framebuffer to memory (readi ng) are si mi l ar but not
i denti cal to the conversi ons performed when goi ng i n the opposi te di recti on (drawi ng), as expl ai ned i n
the fol l owi ng secti ons.
The Pixel Rectangle−Drawing Process in Detail
Figure 8−5 and the fol l owi ng paragraphs descri be the operati on of drawi ng pi xel s i nto the framebuffer.
174
175
Figure 8−5 Drawi ng Pi xel s wi th gl DrawPi xel s*()
1. I f the pi xel s aren’t i ndi ces (col or or stenci l ), the fi rst step i s to convert the components to
fl oati ng−poi nt format i f necessary. See Table 5−1 for the detai l s of the conversi on.
2. I f the format i s GL_LUMI NANCE or GL_LUMI NANCE_ALPHA, the l umi nance el ement i s
converted i nto R, G, and B, by usi ng the l umi nance val ue for each of the R, G, and B components.
I n GL_LUMI NANCE_ALPHA format, the al pha val ue becomes the A val ue. I f A i s mi ssi ng, i t’s set
to 1.0.
3. Each component (R, G, B, A, or depth) i s mul ti pl i ed by the appropri ate scal e, and the appropri ate
bi as i s added. For exampl e, the R component i s mul ti pl i ed by the val ue correspondi ng to
GL_RED_SCALE, and added to the val ue correspondi ng to GL_RED_BI AS.
4. I f GL_MAP_COLOR i s true, each of the R, G, B, and A components i s cl amped to the range
[0.0,1.0], mul ti pl i ed by an i nteger one l ess than the tabl e si ze, truncated, and l ooked up i n the tabl e.
See "Pixel Mapping" for more detai l s.
5. Next, the R, G, B, and A components are cl amped to [0.0,1.0] i f they weren’t al ready, and they’re
converted to fi xed−poi nt wi th as many bi ts to the l eft of the bi nary poi nt as there are i n the
correspondi ng framebuffer component.
6. I f you’re worki ng wi th i ndex val ues (stenci l or col or i ndi ces), then the val ues are fi rst converted to
fi xed−poi nt (i f they were i ni ti al l y fl oati ng−poi nt numbers) wi th some unspeci fi ed bi ts to the ri ght of
the bi nary poi nt. I ndi ces that were i ni ti al l y fi xed−poi nt remai n so, and any bi ts to the ri ght of the
bi nary poi nt are set to zero.
7. The resul ti ng i ndex val ue i s then shi fted ri ght or l eft by the absol ute val ue of GL_I NDEX_SHI FT
bi ts; the val ue i s shi fted l eft i f GL_I NDEX_SHI FT > 0 and ri ght otherwi se. Fi nal l y,
GL_I NDEX_OFFSET i s added to the i ndex.
8. The next step wi th i ndi ces depends on whether you’re usi ng RGBA mode or i ndex mode. I n RGBA
mode, a col or i ndex i s converted to RGBA usi ng the col or components speci fi ed by
GL_PI XEL_MAP_I _TO_R, GL_PI XEL_MAP_I _TO_G, GL_PI XEL_MAP_I _TO_B, and
GL_PI XEL_MAP_I _TO_A (see the next secti on for detai l s). Otherwi se, i f GL_MAP_COLOR i s
TRUE, a col or i ndex i s l ooked up through the tabl e GL_PI XEL_MAP_I _TO_I . (I f GL_MAP_COLOR
i s FALSE, the i ndex i s unchanged.) I f the i mage i s made up of stenci l i ndi ces rather than col or
i ndi ces, and i f GL_MAP_STENCI L i s TRUE, the i ndex i s l ooked up i n the tabl e correspondi ng to
GL_PI XEL_MAP_S_TO_S. I f GL_MAP_STENCI L i s FALSE, the stenci l i ndex i s unchanged.
The Pixel Rectangle−Reading Process in Detail
Duri ng the pi xel readi ng process, many of the same conversi ons are done, as shown i n Figure 8−6 and
as descri bed i n the fol l owi ng paragraphs.
176
177
Figure 8−6 Readi ng Pi xel s wi th gl ReadPi xel s*()
I f the pi xel s to be read aren’t i ndi ces (col or or stenci l ), the components are mapped to [0.0,1.0]that i s,
i n exactl y the opposi te way that they are when wri tten. Next, the scal es and bi ases are appl i ed to each
component. I f GL_MAP_COLOR i s TRUE, they’re mapped and agai n cl amped to [0.0,1.0]. I f l umi nance
i s desi red i nstead of RGB, the R, G, and B components are added (L = R + G + B). Fi nal l y, the resul ts
are packed i nto memory accordi ng to the GL_PACK* modes set wi th glPixelStore*().
I f the pi xel s are i ndi ces (col or or stenci l ), they’re shi fted and offset, and mapped i f GL_MAP_COLOR i s
TRUE. I f the storage format i s ei ther GL_COLOR_I NDEX or GL_STENCI L_I NDEX, the pi xel i ndi ces
are masked to the number of bi ts of the storage type (1, 8, 16, or 32) and packed i nto memory as
descri bed previ ousl y. I f the storage format i s one of the component ki nd (such as l umi nance or RGB),
the pi xel s are al ways mapped by the i ndex−to−RGBA maps. Then, they’re treated as though they had
been RGBA pi xel s i n the fi rst pl ace (i ncl udi ng perhaps bei ng converted to l umi nance).
The scal i ng, bi as, shi ft, and offset val ues are the same as those used when drawi ng pi xel s, so i f you’re
doi ng both readi ng and drawi ng of pi xel s, be sure to reset these components to the appropri ate val ues
before doi ng a read or a draw. Si mi l arl y, the vari ous maps (see the next secti on) must al so be properl y
reset i f you i ntend to use maps for both readi ng and drawi ng.
Note: I t mi ght seem that l umi nance i s handl ed i ncorrectl y i n both the readi ng and drawi ng
operati ons. For exampl e, l umi nance i s not usual l y equal l y dependent on the R, G, and B
components as i t seems above. I f you wanted your l umi nance to be cal cul ated such that the R
component contri buted 30 percent, the G 59 percent, and the B 11 percent, you coul d set
GL_RED_SCALE to .30, GL_RED_BI AS to 0.0, and so on. Then the computed L i s then .30R +
.59G + .11B.
Pixel Mapping
As menti oned i n the previ ous secti on, al l the col or components, col or i ndi ces, and stenci l i ndi ces can be
modi fi ed by means of a tabl e l ookup before bei ng pl aced i n screen memory. The command for
control l i ng thi s mappi ng i s glPixelMap*().
voi d glPixelMap[ui us f}v(GLenum map, GLi nt mapsize, const TYPE *values);
Loads the pi xel map i ndi cated by map wi th mapsizeentri es, whose val ues are poi nted to by values.
Table 8−5 l i sts the map names and val ues; the defaul t si zes are al l 1 and the defaul t val ues are al l 0.
Each map’s si ze must be a power of 2.
Map Name Address Value
GL_PIXEL_MAP_I_TO_I color index color index
GL_PIXEL_MAP_S_TO_S stencil index stencil index
GL_PIXEL_MAP_I_TO_R color index R
GL_PIXEL_MAP_I_TO_G color index G
GL_PIXEL_MAP_I_TO_B color index B
GL_PIXEL_MAP_I_TO_A color index A
GL_PIXEL_MAP_R_TO_R R R
GL_PIXEL_MAP_G_TO_G G G
GL_PIXEL_MAP_B_TO_B B B
GL_PIXEL_MAP_A_TO_A A A
Table 8−5 Val i d Parameter Names and Val ues for Use wi th gl Pi xel Map*()
The maxi mum si ze of the maps i s machi ne−dependent. You can fi nd the si zes of the pi xel maps
supported on your machi ne wi th the glGet*() command: Use the query argument
GL_MAX_PI XEL_MAP_TABLE to obtai n the maxi mum si ze for al l the pi xel map tabl es, and use
GL_PI XEL_MAP_*_TO_*_SI ZE to obtai n the current si ze of the speci fi ed map. The si x maps whose
178
address i s a col or i ndex must al ways be si zed to an i ntegral power of 2. The four RGBA maps can be any
si ze from 1 through GL_MAX_PI XEL_MAP_TABLE.
To i l l ustrate how a tabl e works, l et’s l ook at a si mpl e exampl e. Suppose that you want to create a
256−entry tabl e that maps col or i ndi ces to col or i ndi ces usi ng GL_PI XEL_MAP_I _TO_I . You create a
tabl e wi th an entry for each of the val ues between 0 and 255, and i ni ti al i ze the tabl e wi th glPixelMap*()
. Let’s say that you’re usi ng the tabl e for threshol di ng, for exampl e, and you want to map al l i ndi ces 100
and bel ow to 0, and al l i ndi ces 101 and above to 255. I n thi s case, your tabl e consi sts of 101 0s and 155
255s. The pi xel map i s enabl ed usi ng the routi ne glPixelTransfer*() to set the parameter
GL_MAP_COLOR to TRUE. Once the pi xel map i s l oaded and enabl ed, i ncomi ng col or i ndi ces bel ow
101 come out as 0, and i ncomi ng pi xel s between 101 and 255 are mapped to 255. I f the i ncomi ng pi xel
i s l arger than 255, i t’s fi rst masked by 255, throwi ng out al l the bi ts beyond the ei ghth, and the
resul ti ng masked val ue i s l ooked up i n the tabl e. I f the i ncomi ng i ndex i s a fl oati ng−poi nt val ue (say
88.14585), i t’s rounded to the nearest i nteger val ue (gi vi ng 88), and that number i s l ooked up i n the
tabl e (gi vi ng 0).
Chapter 9
Texture Mapping
Chapter Objectives
After readi ng thi s chapter, you’l l be abl e to do the fol l owi ng:
• Understand what texture mappi ng can add to your scene
• Speci fy a texture map and how i ts coordi nates rel ate to those of the objects i n your scene
• Control how a texture i mage i s fi l tered as i t’s appl i ed to a fragment
• Speci fy how the col or val ues i n the i mage combi ne wi th those of the fragment to whi ch i t’s bei ng
appl i ed
• Use automati c texture coordi nate generati on to produce effects l i ke contour maps and envi ronment
maps
So far i n thi s gui de, every geometri c pri mi ti ve has been drawn as ei ther a sol i d col or or smoothl y
shaded between the col ors at i ts verti cesthat i s, they’ve been drawn wi thout texture mappi ng. I f you
want to draw a l arge bri ck wal l wi thout texture mappi ng, for exampl e, each bri ck must be drawn as a
separate pol ygon. Wi thout texturi ng, a l arge fl at wal lwhi ch i s real l y a si ngl e rectangl emi ght
requi re thousands of i ndi vi dual bri cks, and even then the bri cks woul d appear too smooth and regul ar
to be real i sti c.
Texture mappi ng al l ows you to gl ue an i mage of a bri ck wal l (obtai ned, perhaps, by scanni ng i n a
photograph of a real wal l ) to a pol ygon, and to draw the enti re wal l as a si ngl e pol ygon. Texture
mappi ng ensures that al l the ri ght thi ngs happen as the pol ygon i s transformed and rendered: When
the wal l i s vi ewed i n perspecti ve, for exampl e, the bri cks decrease i n si ze al ong wi th the wal l as the wal l
gets farther from the vi ewpoi nt. Other uses for texture mappi ng i ncl ude vegetati on to be textured on
l arge pol ygons representi ng the ground for a fl i ght si mul ator; wal l paper patterns; and textures that
make pol ygons appear to be made of natural substances such as marbl e, wood, or cl oth. The
possi bi l i ti es are endl ess. Al though i t’s most natural to thi nk of appl yi ng textures to pol ygons, textures
can be appl i ed to al l pri mi ti vespoi nts, l i nes, pol ygons, bi tmaps, and i mages. Pl ates 6, 8, 18−21, 24−27,
and 29−31 al l demonstrate the use of textures.
Because there are so many possi bi l i ti es, texture mappi ng i s a fai rl y l arge, compl ex subject, and you
must make several programmi ng choi ces when usi ng i t. For i nstance, you can map textures to surfaces
made of a set of pol ygons or to curved surfaces, and you can repeat a texture i n one or both di recti ons to
cover the surface. A texture can even be one−di mensi onal . I n addi ti on, you can automati cal l y map a
texture onto an object i n such a way that the texture i ndi cates contours or other properti es of the i tem
bei ng vi ewed. Shi ny objects can be textured so that they appear as i f they were i n the center of a room
or other envi ronment, refl ecti ng the surroundi ngs off thei r surfaces. Fi nal l y, a texture can be appl i ed to
a surface i n di fferent ways. I t can be pai nted on di rectl y (l i ke a decal pl aced on a surface), i t can be used
179
to modul ate the col or the surface woul d have been pai nted otherwi se, or i t can be used to bl end a
texture col or wi th the surface col or. I f thi s i s your fi rst exposure to texture mappi ng, you mi ght fi nd
that the di scussi on i n thi s chapter moves fai rl y qui ckl y. As an addi ti onal reference, you mi ght l ook at
the chapter on texture mappi ng i n Fundamentals of Three−Dimensional Computer Graphics by Al an
Watt (Readi ng, Mass.: Addi son−Wesl ey, 1990).
Textures are si mpl y rectangul ar arrays of datafor exampl e, col or data, l umi nance data, or col or and
al pha data. The i ndi vi dual val ues i n a texture array are often cal l ed texels. What makes texture
mappi ng tri cky i s that a rectangul ar texture can be mapped to nonrectangul ar regi ons, and thi s must
be done i n a reasonabl e way.
Figure 9−1 i l l ustrates the texture−mappi ng process. The l eft si de of the fi gure represents the enti re
texture, and the bl ack outl i ne represents a quadri l ateral shape whose corners are mapped to those
spots on the texture. When the quadri l ateral i s di spl ayed on the screen, i t mi ght be di storted by
appl yi ng vari ous transformati onsrotati ons, transl ati ons, scal i ng, and projecti ons. The ri ght si de of
the fi gure shows how the texture−mapped quadri l ateral mi ght appear on your screen after these
transformati ons. (Note that thi s quadri l ateral i s concave and mi ght not be rendered correctl y by
OpenGL.)
Figure 9−1 The Texture−Mappi ng Process
Noti ce how the texture i s di storted to match the di storti on of the quadri l ateral . I n thi s case, i t’s
stretched i n the x di recti on and compressed i n the y di recti on; there’s a bi t of rotati on and sheari ng
goi ng on as wel l . Dependi ng on the texture si ze, the quadri l ateral ’s di storti on, and the si ze of the screen
i mage, some of the texel s mi ght be mapped to more than one fragment, and some fragments mi ght be
covered by mul ti pl e texel s. Si nce the texture i s made up of di screte texel s (i n thi s case, 256 × 256 of
them), fi l teri ng operati ons must be performed to map texel s to fragments. For exampl e, i f many texel s
correspond to a fragment, they’re averaged down to fi t; i f texel boundari es fal l across fragment
boundari es, a wei ghted average of the appl i cabl e texel s i s performed. Because of these cal cul ati ons,
texturi ng i s computati onal l y expensi ve, whi ch i s why many speci al i zed graphi cs systems i ncl ude
hardware support for texture mappi ng.
Thi s chapter covers the OpenGL’s texture−mappi ng faci l i ty i n the fol l owi ng major secti ons:
• "An Overview and an Example"gi ves a bri ef, broad l ook at the steps requi red to perform texture
180
mappi ng. I t al so presents a rel ati vel y si mpl e exampl e of texture mappi ng.
• "Specifying the Texture"expl ai ns how to speci fy a two− or one−di mensi onal texture. I t al so
di scusses how to use a texture’s borders, how to suppl y a seri es of rel ated textures of di fferent si zes,
and how to control the fi l teri ng methods used to determi ne how an appl i ed texture i s mapped to
screen coordi nates.
• "Modulating and Blending"di scusses the methods used for pai nti ng a texture onto a surface.
You can choose to have the texture col or val ues repl ace those that woul d be used i f texturi ng wasn’t
i n effect, or you can have the fi nal col or be a combi nati on of the two.
• "Assigning Texture Coordinates"descri bes how to compute and assi gn appropri ate texture
coordi nates to the verti ces of an object. I t al so expl ai ns how to control the behavi or of coordi nates
that l i e outsi de the defaul t rangethat i s, how to repeat or cl amp textures across a surface.
• "Automatic Texture−Coordinate Generation"shows you how to have OpenGL automati cal l y
generate texture coordi nates for you, i n order to achi eve such effects as contour and envi ronment
maps.
• "Advanced Features"expl ai ns how to mani pul ate the texture matri x stack and how to use the q
texture coordi nate.
Remember that you mi ght be abl e to use di spl ay l i sts to store defi ned textures for maxi mum
performance effi ci ency. See "Display−List Design Philosophy."
An Overview and an Example
Thi s secti on gi ves an overvi ew of the steps necessary to perform texture mappi ng. I t al so presents a
rel ati vel y si mpl e texture−mappi ng programrelatively because, remember, texture mappi ng i s a fai rl y
i nvol ved process.
Steps in Texture Mapping
To use texture mappi ng, you perform these steps:
1. Speci fy the texture.
2. I ndi cate how the texture i s to be appl i ed to each pi xel .
3. Enabl e texture mappi ng.
4. Draw the scene, suppl yi ng both texture and geometri c coordi nates.
Keep i n mi nd that texture mappi ng works onl y i n RGB mode; the resul ts i n col or−i ndex mode are
undefi ned.
Specify the Texture
I n the si mpl est case, the texture i s a si ngl e i mage. A texture i s usual l y thought of as bei ng
two−di mensi onal , l i ke most i mages, but i t can al so be one−di mensi onal . The data descri bi ng a texture
can consi st of one, two, three, or four el ements per texel , representi ng anythi ng from a modul ati on
constant to an (R, G, B, A) quadrupl e.
Usi ng an advanced techni que, cal l ed mipmapping, you can speci fy a si ngl e texture at many di fferent
resol uti ons; thi s al l ows you to avoi d mappi ng a ful l −resol uti on i mage of a bri ck wal l on a wal l that’s so
far away from the vi ewer that i t appears on the screen as a si ngl e pi xel , for exampl e. Al so, the
speci fi cati on of the map can i ncl ude boundary val ues to use when the object’s texture coordi nates get
outsi de the val i d range. Boundary val ues al l ow you to paste together mul ti pl e texture maps smoothl y,
thereby i ncreasi ng the effecti ve si ze of the l argest avai l abl e texture.
Indicate How the Texture Is to Be Applied to Each Pixel
You can choose any of three possi bl e functi ons for computi ng the fi nal RGBA val ue from the fragment
181
col or and the texture−i mage data. One possi bi l i ty i s to si mpl y use the texture col or as the fi nal col or;
thi s i s the decal mode, i n whi ch the texture i s pai nted on top of the fragment, just as a decal woul d be
appl i ed. Another method i s to use the texture to modulate, or scal e, the fragment’s col or; thi s techni que
i s useful for combi ni ng the effects of l i ghti ng wi th texturi ng. Fi nal l y, a constant col or can be bl ended
wi th that of the fragment, based on the texture val ue.
Enable Texture Mapping
You need to enabl e texturi ng before drawi ng your scene. Texturi ng i s enabl ed or di sabl ed usi ng
glEnable() or glDisable() wi th the symbol i c constant GL_TEXTURE_1D or GL_TEXTURE_2D for one−
or two−di mensi onal texturi ng, respecti vel y. (I f both are enabl ed, *2D i s preferred.)
Draw the Scene, Supplying Both Texture and Geometric Coordinates
You need to i ndi cate how the texture shoul d be al i gned rel ati ve to the fragments to whi ch i t’s to be
appl i ed before i t’s "gl ued on." That i s, you need to speci fy both texture coordi nates and geometri c
coordi nates as you speci fy the objects i n your scene. For a two−di mensi onal texture map, for exampl e,
the texture coordi nates range from 0.0 to 1.0 i n both di recti ons, but the coordi nates of the i tems bei ng
textured can be anythi ng. For the bri ck−wal l exampl e, i f the wal l i s square and meant to represent one
copy of the texture, the code woul d probabl y assi gn texture coordi nates (0, 0), (1, 0), (1, 1), and (0, 1) to
the four corners of the wal l . I f the wal l i s l arge, you mi ght want to pai nt several copi es of the texture
map on i t. I f you do so, the texture map must be desi gned so that the bri cks on the l eft edge bl end
ni cel y wi th the bri cks on the ri ght edge, and si mi l arl y for the bri cks on the top and those on the bottom.
You must al so i ndi cate how texture coordi nates outsi de the range [0.0,1.0] shoul d be treated. Do the
textures wrap to cover the object, or are they cl amped to a boundary val ue?
A Sample Program
One of the probl ems wi th showi ng sampl e programs to i l l ustrate texture mappi ng i s that i nteresti ng
textures are l arge. Typi cal l y, textures are read from an i mage fi l e, si nce speci fyi ng a texture
programmati cal l y coul d take hundreds of l i nes of code. I n Example 9−1, the texturewhi ch consi sts
of al ternati ng whi te and bl ack squares, l i ke a checkerboardi s generated by the program. The
program appl i es thi s texture to two squares, whi ch are then rendered i n perspecti ve, one of them faci ng
the vi ewer squarel y and the other ti l ti ng back at 45 degrees, as shown i n Figure 9−2 . I n object
coordi nates, both squares are the same si ze.
182
Figure 9−2 Texture−Mapped Squares
Example 9−1 A Texture−Mappedfs Checkerboard: checker.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
#define checkImageWidth 64
#define checkImageHeight 64
GLubyte checkImage[checkImageWidth][checkImageHeight][3];
void makeCheckImage(void)
{
int i, j, r, c;
for (i = 0; i < checkImageWidth; i++) {
for (j = 0; j < checkImageHeight; j++) {
c = ((((i&0x8)==0)^((j&0x8))==0))*255;
checkImage[i][j][0] = (GLubyte) c;
checkImage[i][j][1] = (GLubyte) c;
checkImage[i][j][2] = (GLubyte) c;
}
}
}
void myinit(void)
{
glClearColor (0.0, 0.0, 0.0, 0.0);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
makeCheckImage();
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, 3, checkImageWidth,
checkImageHeight, 0, GL_RGB, GL_UNSIGNED_BYTE,
&checkImage[0][0][0]);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_NEAREST);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glEnable(GL_TEXTURE_2D);
glShadeModel(GL_FLAT);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex3f(−2.0, −1.0, 0.0);
glTexCoord2f(0.0, 1.0); glVertex3f(−2.0, 1.0, 0.0);
183
glTexCoord2f(1.0, 1.0); glVertex3f(0.0, 1.0, 0.0);
glTexCoord2f(1.0, 0.0); glVertex3f(0.0, −1.0, 0.0);
glTexCoord2f(0.0, 0.0); glVertex3f(1.0, −1.0, 0.0);
glTexCoord2f(0.0, 1.0); glVertex3f(1.0, 1.0, 0.0);
glTexCoord2f(1.0, 1.0); glVertex3f(2.41421, 1.0, −1.41421);
glTexCoord2f(1.0, 0.0); glVertex3f(2.41421, −1.0,−1.41421);
glEnd();
glFlush();
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, 1.0*(GLfloat)w/(GLfloat)h, 1.0, 30.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, −3.6);
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA | AUX_DEPTH);
auxInitPosition (0, 0, 500, 500);
auxInitWindow (argv[0]);
myinit();
auxReshapeFunc (myReshape);
auxMainLoop(display);
}
The checkerboard texture i s generated i n the routi ne makeCheckI mage(), and al l the texture−mappi ng
i ni ti al i zati on occurs i n the routi ne myinit(). The si ngl e, ful l −resol uti on texture map i s speci fi ed by
glTexI mage2D(), whose parameters i ndi cate the si ze of the i mage, type of the i mage, l ocati on of the
i mage, and other properti es of i t. See the next secti on for more i nformati on about thi s command.
The next four cal l s to glTexParameter*() speci fy how the texture i s to be wrapped (see "Repeating and
Clamping Textures") and how the col ors are to be fi l tered i f there i sn’t an exact match between
pi xel s i n the texture and pi xel s on the screen (see "Controlling Filtering"). Next, glTexEnv*() sets the
drawi ng mode to GL_DECAL so that the textured pol ygons are drawn usi ng the col ors from the texture
map (rather than taki ng i nto account what col or the pol ygons woul d have been drawn wi thout the
texture). Fi nal l y, glEnable() turns on texturi ng.
The routi ne display() draws the two pol ygons. Note that texture coordi nates are speci fi ed al ong wi th
vertex coordi nates. The glTexCoord*() command behaves si mi l arl y to the glNormal() command: I t sets
the current texture coordi nates; any subsequent vertex command has those texture coordi nates
associ ated wi th i t unti l glTexCoord*() i s cal l ed agai n.
Note: The checkerboard i mage on the ti l ted pol ygon mi ght l ook wrong when you compi l e and run i t on
your machi nefor exampl e, i t mi ght l ook l i ke two tri angl es wi th di fferent projecti ons of the
checkerboard i mage on them. I f so, try setti ng the parameter
GL_PERSPECTI VE_CORRECTI ON_HI NT to GL_NI CEST and runni ng the exampl e agai n. To
do thi s, use glHint().
184
Specifying the Texture
The command glTexI mage2D() defi nes a two−di mensi onal texture. I t takes several arguments, whi ch
are descri bed bri efl y here and i n more detai l i n the subsecti ons that fol l ow. The rel ated command for
one−di mensi onal textures, glTexI mage1D(), i s descri bed i n "One−Dimensional Textures."
voi d glTexI mage2D(GLenum target, GLi nt level, GLi nt components, GLsi zei width, GLsi zei height, GLi nt
border, GLenum format, GLenum type, const GLvoi d *pixels);
Defi nes a two−di mensi onal texture. The target parameter i s i ntended for future use by OpenGL; for
thi s rel ease, i t must be set to the constant GL_TEXTURE_2D. You use the level parameter i f you’re
suppl yi ng mul ti pl e resol uti ons of the texture map; wi th onl y one resol uti on, level shoul d be 0. (See
"Multiple Levels of Detail" for more i nformati on about usi ng mul ti pl e resol uti ons.)
The next parameter, components, i s an i nteger from 1 to 4 i ndi cati ng whi ch of the R, G, B, and A
components are sel ected for use i n modul ati ng or bl endi ng. A val ue of 1 sel ects the R component, 2
sel ects the R and A components, 3 sel ects R, G, and B, and 4 sel ects R, B, G, and A. See "Modulating
and Blending" for a di scussi on of how these sel ected components are used.
The width and height parameters gi ve the di mensi ons of the texture i mage; border i ndi cates the wi dth
of the border, whi ch i s usual l y zero. (See "Using a Texture’s Borders.") Both width and height must
have the form 2
m
+2b, where m i s an i nteger (whi ch can have a di fferent val ue for width than for height)
and b i s the val ue of border. The maxi mum si ze of a texture map depends on the i mpl ementati on of
OpenGL, but i t must be at l east 64 × 64 (or 66 × 66 wi th borders). I f width or height i s set to zero,
texture mappi ng i s effecti vel y di sabl ed.
The format and typeparameters descri be the format and data type of the texture i mage data. They have
the same meani ng as they do for glDrawPixels(), whi ch i s descri bed i n "Storing, Transforming, and
Mapping Pixels." I n fact, texture data i s i n the same format as the data used by glDrawPixels(), so
the setti ngs of such modes as GL_ALI GNMENT appl y. (I n the checkered−squares exampl e, the cal l
glPixelStorei(GL_ALIGNMENT, 1);
i s made because the data i n the exampl e i sn’t padded at the end of each texel row.) The format
parameter can be GL_COLOR_I NDEX, GL_RGB, GL_RGBA, GL_RED, GL_GREEN, GL_BLUE,
GL_ALPHA, GL_LUMI NANCE, or GL_LUMI NANCE_ALPHAthat i s, the same formats avai l abl e for
glDrawPixels() wi th the excepti ons of GL_STENCI L_I NDEX and GL_DEPTH_COMPONENT.
Si mi l arl y, the typeparameter can be GL_BYTE, GL_UNSI GNED_BYTE, GL_SHORT,
GL_UNSI GNED_SHORT, GL_I NT, GL_UNSI GNED_I NT, GL_FLOAT, or GL_BI TMAP.
Fi nal l y, pixels contai ns the texture−i mage data. Thi s data descri bes the texture i mage i tsel f as wel l as
i ts border.
The next secti ons gi ve more detai l about usi ng the border and level parameters. The level parameter,
whi ch speci fi es textures of di fferent resol uti ons, natural l y rai ses the topi c of fi l teri ng textures as
they’re appl i ed; fi l teri ng i s the subject of "Controlling Filtering." Fi nal l y, one−di mensi onal textures
are di scussed i n "One−Dimensional Textures."
Using a Texture’s Borders
Advanced
I f you need to appl y a l arger texture map than your i mpl ementati on of OpenGL al l ows, you can, wi th a
l i ttl e care, effecti vel y make l arger textures by ti l i ng wi th several di fferent textures. For exampl e, i f you
need a texture twi ce as l arge as the maxi mum al l owed si ze mapped to a square, draw the square as
four subsquares, and l oad a di fferent texture before drawi ng each pi ece.
185
Si nce onl y a si ngl e texture map i s avai l abl e at one ti me, thi s approach mi ght l ead to probl ems at the
edges of the textures, especi al l y i f some form of l i near fi l teri ng i s enabl ed. The texture val ue to be used
for pi xel s at the edges must be averaged wi th somethi ng off the edge, whi ch, i deal l y, shoul d come from
the adjacent texture map. I f you defi ne a border for each texture whose texel val ues are equal to the
val ues of the texel s on the edge of the adjacent texture map, then when l i near averagi ng takes pl ace,
the correct behavi or resul ts.
To do thi s correctl y, noti ce that each map can have ei ght nei ghborsone adjacent to each edge, and one
touchi ng each corner. The val ues of the texel s i n the corner of the border need to correspond wi th the
texel s i n the texture maps that touch the corners. I f your texture i s an edge or corner of the whol e
ti l i ng, you need to deci de what val ues woul d be reasonabl e to put i n the borders. The easi est reasonabl e
thi ng to do i s to copy the val ue of the adjacent texel i n the texture map. Remember that the border
val ues need to be suppl i ed at the same ti me as the texture−i mage data, so you need to fi gure thi s out
ahead of ti me.
A texture’s border col or i s al so used i f the texture i s appl i ed i n such a way that i t onl y parti al l y covers a
pri mi ti ve. See "Repeating and Clamping Textures" for more i nformati on about thi s si tuati on.
Multiple Levels of Detail
Advanced
Textured objects can be vi ewed, l i ke any other objects i n a scene, at di fferent di stances from the
vi ewpoi nt. I n a dynami c scene, for exampl e, as a textured object moves farther from the vi ewpoi nt, the
texture map must decrease i n si ze al ong wi th the si ze of the projected i mage. To accompl i sh thi s,
OpenGL has to fi l ter the texture map down to an appropri ate si ze for mappi ng onto the object, wi thout
i ntroduci ng vi sual l y di sturbi ng arti facts. To avoi d such arti facts, you can speci fy a seri es of prefi l tered
texture maps of decreasi ng resol uti ons, cal l ed mipmaps, as shown i n Figure 9−3 . Then, OpenGL
automati cal l y determi nes whi ch texture map to use based on the si ze (i n pi xel s) of the object bei ng
mapped. Wi th thi s approach, the l evel of detai l i n the texture map i s appropri ate for the i mage that’s
drawn on the screenas the i mage of the object gets smal l er, the si ze of the texture map decreases.
Mi pmappi ng requi res some extra computati on, but, when i t’s not used, textures that are mapped onto
smal l er objects mi ght shi mmer and fl ash as the objects move.
186
Figure 9−3 Mi pmaps
Thi s techni que i s cal l ed mipmapping. (Mip stands for the Lati n multim im parvo, meani ng "many
thi ngs i n a smal l pl ace." Mi pmappi ng uses some cl ever methods to pack the i mage data i nto memory.
See "Pyramidal Parametrics " by Lance Wi l l i ams, SI GGRAPH 1983 Proceedi ngs.)
To use mi pmappi ng, you provi de al l si zes of your texture i n powers of 2 between the l argest si ze and a 1
× 1 map. For exampl e, i f your hi ghest−resol uti on map i s 64 × 16, you must al so provi de maps of si ze 32
× 8, 16 × 4, 8 × 2, 4 × 1, 2 × 1, and 1 × 1. The smal l er maps are typi cal l y fi l tered and averaged−down
versi ons of the l argest map i n whi ch each texel i n a smal l er texture i s an average of the correspondi ng
four texel s i n the l arger texture. OpenGL doesn’t requi re any parti cul ar method for cal cul ati ng the
smal l er maps, however, so the di fferentl y si zed textures coul d be total l y unrel ated.
To speci fy these textures, cal l glTexI mage2D() once for each resol uti on of the texture map, wi th
di fferent val ues for the level, width, height, and imageparameters. Starti ng wi th zero, level i denti fi es
whi ch texture i n the seri es i s speci fi ed; wi th the previ ous exampl e, the l argest texture of si ze 64 × 16
woul d be decl ared wi th level = 0, the 32 × 8 texture wi th level = 1, and so on. I n addi ti on, for the
mi pmapped textures to take effect, you need to choose one of the appropri ate fi l teri ng methods
descri bed i n the next secti on.
Example 9−2i l l ustrates the use of a seri es of si x texture maps decreasi ng i n si ze from 32 × 32 to 1 × 1.
Thi s program draws a rectangl e that extends from the foreground far back i n the di stance, eventual l y
di sappeari ng at a poi nt, as shown i n Figure J −27. Note that si xty−four copi es of the texture map are
requi red to ti l e the rectangl e, ei ght i n each di recti on. To i l l ustrate how one texture map succeeds
another, each map has a di fferent col or.
Example 9−2 A Mi pmappi ng Exampl e: mi pmap.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
GLubyte mipmapImage32[32][32][3];
GLubyte mipmapImage16[16][16][3];
GLubyte mipmapImage8[8][8][3];
GLubyte mipmapImage4[4][4][3];
GLubyte mipmapImage2[2][2][3];
GLubyte mipmapImage1[1][1][3];
void loadImages(void)
{
int i, j;
for (i = 0; i < 32; i++) {
for (j = 0; j < 32; j++) {
mipmapImage32[i][j][0] = 255;
mipmapImage32[i][j][1] = 255;
mipmapImage32[i][j][2] = 0;
}
}
for (i = 0; i < 16; i++) {
for (j = 0; j < 16; j++) {
mipmapImage16[i][j][0] = 255;
mipmapImage16[i][j][1] = 0;
mipmapImage16[i][j][2] = 255;
}
187
}
for (i = 0; i < 8; i++) {
for (j = 0; j < 8; j++) {
mipmapImage8[i][j][0] = 255;
mipmapImage8[i][j][1] = 0;
mipmapImage8[i][j][2] = 0;
}
}
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
mipmapImage4[i][j][0] = 0;
mipmapImage4[i][j][1] = 255;
mipmapImage4[i][j][2] = 0;
}
}
for (i = 0; i < 2; i++) {
for (j = 0; j < 2; j++) {
mipmapImage2[i][j][0] = 0;
mipmapImage2[i][j][1] = 0;
mipmapImage2[i][j][2] = 255;
}
}
mipmapImage1[0][0][0] = 255;
mipmapImage1[0][0][1] = 255;
mipmapImage1[0][0][2] = 255;
}
void myinit(void)
{
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glShadeModel(GL_FLAT);
glTranslatef(0.0, 0.0, −3.6);
loadImages();
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, 3, 32, 32, 0,
GL_RGB, GL_UNSIGNED_BYTE, &mipmapImage32[0][0][0]);
glTexImage2D(GL_TEXTURE_2D, 1, 3, 16, 16, 0,
GL_RGB, GL_UNSIGNED_BYTE, &mipmapImage16[0][0][0]);
glTexImage2D(GL_TEXTURE_2D, 2, 3, 8, 8, 0,
GL_RGB, GL_UNSIGNED_BYTE, &mipmapImage8[0][0][0]);
glTexImage2D(GL_TEXTURE_2D, 3, 3, 4, 4, 0,
GL_RGB, GL_UNSIGNED_BYTE, &mipmapImage4[0][0][0]);
glTexImage2D(GL_TEXTURE_2D, 4, 3, 2, 2, 0,
GL_RGB, GL_UNSIGNED_BYTE, &mipmapImage2[0][0][0]);
glTexImage2D(GL_TEXTURE_2D, 5, 3, 1, 1, 0,
GL_RGB, GL_UNSIGNED_BYTE, &mipmapImage1[0][0][0]);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_NEAREST);
188
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_NEAREST_MIPMAP_NEAREST);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glEnable(GL_TEXTURE_2D);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex3f(−2.0, −1.0, 0.0);
glTexCoord2f(0.0, 8.0); glVertex3f(−2.0, 1.0, 0.0);
glTexCoord2f(8.0, 8.0); glVertex3f(2000.0, 1.0, −6000.0);
glTexCoord2f(8.0, 0.0); glVertex3f(2000.0, −1.0, −6000.0);
glEnd();
glFlush();
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, 1.0*(GLfloat)w/(GLfloat)h, 1.0,
30000.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA | AUX_DEPTH);
auxInitPosition (0, 0, 500, 500);
auxInitWindow (argv[0]);
myinit();
auxReshapeFunc (myReshape);
auxMainLoop(display);
}
Example 9−2i l l ustrates mi pmappi ng by maki ng each mi pmap a di fferent col or so that i t’s obvi ous
when one map i s repl aced by another. I n a real si tuati on, you defi ne mi pmaps so that the transi ti on i s
as smooth as possi bl e. Thus, the maps of l ower resol uti on are usual l y fi l tered versi ons of an ori gi nal ,
hi gh−resol uti on map. The constructi on of a seri es of such mi pmaps i s a software process, and thus i sn’t
part of OpenGL, whi ch i s si mpl y a renderi ng l i brary. Si nce mi pmap constructi on i s such an i mportant
operati on, however, the OpenGL Uti l i ty Li brary contai ns three routi nes that ai d i n the mani pul ati on of
i mages to be used as texture maps.
Assumi ng that you have constructed the l evel 0, or hi ghest−resol uti on map, the routi nes
gluBuild1DMipmaps() and gluBuild2DMipmaps() construct and defi ne the pyrami d of mi pmaps down
to a resol uti on of 1 × 1 (or 1, for one−di mensi onal texture maps). Both these routi nes requi re that the
ori gi nal i mage al ready be sui tabl e for a texture map, namel y that i ts di mensi ons must be powers of 2.
Most scanned i mages don’t sati sfy thi s property, so you have to scal e the i ncomi ng i mage to some
appropri ate si ze. The GLU provi des the routi ne gluScaleI mage() to perform such scal i ng.
189
i nt gluBuild1DMipmaps(GLenum target, GLi nt components, GLi nt width, GLenum format, GLenum
type, voi d *data);
i nt gluBuild2DMipmaps(GLenum target, GLi nt components, GLi nt width, GLi nt height, GLenum format
, GLenum type, voi d *data);
Construct a seri es of mi pmaps. The parameters for target, components, width, height, format, type, and
data are exactl y the same as those for glTexI mage1D() and glTexI mage2D(). A val ue of 0 i s returned i f
al l the mi pmaps are constructed successful l y; otherwi se, a GLU error code i s returned.
i nt gluScaleI mage(GLenum format, GLi nt widthin, GLi nt heightin, GLenum typein, const voi d *datain,
GLi nt widthout, GLi nt heightout, GLenum typeout, voi d *dataout);
Scal es an i mage usi ng the appropri ate pi xel −storage modes to unpack the data from datain. The format
, typein, and typeout parameters can refer to any of the formats or data types supported by
glDrawPixels(). The i mage i s scal ed usi ng l i near i nterpol ati on and box fi l teri ng (from the si ze i ndi cated
by widthin and heightin to widthout and heightout), and the resul ti ng i mage i s wri tten to dataout. A
val ue of 0 i s returned on success, and a GLU error code i s returned on fai l ure.
Controlling Filtering
Texture maps are square or rectangul ar, but after bei ng mapped to a pol ygon or surface and
transformed i nto screen coordi nates, the i ndi vi dual texel s of a texture rarel y correspond to i ndi vi dual
pi xel s of the fi nal screen i mage. Dependi ng on the transformati ons used and the texture mappi ng
appl i ed, a si ngl e pi xel on the screen can correspond to anythi ng from a ti ny porti on of a texel
(magni fi cati on) to a l arge col l ecti on of texel s (mi ni fi cati on), as shown i n Figure 9−4 . I n ei ther case, i t’s
uncl ear exactl y whi ch texel val ues shoul d be used and how they shoul d be averaged or i nterpol ated.
Consequentl y, OpenGL al l ows you to speci fy any of several fi l teri ng opti ons to determi ne these
cal cul ati ons. The opti ons provi de di fferent trade−offs between speed and i mage qual i ty. Al so, you can
speci fy the fi l teri ng methods for magni fi cati on and mi ni fi cati on i ndependentl y.
Figure 9−4 Texture Magni fi cati on and Mi ni fi cati on
I n some cases, i t i sn’t obvi ous whether magni fi cati on or mi ni fi cati on i s cal l ed for. I f the mi pmap needs
to be stretched (or shrunk) i n both the x and y di recti ons, then magni fi cati on (or mi ni fi cati on) i s
needed. I f the mi pmap needs to be stretched i n one di recti on and shrunk i n the other, however,
OpenGL makes a choi ce between magni fi cati on and mi ni fi cati on that i n most cases gi ves the best
resul t possi bl e. I t’s best to try to avoi d these si tuati ons by usi ng texture coordi nates that map wi thout
such di storti on; see "Computing Appropriate Texture Coordinates."
The fol l owi ng l i nes are exampl es of how to use glTexParameter*() to speci fy the magni fi cati on and
190
mi ni fi cati on fi l teri ng methods:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_NEAREST);
The fi rst argument to glTexParameter*() i s ei ther GL_TEXTURE_2D or GL_TEXTURE_1D, dependi ng
on whether you’re worki ng wi th two− or one−di mensi onal textures. For the purposes of thi s di scussi on,
the second argument i s ei ther GL_TEXTURE_MAG_FI LTER or GL_TEXTURE_MI N_FI LTER to
i ndi cate whether you’re speci fyi ng the fi l teri ng method for magni fi cati on or mi ni fi cati on. The thi rd
argument speci fi es the fi l teri ng method; Table 9−1 l i sts the possi bl e val ues.
Parameter Values
GL_TEXTURE_MAG_FILTER GL_NEAREST or GL_LINEAR
GL_TEXTURE_MIN_FILTER GL_NEAREST, GL_LINEAR,
GL_NEAREST_MIPMAP_NEAREST,
GL_NEAREST_MIPMAP_LINEAR,
GL_LINEAR_MIPMAP_NEAREST, or
GL_LINEAR_MIPMAP_LINEAR
Table 9−1 Fi l teri ng Methods for Magni fi cati on and Mi ni fi cati on
I f you choose GL_NEAREST, the texel wi th coordi nates nearest the center of the pi xel i s used for both
magni fi cati on and mi ni fi cati on. Thi s can resul t i n al i asi ng arti facts (someti mes severe). I f you choose
GL_LI NEAR, a wei ghted l i near average of the 2x2 array of texel s that l i es nearest to the center of the
pi xel i s used, agai n for both magni fi cati on and mi ni fi cati on. When the texture coordi nates are near the
edge of the texture map, the nearest 2x2 array of texel s mi ght i ncl ude some that are outsi de the texture
map. I n these cases, the texel val ues used depend on whether GL_REPEAT or GL_CLAMP i s i n effect
and whether you’ve assi gned a border for the texture, as descri bed i n "Using a Texture’s Borders."
GL_NEAREST requi res l ess computati on than GL_LI NEAR and therefore mi ght execute more qui ckl y,
but GL_LI NEAR provi des smoother resul ts.
Wi th magni fi cati on, even i f you’ve suppl i ed mi pmaps, the l argest texture map (level = 0) i s al ways used.
Wi th mi ni fi cati on, you can choose a fi l teri ng method that uses the most appropri ate one or two
mi pmaps, as descri bed i n the next paragraph. (I f GL_NEAREST or GL_LI NEAR i s speci fi ed wi th
mi ni fi cati on, the l argest texture map i s used.)
As shown i n Table 9−1 , four addi ti onal fi l teri ng choi ces are avai l abl e when mi ni fyi ng wi th mi pmaps.
Wi thi n an i ndi vi dual mi pmap, you can choose the nearest texel val ue wi th
GL_NEAREST_MI PMAP_NEAREST, or you can i nterpol ate l i nearl y by speci fyi ng
GL_LI NEAR_MI PMAP_NEAREST. Usi ng the nearest texel s i s faster but yi el ds l ess desi rabl e resul ts.
The parti cul ar mi pmap chosen i s a functi on of the amount of mi ni fi cati on requi red, and there’s a cutoff
poi nt from the use of one parti cul ar mi pmap to the next. To avoi d a sudden transi ti on, use
GL_NEAREST_MI PMAP_LI NEAR or GL_LI NEAR_MI PMAP_LI NEAR to l i nearl y i nterpol ate texel
val ues from the two nearest best choi ces of mi pmaps. GL_NEAREST_MI PMAP_LI NEAR sel ects the
nearest texel i n each of the two maps and then i nterpol ates l i nearl y between these two val ues.
GL_LI NEAR_MI PMAP_LI NEAR uses l i near i nterpol ati on to compute the val ue i n each of two maps
and then i nterpol ates l i neral y between these two val ues. As you mi ght expect,
GL_LI NEAR_MI PMAP_LI NEAR general l y produces the smoothest resul ts, but i t requi res the most
computati on and therefore mi ght be the sl owest.
One−Dimensional Textures
Someti mes a one−di mensi onal texture i s suffi ci entfor exampl e, i f you’re drawi ng textured bands
where al l the vari ati on i s i n one di recti on. A one−di mensi onal texture behaves l i ke a two−di mensi onal
one wi th height = 1, and wi thout borders al ong the top and bottom. To speci fy a one−di mensi onal
191
texture, use glTexI mage1D().
voi d glTexI mage1D(GLenum target, GLi nt level, GLi nt components, GLsi zei width, GLi nt border,
GLenum format, GLenum type, const GLvoi d *pixels);
Defi nes a one−di mensi onal texture. Al l the parameters have the same meani ngs as for glTexI mage2D(),
except that the i mage i s now a one−di mensi onal array of texel s. As before, the val ue of width must be a
power of 2 (2
m
, or 2
m
+2 i f there’s a border). You can suppl y mi pmaps, and the same fi l teri ng opti ons
are avai l abl e as wel l .
For a sampl e program that uses a one−di mensi onal texture map, see Example 9−3.
Modulating and Blending
I n al l the exampl es so far i n thi s chapter, the val ues i n the texture map have been used di rectl y as
col ors to be pai nted on the surface bei ng rendered. You can al so use the val ues i n the texture map to
modul ate the col or that the surface woul d be pai nted wi thout texturi ng, or to bl end the col or i n the
texture map wi th the nontextured col or of the surface. You choose one of these three texturi ng
functi ons by suppl yi ng the appropri ate arguments to glTexEnv*().
voi d glTexEnv{i f}{v}(GLenum target, GLenum pname, TYPEparam);
Sets the current texturi ng functi on. target must be GL_TEXTURE_ENV. I f pname i s
GL_TEXTURE_ENV_MODE, param can be GL_DECAL, GL_MODULATE, or GL_BLEND, to speci fy
how texture val ues are to be combi ned wi th the col or val ues of the fragment bei ng processed. I n decal
mode and wi th a three−component texture, the texture’s col ors repl ace the fragment’s col ors. Wi th
ei ther of the other modes or wi th a four−component texture, the fi nal col or i s a combi nati on of the
texture’s and the fragment’s val ues. I f pnamei s GL_TEXTURE_ENV_COLOR, param i s an array of
four fl oati ng−poi nt val ues representi ng R, G, B, and A components. These val ues are used onl y i f the
GL_BLEND texture functi on has been speci fi ed as wel l .
The texturi ng functi on operates on sel ected components of the texture and the col or val ues that woul d
be used wi th no texturi ng. Recal l that when you speci fy your texture map wi th glTexI mage*d(), the
thi rd argument i s the number of R, G, B, A components to be sel ected for each texel . A si ngl e sel ected
component i s i nterpreted as a l umi nance val ue (L); i f there are two, the fi rst i s l umi nance, and the
second i s an al pha val ue (A). Three components form an RGB col or tri pl e (C), and four components
provi de an RGB tri pl e and a val ue for al pha. Note that thi s sel ecti on i s performed after the
pi xel −transfer functi on has been appl i ed. Therefore, i t makes sense, for exampl e, to speci fy a texture
wi th a GL_COLOR_I NDEX i mage because the i ndi ces are converted to RGBA val ues by tabl e l ookup
before they’re used to form the texture i mage. These components are used by the texturi ng functi ons as
shown i n Table 9−2 .
Components Decal Mode Modulate Mode Blend Mode
1 undefined C = L
t
C
f
,
A = A
f
C = (1−L
t
)C
f
+ L
t
C
c
,
A = A
f
2 undefined C = L
t
C
f
,
A = A
t
A
f
C = (1−L
t
)C
f
+ L
t
C
c
,
A = A
t
A
f
3 C = C
t
,
A = A
f
C = C
t
C
f
,
A = A
f
undefined
4 C = (1
t
)C
f
+ A
t
C
t
,
A = A
f
C = C
t
C
f
,
A = A
t
A
f
undefined
Table 9−2 Decal , Modul ate, and Bl end Functi ons
192
Note: I n the tabl e, a subscri pt of t i ndi cates a texture val ue, f i ndi cates a fragment val ue, c i ndi cates
the val ues assi gned wi th GL_TEXTURE_ENV_COLOR, and no subscri pt i ndi cates the fi nal ,
computed val ue. Al so i n the tabl e, mul ti pl i cati on of a col or tri pl e by a scal ar means mul ti pl yi ng
each of the R, G, and B components by the scal ar; mul ti pl yi ng (or addi ng) two col or tri pl es
means mul ti pl yi ng (or addi ng) each component of the second by the correspondi ng component
of the fi rst.
Decal mode makes sense onl y i f the number of components i s three or four (remember that texture
mappi ng doesn’t work i n col or−i ndex mode). Wi th three sel ected components, the col or that woul d have
been pai nted i n the absence of any texture mappi ng (the fragment’s col or) i s repl aced by the texture
col or, and i ts al pha i s unchanged. Wi th four components, the fragment’s col or i s bl ended wi th the
texture col or i n a rati o determi ned by the texture al pha, and the fragment’s al pha i s unchanged. You
use decal mode i n si tuati ons where you want to appl y an opaque texture to an objecti f you were
drawi ng a soup can wi th an opaque l abel , for exampl e.
For modul ati on, the fragment’s col or i s modul ated by the contents of the texture map. For one or two
components, the col or val ues are mul ti pl i ed by the same val ue, so the texture map modul ates between
the fragment’s col or (i f the l umi nance i s 1) to bl ack (i f i t’s 0). Wi th three or four components, each of the
i ncomi ng col or components i s mul ti pl i ed by a correspondi ng (possi bl y di fferent) val ue i n the texture. I f
there’s an al pha val ue (whi ch there i s for two or four components), i t’s mul ti pl i ed by the fragment’s
al pha. You need to use modul ati on to create a texture that responds to l i ghti ng condi ti ons; most of the
texture−mappi ng exampl es i n the col or pl ates use modul ati on for thi s reason.
Bl endi ng mode makes sense onl y for one− or two−component textures. The l umi nance i s used
somewhat l i ke an al pha val ue to bl end the fragment’s col or wi th the col or speci fi ed by
GL_TEXTURE_ENV_COLOR. Wi th two components, the fragment’s al pha i s al so mul ti pl i ed by the
al pha i n the texture. See "Sample Uses of Blending" for the bi l l boardi ng exampl e, whi ch uses a
bl ended texture.
Assigning Texture Coordinates
As you draw your texture−mapped scene, you must provi de both object coordi nates and texture
coordi nates for each vertex. After transformati on, the object coordi nates determi ne where on the screen
that parti cul ar vertex i s rendered. The texture coordi nates determi ne whi ch texel i n the texture map i s
assi gned to that vertex. I n exactl y the same way that col ors are i nterpol ated between two verti ces of
shaded pol ygons and l i nes, texture coordi nates are l i nearl y i nterpol ated between verti ces. (Remember
that textures are rectangul ar arrays of data.)
Texture coordi nates can compri se one, two, three, or four coordi nates. They’re usual l y referred to as the
s, t, r, and q coordi nates to di sti ngui sh them from object coordi nates (x, y, z, and w) and from eval uator
coordi nates (u and v; see Chapter 11). For one−di mensi onal textures, you use the s coordi nate; for
two−di mensi onal textures, you use s and t. Currentl y, the r coordi nate i s i gnored (al though i t mi ght
have meani ng i n the future). The q coordi nate, l i ke w, i s typi cal l y gi ven the val ue 1 and can be used to
create homogeneous coordi nates; i t’s descri bed as an advanced feature i n "The q Coordinate." The
command to speci fy texture coordi nates, glTexCoord*(), i s si mi l ar to glVertex*(), glColor*(), and
glNormal*()i t comes i n si mi l ar vari ati ons and i s used the same way between glBegin() and glEnd()
pai rs. Usual l y, texture−coordi nate val ues range between 0 and 1; val ues can be assi gned outsi de thi s
range, however, wi th the resul ts descri bed i n "Repeating and Clamping Textures."
voi d glTexCoord{1234}{si fd}{v}(TYPEcoords);
Sets the current texture coordi nates (s, t, r, q). Subsequent cal l s to glVertex*() resul t i n those verti ces
bei ng assi gned the current texture coordi nates. Wi th glTexCoord1*(), the s coordi nate i s set to the
speci fi ed val ue, t and r are set to 0, and q i s set to 1. Usi ng glTexCoord2*() al l ows you to speci fy s and t; r
and q are set to 0 and 1, respecti vel y. Wi th glTexCoord3*(), q i s set to 1 and the other coordi nates are
set as speci fi ed. You can speci fy al l coordi nates wi th glTexCoord4*(). Use the appropri ate suffi x (s, i , f,
193
or d) and the correspondi ng val ue for TYPE (GLshort, GLi nt, GLfl oat, or GLdoubl e) to speci fy the
coordi nates’ data type. You can suppl y the coordi nates i ndi vi dual l y, or you can use the vector versi on of
the command to suppl y them i n a si ngl e array. Texture coordi nates are mul ti pl i ed by the 4x4 texture
matri x before any texture mappi ng occurs, as descri bed i n "The Texture Matrix Stack." Note that
i nteger texture coodi nates are i nterpreted di rectl y rather than bei ng mapped to the range [−1,1] as
normal coordi nates are.
The next secti on di scusses how to cal cul ate appropri ate texture coordi nates. I nstead of expl i ci tl y
assi gni ng them yoursel f, you can choose to have texture coordi nates cal cul ated automati cal l y by
OpenGL as a functi on of the vertex coordi nates. Thi s techni que i s descri bed i n "Automatic
Texture−Coordinate Generation."
Computing Appropriate Texture Coordinates
Two−di mensi onal textures are square or rectangul ar i mages that are typi cal l y mapped to the pol ygons
that make up a pol ygonal model . I n the si mpl est case, you’re mappi ng a rectangul ar texture onto a
model that’s al so rectangul arfor exampl e, your texture i s a scanned i mage of a bri ck wal l , and your
rectangl e i s to represent a bri ck wal l of a bui l di ng. Suppose the bri ck wal l i s square, and the texture i s
square, and you want to map the whol e texture to the whol e wal l . The texture coordi nates of the
texture square are (0, 0), (1, 0), (1, 1), and (0, 1) i n countercl ockwi se order. When you’re drawi ng the
wal l , just gi ve those four coordi nate sets as the texture coordi nates as you speci fy the wal l ’s verti ces i n
countercl ockwi se order.
Now suppose that the wal l i s two−thi rds as hi gh as i t i s wi de, that the texture i s agai n square. To avoi d
di storti ng the texture, you need to map the wal l to a porti on of the texture map so that the aspect rati o
of the texture i s preserved. Suppose that you deci de to use the l ower two−thi rds of the texture map to
texture the wal l . I n thi s case, use texture coordi nates of (0,0), (1,0), (1,2/3), and (0,2/3) for the texture
coordi nates as the wal l verti ces are traversed i n a countercl ockwi se order.
As a sl i ghtl y more compl i cated exampl e, suppose you’d l i ke to di spl ay a ti n can wi th a l abel wrapped
around i t on the screen. To obtai n the texture, you purchase a can, remove the l abel , and scan i t i n.
Suppose the l abel i s 4 uni ts tal l and 12 uni ts around, whi ch yi el ds an aspect rati o of 3 to 1. Si nce
textures must have aspect rati os of 2
n
to 1, you can ei ther si mpl y not use the top thi rd of the texture, or
you can cut and paste the texture unti l i t has the necessary aspect rati o. Let’s say you deci de to not use
the top thi rd. Now suppose the ti n can i s a cyl i nder approxi mated by thi rty pol ygons of l ength 4 uni ts
(the hei ght of the can) and wi dth 12/30 (1/30 of the ci rcumference of the can). You can use the fol l owi ng
texture coordi nates for each of the thi rty approxi mati ng rectangl es:
1: (0, 0), (1/30, 0), (1/30, 2/3), (0, 2/3)
2: (1/30, 0), (2/30, 0), (2/30, 2/3), (1/30, 2/3)
3: (2/30, 0), (3/30, 0), (3/30, 2/3), (2/30, 2/3)
. . .
30: (29/30, 0), (1, 0), (1, 2/3), (29/30, 2/3)
Onl y a few curved surfaces such as cones and cyl i nders can be mapped to a fl at surface wi thout
geodesi c di storti on. Any other shape requi res some di storti on. I n general , the hi gher the curvature of
the surface, the more di storti on of the texture i s requi red.
I f you don’t care about texture di storti on, i t’s often qui te easy to fi nd a reasonabl e mappi ng. For
exampl e, consi der a sphere whose surface coordi nates are gi ven by (cos θ cos φ, cos θ si n φ, si n θ), where
0≤θ≤2π, and 0≤φ≤π. The θ−φ rectangl e can be mapped di rectl y to a rectangul ar texture map, but the
cl oser you get to the pol es, the more di storted the texture i s. The enti re top edge of the texture map i s
mapped to the north pol e, and the enti re bottom edge to the south pol e. For other surfaces, such as that
of a torus (doughnut) wi th a l arge hol e, the natural surface coordi nates map to the texture coordi nates
i n a way that produces onl y a l i ttl e di storti on, so i t mi ght be sui tabl e for many appl i cati ons. Figure
9−5 shows two tori , one wi th a smal l hol e (and therefore a l ot of di storti on near the center) and one
194
9−5 shows two tori , one wi th a smal l hol e (and therefore a l ot of di storti on near the center) and one
wi th a l arge hol e (and onl y a l i ttl e di storti on).
Figure 9−5 Texture−Map Di storti on
I f you’re texturi ng spl i ne surfaces generated wi th eval uators (see Chapter 11), the u and v parameters
for the surface can someti mes be used as texture coordi nates. I n general , however, there’s a l arge
arti sti c component to successful l y mappi ng textures to pol ygonal approxi mati ons of curved surfaces.
Repeating and Clamping Textures
You can assi gn texture coordi nates outsi de the range [0,1] and have them ei ther cl amp or repeat i n the
texture map. Wi th repeati ng textures, i f you have a l arge pl ane wi th texture coordi nates runni ng from
0.0 to 10.0 i n both di recti ons, for exampl e, you’l l get 100 copi es of the texture ti l ed together on the
screen. Duri ng repeati ng, the i nteger part of texture coordi nates i s i gnored, and copi es of the texture
map ti l e the surface. For most appl i cati ons where the texture i s to be repeated, the texel s at the top of
the texture shoul d match those at the bottom, and si mi l arl y for the l eft and ri ght edges.
The other possi bi l i ty i s to cl amp the texture coordi nates: Any val ues greater than 1.0 are set to 1.0, and
any val ues l ess than 0.0 are set to 0.0. Cl ampi ng i s useful for appl i cati ons where you want a si ngl e copy
of the texture to appear on a l arge surface. I f the surface−texture coordi nates range from 0.0 to 10.0 i n
both di recti ons, one copy of the texture appears i n the l ower corner of the surface. The rest of the
surface i s pai nted wi th the texture’s border col ors as needed. I f you’ve chosen GL_LI NEAR as the
fi l teri ng method (see "Controlling Filtering"), an equal l y wei ghted combi nati on of the border col or
and the texture col or i s used, as fol l ows:
• When repeati ng, the 2 × 2 array wraps to the opposi te edge of the texture. Thus, texel s on the ri ght
edge are averaged wi th those on the l eft, and top and bottom texel s are al so averaged.
• I f there i s a border, then the texel from the border i s used. Otherwi se,
GL_TEXTURE_BORDER_COLOR i s used.
Note that you can avoi d havi ng the rest of the surface affected by the texture. To do thi s, use bl endi ng
wi th al pha val ues of 0 to el i mi nate the drawi ng. (See "Blending.")
I f you haven’t speci fi ed a border wi th glTexI mage*d(), the col or val ue of
GL_TEXTURE_BORDER_COLOR i s used to pai nt the rest of the surface. By defaul t, thi s val ue i s (0, 0,
0, 0); use glTexParameter*() to change thi s val ue, as descri bed near the end of thi s secti on.
195
I n Example 9−1, i f the texture coordi nates for the squares are mapped from 0.0 to 3.0 as fol l ows, the
resul t i s as shown i n Figure 9−6 .
glBegin(GL_POLYGON);
glTexCoord2f(0.0, 0.0); glVertex3f(−2.0, −1.0, 0.0);
glTexCoord2f(0.0, 3.0); glVertex3f(−2.0, 1.0, 0.0);
glTexCoord2f(3.0, 3.0); glVertex3f(0.0, 1.0, 0.0);
glTexCoord2f(3.0, 0.0); glVertex3f(0.0, −1.0, 0.0);
glEnd();
glBegin(GL_POLYGON);
glTexCoord2f(0.0, 0.0); glVertex3f(1.0, −1.0, 0.0);
glTexCoord2f(0.0, 3.0); glVertex3f(1.0, 1.0, 0.0);
glTexCoord2f(3.0, 3.0); glVertex3f(2.41421, 1.0, −1.41421);
glTexCoord2f(3.0, 0.0); glVertex3f(2.41421, −1.0, −1.41421); glEnd();
Figure 9−6 Repeati ng a Texture
I n thi s case, the texture i s repeated i n both the s and t di recti ons, si nce the fol l owi ng cal l s are made to
glTexParameter*():
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_S_WRAP, GL_REPEAT);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_T_WRAP, GL_REPEAT);
I f GL_CLAMP i s used i nstead of GL_REPEAT, you see the pi cture shown i n Figure 9−7 .
196
Figure 9−7 Cl ampi ng a Texture
Noti ce that the border col ors are conti nued outsi de the range of the texture map. You can al so cl amp i n
one di recti on and repeat i n the other, as shown i n Figure 9−8 .
Figure 9−8 Repeati ng and Cl ampi ng a Texture
You’ve now seen al l the possi bl e arguments for glTexParameter*(), whi ch i s summari zed here.
voi d glTexParameter{i f}{v}(GLenum target, GLenum pname, TYPE param);
Sets vari ous parameters that control how a texture i s treated as i t’s appl i ed to a fragment. The target
parameter i s ei ther GL_TEXTURE_2D or GL_TEXTURE_1D to i ndi cate a two− or one−di mensi onal
texture. The possi bl e val ues for pnameand param are shown i n Table 9−3 . You can use the vector
versi on of the command to suppl y an array of val ues for GL_TEXTURE_BORDER_COLOR, or you can
suppl y them i ndi vi dual l y usi ng the nonvector versi on. I f these val ues are suppl i ed as i ntegers, they’re
converted to fl oati ng−poi nt accordi ng to Table 5−1 ; they’re al so cl amped to the range [0,1]
Parameter Values
197
GL_TEXTURE_WRAP_S GL_CLAMP, GL_REPEAT
GL_TEXTURE_WRAP_T GL_CLAMP, GL_REPEAT
GL_TEXTURE_MAG_FILTER GL_NEAREST, GL_LINEAR
GL_TEXTURE_MIN_FILTER GL_NEAREST, GL_LINEAR,
GL_NEAREST_MIPMAP_NEAREST,
GL_NEAREST_MIPMAP_LINEAR,
GL_LINEAR_MIPMAP_NEAREST,
GL_LINEAR_MIPMAP_LINEAR
GL_TEXTURE_BORDER_COLOR any four values in [0, 1]
Table 9−3 Arguments for gl TexParameter*()
Automatic Texture−Coordinate Generation
You can use texture mappi ng to make contours on your model s or to si mul ate the refl ecti ons from an
arbi trary envi ronment on a shi ny model . To achi eve these effects, l et OpenGL automati cal l y generate
the texture coordi nates for you, rather than expl i ci tl y assi gni ng them wi th glTexCoord*(). Actual l y, the
mechani sm for automati c texture−coordi nate generati on i s useful for many di fferent appl i cati ons such
as showi ng contours and envi ronment mappi ng. To generate texture coordi nates automati cal l y, use the
command glTexGen().
voi d glTexGen{i fd}{v}(GLenum coord, GLenum pname, TYPEparam);
Speci fi es the functi ons for automati cal l y generati ng texture coordi nates. The fi rst parameter, coord,
must be GL_S, GL_T, GL_R, or GL_Q to i ndi cate whether texture coordi nate s, t, r, or q i s to be
generated. The pnameparameter i s GL_TEXTURE_GEN_MODE, GL_OBJECT_PLANE, or
GL_EYE_PLANE. I f i t’s GL_TEXTURE_GEN_MODE, param i s an i nteger (or, i n the vector versi on of
the command, poi nts to an i nteger) that’s ei ther GL_OBJECT_LI NEAR, GL_EYE_LI NEAR, or
GL_SPHERE_MAP. These symbol i c constants determi ne whi ch functi on i s used to generate the texture
coordi nate. Wi th ei ther of the other possi bl e val ues for pname, param i s ei ther a poi nter to an array of
val ues (i n the vector versi on) or a si ngl e val ue speci fyi ng parameters for the texture−generati on
functi on.
Creating Contours
When GL_TEXTURE_GEN_MODE and GL_OBJECT_LI NEAR are speci fi ed, the generati on functi on
i s a l i near combi nati on of the object coordi nates of the vertex (x
o,
y
o,
z
o,
w
o
):
generated coordi nate = p
1
x
0
+ p
2
y
0
+ p
3
z
0
+ p
4
w
0
The p
1
, ..., p
4
val ues are suppl i ed as the param argument to glTexGen*() wi th pnameset to
GL_OBJECT_PLANE. Wi th p
1
, ..., p
4
correctl y normal i zed, thi s functi on gi ves the di stance from the
vertex to a pl ane. For exampl e, i f p
1
= p
3
= p
4
= 0 and p
2
= 1, the functi on gi ves the di stance between
the vertex and the pl ane y = 0. The di stance i s posi ti ve on one si de of the pl ane, negati ve on the other,
and zero i f the vertex l i es on the pl ane.
I n Example 9−3, equal l y spaced contour l i nes are drawn on a teapot; the l i nes i ndi cate the di stance
from the pl ane y = 0. Si nce onl y one property i s bei ng shown (the di stance from the pl ane), a
one−di mensi onal texture map suffi ces. The texture map i s a constant green col or, except that at equal l y
spaced i nterval s i t i ncl udes a red mark. Si nce the teapot i s si tti ng on the x−y pl ane, the contours are al l
perpendi cul ar to i ts base. Figure J −23 shows the pi cture drawn by the program.
Example 9−3 Automati c Texture−Coordi nate Generati on: texgen.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
198
#define stripeImageWidth 32
GLubyte stripeImage[3*stripeImageWidth];
void loadStripeImage(void)
{
int j;
for (j = 0; j < stripeImageWidth; j++) {
stripeImage[3*j] = (j<=4) ? 255 : 0;
stripeImage[3*j+1] = (j>4) ? 255 : 0;
stripeImage[3*j+2] = 0;
}
}
GLfloat sgenparams[] = {1.0, 0.0, 0.0, 0.0};
void myinit(void)
{
glClearColor (0.0, 0.0, 0.0, 0.0);
loadStripeImage();
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S,
GL_REPEAT);
glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER,
GL_LINEAR);
glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR);
glTexImage1D(GL_TEXTURE_1D, 0, 3, stripeImageWidth, 0,
GL_RGB, GL_UNSIGNED_BYTE, stripeImage);
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
glTexGenfv(GL_S, GL_OBJECT_PLANE, sgenparams);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_1D);
glEnable(GL_CULL_FACE);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_AUTO_NORMAL);
glEnable(GL_NORMALIZE);
glFrontFace(GL_CW);
glCullFace(GL_BACK);
glMaterialf (GL_FRONT, GL_SHININESS, 64.0);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix ();
glRotatef(45.0, 0.0, 0.0, 1.0);
auxSolidTeapot(2.0);
199
glPopMatrix ();
glFlush();
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h) glOrtho (−3.5, 3.5, −3.5*(GLfloat)h/(GLfloat)w,
3.5*(GLfloat)h/(GLfloat)w, −3.5, 3.5);
else glOrtho (−3.5*(GLfloat)w/(GLfloat)h,
3.5*(GLfloat)w/(GLfloat)h, −3.5, 3.5, −3.5, 3.5);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA | AUX_DEPTH);
auxInitPosition (0, 0, 200, 200);
auxInitWindow (argv[0]);
myinit();
auxReshapeFunc (myReshape);
auxMainLoop(display);
}
As shown, you have to enabl e texture−coordi nate generati on for the s coordi nate by passi ng
GL_TEXTURE_GEN_S to glEnable(); i f you were generati ng other coordi nates, you’d have to enabl e
them wi th GL_TEXTURE_GEN_T, GL_TEXTURE_GEN_R, or GL_TEXTURE_GEN_Q. (Use
glDisable() wi th the appropri ate constant to di sabl e coordi nate generati on.) Al so note the use of
GL_REPEAT to cause the contour l i nes to be repeated across the teapot.
I f you change the l i ne that defi nes the parameter array sgenparams to
GLfloat sgenparams[] = {1, 1, 1, 0};
the contour stri pes are paral l el to the pl ane x + y + z = 0, sl i ci ng across the teapot at an angl e, as shown
i n Figure J −24.
The GL_OBJECT_LI NEAR functi on cal cul ates the texture coordi nates i n the model ’s coordi nate
system. I n Example 9−3, where the contour l i nes are perpendi cul ar to the base of the teapot, they
woul d remai n so, no matter how the teapot was rotated or vi ewed. Someti mes you’d l i ke the contour
l i nes to be cal cul ated rel ati ve to the eye’s coordi nate system. I n other words, you want to mul ti pl y the
vector (p
1
p
2
p
3
p
4
) by the i nverse of the model vi ew matri x before cal cul ati ng the di stance to the pl ane. I f
you speci fy GL_TEXTURE_GEN_MODE wi th GL_EYE_LI NEAR, thi s i s exactl y what happens. The
texture coordi nate i s generated wi th the fol l owi ng functi on:
generated coordi nate = p
1
’x
e
+ p
2
’y
e
+ p
3
’z
e
+ p
4
’w
e
where (p
1
’ p
2
’ p
3
’ p
4
’) = (p
1
p
2
p
3
p
4
)M−1
I n thi s case, (x
e
, y
e
, z
e
, w
e
) are the eye coordi nates of the vertex, and p
1
, ..., p
4
are suppl i ed as the param
argument to glTexGen*() wi th pnameset to GL_EYE_PLANE. The pri med val ues are cal cul ated onl y
once, at the ti me they’re speci fi ed, so thi s operati on i sn’t as computati onal l y expensi ve as i t l ooks. To
see the effect of thi s functi on, i n the exampl e above, change sgenparams back to {1, 0, 0, 0}, and change
GL_OBJECT_LI NEAR to GL_EYE_LI NEAR. The resul t i s red stri pes paral l el to the y−z pl ane from
the eye’s poi nt of vi ew, as shown i n Figure J −25.
200
I n al l these exampl es, a si ngl e texture coordi nate i s used to generate contours. The s and t texture
coordi nates can be generated i ndependentl y, however, to i ndi cate the di stances to two di fferent pl anes.
Wi th a properl y constructed two−di mensi onal texture map, the resul ti ng two sets of contours can be
vi ewed si mul taneousl y. For an added l evel of compl exi ty, you can cal cul ate the s coordi nate usi ng
GL_OBJECT_LI NEAR and the t coordi nate usi ng GL_EYE_LI NEAR.
Environment Mapping
The goal of envi ronment mappi ng i s to render an object as i f i t were perfectl y refl ecti ve, so that the
col ors on i ts surface are those refl ected to the eye from i ts surroundi ngs. I n other words, i f you l ook at a
perfectl y pol i shed, perfectl y refl ecti ve si l ver object i n a room, you see the wal l s, fl oor, and other objects
i n the room refl ected off the object. The objects whose refl ecti ons you see depend on the posi ti on of your
eye and on the posi ti on and surface angl es of the si l ver object. To perform envi ronment mappi ng, al l
you have to do i s create an appropri ate texture map and then have OpenGL generate the texture
coordi nates for you.
Envi ronment mappi ng i s an approxi mati on based on the assumpti on that the i tems i n the envi ronment
are far away compared to the surfaces of the shi ny objectthat i s, i t’s a smal l object i n a l arge room.
Wi th thi s assumpti on, to fi nd the col or of a poi nt on the surface, take the ray from the eye to the
surface, and refl ect the ray off the surface. The di recti on of the refl ected ray compl etel y determi nes the
col or to be pai nted there. Encodi ng a col or for each di recti on on a fl at texture map i s equi val ent to
putti ng a pol i shed perfect sphere i n the mi ddl e of the envi ronment and taki ng a pi cture of i t wi th a
camera that has a l ens wi th a very l ong focal l ength pl aced far away. Mathemati cal l y, the l ens has an
i nfi ni te focal l ength and the camera i s i nfi ni tel y far away. The encodi ng therefore covers a ci rcul ar
regi on of the texture map, tangent to the top, bottom, l eft, and ri ght edges of the map. The texture
val ues outsi de the ci rcl e make no di fference, as they are never accessed i n envi ronment mappi ng.
To make a perfectl y correct envi ronment texture map, you need to obtai n a l arge si l vered sphere, take
a photograph of i t i n some envi ronment wi th a camera l ocated an i nfi ni te di stance away and wi th a
l ens that has an i nfi ni te focal l ength, and scan i n the photograph. To approxi mate thi s resul t, you can
use a scanned−i n photograph of an envi ronment taken wi th an extremel y wi de−angl e (or fi sh−eye) l ens.
Figure J −28 shows a photograph taken wi th a such a l ens and the resul ts when that i mage i s used as
an envi ronment map.
Once you’ve created a texture desi gned for envi ronment mappi ng, you need to i nvoke OpenGL’s
envi ronment−mappi ng al gori thm. Thi s al gori thm fi nds the poi nt on the surface of the sphere wi th the
same tangent surface as the poi nt on the object bei ng rendered, and i t pai nts the object’s poi nt wi th the
col or vi si bl e on the sphere at the correspondi ng poi nt. Programmati cal l y, al l you need to do i s change
these l i nes from Example 9−3:
glTexGenfv(GL_S, GL_OBJECT_LINEAR, sgenparams);
glEnable(GL_TEXTURE_GEN_S);
to:
glTexGenfv(GL_S, GL_SPHERE_MAP, 0);
glTexGenfv(GL_T, GL_SPHERE_MAP, 0);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
The GL_SPHERE_MAP constant i s what i nvokes the envi ronment mappi ng. As shown, you need to
speci fy i t for both the s and t di recti ons. You don’t have to speci fy any parameters for the
texture−coordi nate generati on functi on, however.
Advanced Features
201
Advanced
Thi s secti on descri bes how to mani pul ate the texture matri x stack and how to use the q coordi nate.
Both techni ques are consi dered advanced, si nce you don’t need them for many appl i cati ons of texture
mappi ng.
The Texture Matrix Stack
Just as your model coordi nates are transformed by a matri x before bei ng rendered, texture coordi nates
are mul ti pl i ed by a 4 × 4 matri x before any texture mappi ng occurs. By defaul t, the texture matri x i s
the i denti ty, so the texture coordi nates you expl i ci tl y assi gn or those that are automati cal l y generated
remai n unchanged. By modi fyi ng the texture matri x whi l e redrawi ng an object, however, you can make
the texture sl i de over the surface, rotate around i t, stretch and shri nk, or any combi nati on of the three.
I n fact, si nce the texture matri x i s a compl etel y general 4 × 4 matri x, effects such as perspecti ve can be
achi eved.
When the four texture coordi nates (s, t, r, q) are mul ti pl i ed by the texture matri x, the resul ti ng vector (
s’ t’ r’ q’) i s i nterpreted as homogeneous texture coordi nates. I n other words, the texture map i s i ndexed
by s’/ q’ and t’/ q’ . (Remember that r’/ q’ i s currentl y i gnored, but i t mi ght be used i n the future.) The
texture matri x i s actual l y the top matri x on a stack whose depth must be at l east two. Al l the standard
matri x−mani pul ati on commands such as glPushMatrix(), glPopMatrix(), glMultMatrix(), and glRotate()
can be appl i ed to the texture matri x. To modi fy the current texture matri x, you need to set the matri x
mode to GL_TEXTURE, as fol l ows:
glMatrixMode(GL_TEXTURE); /* enter texture matrix mode */
glRotate(...);
/* ... other matrix manipulations ... */
glMatrixMode(GL_MODELVIEW); /* back to modelview mode */
The q Coordinate
The mathemati cs of the q coordi nate i n a general four−di mensi onal texture coordi nate i s as descri bed i n
the previ ous secti on. You can make use of q i n cases where more than one projecti on or perspecti ve
transformati on i s needed.
For exampl e, suppose you want to model a spotl i ght that has some nonuni form patternbri ghter i n
the center, perhaps, or nonci rcul ar, because of fl aps or l enses that modi fy the shape of the beam. You
can emul ate shi ni ng such a l i ght on a fl at surface by maki ng a texture map that corresponds to the
shape and i ntensi ty of a l i ght, and then projecti ng i t on the surface i n questi on usi ng projecti on
transformati ons. Projecti ng the cone of l i ght onto surfaces i n the scene requi res a perspecti ve
transformati on (q≠ 1), si nce the l i ghts mi ght shi ne on surfaces that aren’t perpendi cul ar to them. A
second perspecti ve transformati on occurs because the vi ewer sees the scene from a di fferent (but
perspecti ve) poi nt of vi ew. See Figure J −37 for an exampl e, and see "Fast Shadows and Li ghti ng
Effects Usi ng Texture Mappi ng" by Mark Segal , Carl Korobki n, Rol f van Wi denfel t, Ji m Foran, and
Paul Haeberl i , SI GGRAPH 1992 Proceedi ngs, (Computer Graphics, 26:2, Jul y 1992, p. 249−252) for
more detai l s.
Another exampl e mi ght ari se i f the texture map to be appl i ed comes from a photograph that i tsel f was
taken i n perspecti ve. I n the same way as for spotl i ghts, the fi nal vi ew depends on the combi nati on of
two perspecti ve transformati ons.
Chapter 10
The Framebuffer
Chapter Objectives
202
After readi ng thi s chapter, you’l l be abl e to do the fol l owi ng:
• Understand what buffers make up the framebuffer and how they’re used
• Cl ear sel ected buffers and enabl e them for wri ti ng
• Control the parameters of the sci ssori ng, al pha, stenci l , and depth−buffer tests that are appl i ed to
pi xel s
• Perform di theri ng and l ogi cal operati ons
• Use the accumul ati on buffer for such purposes as scene anti al i asi ng
An i mportant goal of al most every graphi cs program i s to draw pi ctures on the screen. The screen i s
composed of a rectangul ar array of pi xel s, each capabl e of di spl ayi ng a ti ny square of col or at that poi nt
i n the i mage. To draw these pi xel s, you need to know what col or they are, whi ch i s the i nformati on
that’s stored i n the col or buffer. Whenever data i s stored uni forml y for each pi xel , such storage for al l
the pi xel s i s cal l ed a buffer. Di fferent buffers mi ght contai n di fferent amounts of data per pi xel , but
wi thi n a gi ven buffer, each pi xel i s assi gned the same amount of data. A buffer that stores a si ngl e bi t
of i nformati on about pi xel s i s cal l ed a bi tpl ane.
As shown i n Figure 10−1, the l ower l eft pi xel i n an OpenGL wi ndow i s pi xel (0, 0), correspondi ng to
the wi ndow coordi nates of the l ower l eft corner of the 1×1 regi on occupi ed by thi s pi xel . I n general ,
pi xel (x, y) fi l l s the regi on bounded by x on the l eft, x+1 on the ri ght, y on the bottom, and y+1 on the
top.
Figure 10−1 The Regi on Occupi ed by a Pi xel
As an exampl e of a buffer, l et’s l ook more cl osel y at the col or buffer, whi ch hol ds the col or i nformati on
that’s to be di spl ayed on the screen. Assume that the screen i s 1280 pi xel s wi de and 1024 pi xel s hi gh
and that i t’s a ful l 24−bi t col or screeni n other words, there are 2
24
(or 16,777,216) di fferent col ors
that can be di spl ayed. Si nce 24 bi ts transl ates to three bytes (8 bi ts/byte), the col or buffer i n thi s
exampl e has to store at l east three bytes of data for each of the 1024*1280 (= 1,310,720) pi xel s on the
screen. A parti cul ar hardware system mi ght have more or fewer pi xel s on the physi cal screen as wel l as
more or l ess col or data per pi xel . Any parti cul ar col or buffer, however, has the same amount of data
saved for each pi xel on the screen.
The col or buffer i s onl y one of several buffers that hol d i nformati on about a pi xel . I n "Hidden−Surface
Removal Survival Kit," for exampl e, you l earned that the depth buffer hol ds depth i nformati on for
203
each pi xel . The col or buffer i tsel f can consi st of several subbuffers. The framebuffer on a system
compri ses al l of these buffers. Wi th the excepti on of the col or buffer(s), you don’t vi ew these other
buffers di rectl y; i nstead, you use them to perform such tasks as hi dden−surface el i mi nati on,
anti al i asi ng of an enti re scene, stenci l i ng, drawi ng smooth moti on, and other operati ons.
Thi s chapter descri bes al l the buffers that can exi st i n an OpenGL i mpl ementati on and how they’re
used. I t al so di scusses the seri es of tests and pi xel operati ons that are performed before any data i s
wri tten to the vi ewabl e col or buffer. Fi nal l y, i t expl ai ns how to use the accumul ati on buffer, whi ch i s
used to accumul ate i mages that are drawn i nto the col or buffer. Thi s chapter has the fol l owi ng major
secti ons:
• "Buffers and Their Uses"descri bes the possi bl e buffers, what they’re for, and how to cl ear them
and enabl e them for wri ti ng.
• "Testing and Operating on Fragments"expl ai ns the sci ssori ng, al pha, stenci l , and depth−buffer
tests that occur after a pi xel ’s posi ti on and col or have been cal cul ated but before thi s i nformati on i s
drawn on the screen. Several operati onsbl endi ng, di theri ng, and l ogi cal operati onscan al so be
performed before a fragment updates the screen.
• "The Accumulation Buffer"descri bes how to perform several advanced techni ques usi ng the
accumul ati on buffer. These techni ques i ncl ude anti al i asi ng an enti re scene, usi ng moti on bl ur, and
si mul ati ng photographi c depth of fi el d.
Buffers and Their Uses
An OpenGL system can mani pul ate the fol l owi ng buffers:
• Col or buffers: front−l eft, front−ri ght, back−l eft, back−ri ght, and any number of auxi l i ary col or
buffers
• Depth buffer
• Stenci l buffer
• Accumul ati on buffer
Your parti cul ar OpenGL i mpl ementati on determi nes whi ch buffers are avai l abl e and how many bi ts
per pi xel each hol ds. Addi ti onal l y, you can have mul ti pl e vi sual s, or wi ndow types, that have di fferent
buffers avai l abl e. At a mi ni mum, you’re guaranteed to have one col or buffer for use i n RGBA mode wi th
associ ated stenci l , depth, and accumul ati on buffers that have col or components of nonzero si ze, and one
col or buffer for use i n col or−i ndex mode wi th associ ated depth and stenci l buffers. Table 10−1 l i sts the
parameters to use wi th glGetI ntegerv() to query your OpenGL system about per−pi xel buffer storage for
a parti cul ar vi sual . I f you’re usi ng the X Wi ndow System, you’l l probabl y want to use glXGetConfig() to
query your vi sual s; see Appendix D and the OpenGL ReferenceManual for more i nformati on about
thi s routi ne.
Parameter Meaning
GL_RED_BITS, GL_GREEN_BITS,
GL_BLUE_BITS, GL_ALPHA_BITS
Number of bits per R, G, B, or A component in the color
buffers
GL_DEPTH_BITS Number of bits per pixel in the depth buffer
GL_STENCIL_BITS Number of bits per pixel in the stencil buffer
GL_ACCUM_RED_BITS,
GL_ACCUM_GREEN_BITS,
GL_ACCUM_BLUE_BITS,
GL_ACCUM_ALPHA_BITS
Number of bits per R, G, B, or A component in the
accumulation buffer
Table 10−1 Query Parameters for Per−Pi xel Buffer Storage
Color Buffers
The col or buffers are usual l y the ones you draw to. They contai n ei ther col or−i ndex or RGB col or data
and may al so contai n al pha val ues. An OpenGL i mpl ementati on that supports stereoscopi c vi ewi ng has
l eft and ri ght col or buffers for the l eft and ri ght stereo i mages. I f stereo i sn’t supported, onl y the l eft
204
l eft and ri ght col or buffers for the l eft and ri ght stereo i mages. I f stereo i sn’t supported, onl y the l eft
buffers are used. Si mi l arl y, doubl e−buffered systems have front and back buffers, and a
si ngl e−buffered system has the front buffers onl y. Every OpenGL i mpl ementati on must provi de a
front−l eft col or buffer.
Up to four opti onal , nondi spl ayabl e auxi l i ary col or buffers can al so be supported. OpenGL doesn’t
speci fy any parti cul ar uses for these buffers, so you can defi ne and use them however you pl ease. For
exampl e, you mi ght use them for savi ng an i mage that you use repeatedl y; rather than redrawi ng the
i mage, you can just copy i t i nto the usual col or buffers. See the descri pti on of glCopyPixels() i n
"Reading, Writing, and Copying Pixel Data" for more i nformati on about how to do thi s.
You can use GL_STEREO or GL_DOUBLE_BUFFER wi th glGetBooleanv() to fi nd out i f your system
supports stereo (that i s, has l eft and ri ght buffers) or doubl e−bufferi ng (has front and back buffers). To
fi nd out how many auxi l i ary buffers are present, use glGetI ntegerv() wi th GL_AUX_BUFFERS.
Depth Buffer
The depth buffer stores a depth val ue for each pi xel . As descri bed i n "Hidden−Surface Removal
Survival Kit" depth i s usual l y measured i n terms of di stance to the eye, so pi xel s wi th l arger
depth−buffer val ues are overwri tten by pi xel s wi th smal l er val ues. Thi s i s just a useful conventi on,
however, and the depth buffer’s behavi or can be modi fi ed as descri bed i n "Depth Test." The depth
buffer i s someti mes cal l ed the z buffer (the z comes from the fact that x and y val ues measure hori zontal
and verti cal di spl acement on the screen, and the z val ue measures di stance perpendi cul ar to the
screen).
Stencil Buffer
One use for the stenci l buffer i s to restri ct drawi ng to certai n porti ons of the screen, just as a cardboard
stenci l can be used wi th a can of spray pai nt to make fai rl y preci se pai nted i mages. For exampl e, i f you
want to draw an i mage as i t woul d appear through an odd−shaped wi ndshi el d, you can store an i mage
of the wi ndshi el d’s shape i n the stenci l buffer, and then draw the enti re scene. The stenci l buffer
prevents anythi ng that woul dn’t be vi si bl e through the wi ndshi el d from bei ng drawn. Thus, i f your
appl i cati on i s a dri vi ng si mul ati on, you can draw al l the i nstruments and other i tems i nsi de the
automobi l e once, and as the car moves, onl y the outsi de scene need be updated.
Accumulation Buffer
The accumul ati on buffer hol ds RGBA col or data just l i ke the col or buffers do i n RGBA mode. (The
resul ts of usi ng the accumul ati on buffer i n col or−i ndex mode are undefi ned.) I t’s typi cal l y used for
accumul ati ng a seri es of i mages i nto a fi nal , composi te i mage. Wi th thi s method, you can perform
operati ons l i ke scene anti al i asi ng by supersampl i ng an i mage and then averagi ng the sampl es to
produce the val ues that are fi nal l y pai nted i nto the pi xel s of the col or buffers. You don’t draw di rectl y
i nto the accumul ati on buffer; accumul ati on operati ons are al ways performed i n rectangul ar bl ocks,
usual l y transfers of data to or from a col or buffer.
Clearing Buffers
I n graphi cs programs, cl eari ng the screen (or any of the buffers) i s typi cal l y one of the most expensi ve
operati ons you can performon a 1280 by 1024 moni tor, i t requi res touchi ng wel l over a mi l l i on pi xel s.
For si mpl e graphi cs appl i cati ons, the cl ear operati on can take more ti me than the rest of the drawi ng.
I f you need to cl ear not onl y the col or buffer but al so the depth and stenci l buffers, say, the cl ear
operati on can be three ti mes as expensi ve.
To address thi s probl em, some machi nes have hardware that can cl ear more than one buffer at once.
The OpenGL cl eari ng commands are structured to take advantage of archi tectures l i ke thi s. Fi rst, you
speci fy the val ues to be wri tten i nto each buffer to be cl eared. Then you i ssue a si ngl e command to
perform the cl ear operati on, passi ng i n a l i st of al l the buffers to be cl eared. I f the hardware i s capabl e
205
of si mul taneous cl ears, they al l occur at once; otherwi se, each buffer i s cl eared sequenti al l y.
The fol l owi ng commands set the cl eari ng val ues for each buffer.
voi d glClearColor(GLcl ampf red, GLcl ampf green, GLcl ampf blue, GLcl ampf alpha);
voi d glClearI ndex(GLfl oat index);
voi d glClearDepth(GLcl ampd depth);
voi d glClearStencil(GLi nt s);
voi d glClearAccum(GLfl oat red, GLfl oat green, GLfl oat blue, GLfl oat alpha);
Speci fi es the current cl eari ng val ues for the col or buffer (i n RGBA mode), the col or buffer (i n
col or−i ndex mode), the depth buffer, the stenci l buffer, and the accumul ati on buffer. The GLcl ampf and
GLcl ampd types (cl amped GLfl oat and cl amped GLdoubl e) are cl amped to be between 0.0 and 1.0. The
defaul t depth−cl eari ng val ue i s 1.0; al l the other defaul t cl eari ng val ues are 0. The val ues set wi th the
cl ear commands remai n i n effect unti l they’re changed by another cal l to the same command.
After you’ve sel ected your cl eari ng val ues and you’re ready to cl ear the buffers, use glClear().
voi d glClear(GLbi tfi el d mask);
Cl ears the speci fed buffers. The val ue of mask i s the bi twi se l ogi cal OR of some combi nati on of
GL_COLOR_BUFFER_BI T, GL_DEPTH_BUFFER_BI T, GL_STENCI L_BUFFER_BI T, and
GL_ACCUM_BUFFER_BI T, to i denti fy whi ch buffers are to be cl eared. GL_COLOR_BUFFER_BI T
cl ears ei ther the RGBA col or or the col or−i ndex buffer, dependi ng on the mode of the system at the
ti me. When you cl ear the col or or col or−i ndex buffer, al l the col or buffers that are enabl ed for wri ti ng
(see the next secti on) are cl eared.
Selecting Color Buffers for Writing
The resul ts of a drawi ng operati on can go i nto any of the col or buffers: front, back, front−l eft, back−l eft,
front−ri ght, back−ri ght, or any of the auxi l i ary buffers. You can choose an i ndi vi dual buffer to be the
drawi ng target, or you can al so set the target to be a combi nati on of these buffers. I n a doubl e−buffered
appl i cati on, for exampl e, you mi ght want to draw a common background i nto both the back and front
buffers; from then on, you want to draw onl y i n the back buffer (and swap the buffers when you’re
fi ni shed drawi ng). I n some cases, however, you mi ght want to treat part of a parti cul ar
doubl e−buffered wi ndow as though i t were si ngl e−buffered by drawi ng to both front and back buffers.
You use the glDrawBuffer() command to sel ect the buffers to be wri tten.
voi d glDrawBuffer(GLenum mode);
Sel ects the buffers enabl ed for wri ti ng or cl eari ng. The val ue of modecan be one of the fol l owi ng:
GL_FRONT
GL_BACK
GL_RI GHT
GL_LEFT
GL_FRONT_RI GHT
GL_FRONT_LEFT
GL_BACK_RI GHT
GL_BACK_LEFT
GL_AUXi
GL_FRONT_AND_BACK
GL_NONE
Arguments that omi t RI GHT or LEFT refer to both the l eft and ri ght buffers; si mi l arl y, arguments that
omi t FRONT or BACK refer to both. The i i n GL_AUXi i s a di gi t i denti fyi ng a parti cul ar auxi l i ary
buffer.
Note: You can enabl e drawi ng to nonexi stent buffers as l ong as you enabl e drawi ng to at l east one
206
buffer that does exi st. I f none of the speci fi ed buffers exi st, an error resul ts.
Masking Buffers
Before OpenGL wri tes data i nto the enabl ed col or, depth, or stenci l buffers, a maski ng operati on i s
appl i ed to the data, as speci fi ed wi th one of the fol l owi ng commands. A bi twi se l ogi cal AND i s
performed wi th each mask and the correspondi ng data to be wri tten.
voi d glI ndexMask(GLui nt mask);
voi d glColorMask(GLbool ean red, GLbool ean green, GLbool ean blue, GLbool ean alpha);
voi d glDepthMask(GLbool ean flag);
voi d glStencilMask(GLui nt mask);
Sets the masks used to control wri ti ng i nto the i ndi cated buffers. The mask set by glI ndexMask()
appl i es onl y i n col or−i ndex mode. I f a 1 appears i n mask, the correspondi ng bi t i n the col or−i ndex buffer
i s wri tten; where a 0 appears, the bi t i sn’t wri tten. Si mi l arl y, glColorMask() affects drawi ng i n RGBA
mode onl y. The red, green, blue, and alpha val ues control whether the correspondi ng component i s
wri tten. (GL_TRUE means i t i s wri tten.) I f flagi s GL_TRUE for glDepthMask(), the depth buffer i s
enabl ed for wri ti ng; otherwi se, i t’s di sabl ed. The mask for glStencilMask() i s used for stenci l data i n the
same way as the mask i s used for col or−i ndex data i n glI ndexMask(). The defaul t val ues of al l the
GLbool ean masks are GL_TRUE, and the defaul t val ues for the two GLui nt masks are al l 1s.
You can do pl enty of tri cks wi th col or maski ng i n col or−i ndex mode. For exampl e, you can use each bi t
i n the i ndex as a di fferent l ayer, and set up i nteracti ons between arbi trary l ayers wi th appropri ate
setti ngs of the col or map. You can create overl ays and underl ays, and do so−cal l ed col or−map
ani mati ons. See Chapter 13 for exampl es of usi ng col or maski ng. Maski ng i n RGBA mode i s useful
l ess often, but you can use i t for l oadi ng separate i mage fi l es i nto the red, green, and bl ue bi tpl anes, for
exampl e.
You’ve seen one use for di sabl i ng the depth buffer i n "Three−Dimensional Blending with the
Depth Buffer." Di sabl i ng the depth buffer for wri ti ng can al so be useful i f a common background i s
desi red for a seri es of frames, and you want to add some features that may be obscured by parts of the
background. For exampl e, suppose your background i s a forest, and you woul d l i ke to draw repeated
frames wi th the same trees, but wi th objects movi ng among them. After the trees are drawn wi th thei r
depths recorded i n the depth buffer, then the i mage of the trees i s saved, and the new i tems are drawn
wi th the depth buffer di sabl ed for wri ti ng. As l ong as the new i tems don’t overl ap each other, the
pi cture i s correct. To draw the next frame, restore the i mage of the trees and conti nue. You don’t need
to restore the val ues i n the depth buffer. Thi s tri ck i s most useful i f the background i s extremel y
compl exso compl ex that i t’s much faster just to recopy the i mage i nto the col or buffer than to
recompute i t from the geometry.
Maski ng the stenci l buffer can al l ow you to use a mul ti pl e−bi t stenci l buffer to hol d mul ti pl e stenci l s
(one per bi t). You mi ght use thi s techni que to perform cappi ng as expl ai ned i n "Stencil Test" or to
i mpl ement the Game of Li fe as descri bed i n "Life in the Stencil Buffer."
Note: The mask speci fi ed by glStencilMask() control s whi ch stenci l bi tpl anes are wri tten. Thi s mask
i sn’t rel ated to the mask that’s speci fi ed as the thi rd parameter of glStencilFunc(), whi ch
speci fi es whi ch bi tpl anes are consi dered by the stenci l functi on.
Testing and Operating on Fragments
When you draw geometry, text, or i mages on the screen, OpenGL performs several cal cul ati ons to
rotate, transl ate, scal e, determi ne the l i ghti ng, project the object(s) i nto perspecti ve, fi gure out whi ch
pi xel s i n the wi ndow are affected, and determi ne what col ors those pi xel s shoul d be drawn. Many of the
207
earl i er chapters i n thi s book gi ve some i nformati on about how to control these operati ons. After
OpenGL determi nes that an i ndi vi dual fragment shoul d be generated and what i ts col or shoul d be,
several processi ng stages remai n that control how and whether the fragment i s drawn as a pi xel i nto
the framebuffer. For exampl e, i f i t’s outsi de the wi ndow or i f i t’s farther from the vi ewpoi nt than the
pi xel that’s al ready i n the framebuffer, i t i sn’t drawn. I n another stage, the fragment’s col or i s bl ended
wi th the col or of the pi xel al ready i n the framebuffer.
Thi s secti on descri bes both the compl ete set of tests that a fragment must pass before i t goes i nto the
framebuffer and the possi bl e fi nal operati ons that can be performed on the fragment as i t’s wri tten. The
tests and operati ons occur i n the fol l owi ng order; i f a fragment i s el i mi nated i n an earl y test, none of
the l ater tests or operati ons take pl ace.
1. Sci ssor test
2. Al pha test
3. Stenci l test
4. Depth test
5. Bl endi ng
6. Di theri ng
7. Logi cal operati on
Each of these tests and operati ons i s descri bed i n detai l i n the fol l owi ng secti ons.
Scissor Test
You can defi ne a rectangul ar porti on of your wi ndow and restri ct drawi ng to take pl ace wi thi n i t by
usi ng the glScissor() command. I f a fragment l i es i nsi de the rectangl e, i t passes the sci ssor test.
voi d glScissor(GLi nt x, GLi nt y, GLsi zei width, GLsi zei height);
Sets the l ocati on and si ze of the sci ssor rectangl e. The parameters defi ne the l ower l eft corner (x, y),
and the wi dth and hei ght of the rectangl e. Pi xel s that l i e i nsi de the rectangl e pass the sci ssor test.
Sci ssori ng i s enabl ed and di sabl ed by passi ng GL_SCI SSOR to glEnable() and glDisable(). By defaul t,
the rectangl e matches the si ze of the wi ndow and sci ssori ng i s di sabl ed.
The sci ssor test i s just a versi on of a stenci l test usi ng a rectangul ar regi on of the screen. I t’s fai rl y easy
to create a bl i ndi ngl y fast hardware i mpl ementati on of sci ssori ng, whi l e a gi ven system mi ght be much
sl ower at stenci l i ngperhaps because the stenci l i ng i s performed i n software.
Advanced
As an advanced use of sci ssori ng, you mi ght use i t to perform nonl i near projecti on. Fi rst, di vi de the
wi ndow i nto a regul ar gri d of subregi ons, speci fyi ng vi ewport and sci ssor parameters that l i mi t
renderi ng to one regi on at a ti me. Then project the enti re scene to each regi on usi ng a di fferent
projecti on matri x.
You can use GL_SCI SSOR_TEST wi th glI sEnabled() and GL_SCI SSOR_BOX wi th glGetI ntegerv() to
determi ne whether sci ssori ng i s enabl ed and to obtai n the val ues that defi ne the sci ssor rectangl e.
Alpha Test
I n RGBA mode, the al pha test al l ows you to accept or reject a fragment based on i ts al pha val ue. I f
enabl ed, the test compares the i ncomi ng al pha val ue wi th a reference val ue. The fragment i s accepted
or rejected dependi ng on the resul t of the compari son. Both the reference val ue and the compari son
functi on are set wi th glAlphaFunc(). To determi ne whether the al pha test i s enabl ed and to obtai n the
reference val ue and the compari son functi on, use GL_ALPHA_TEST wi th glI sEnabled() and
GL_ALPHA_TEST_FUNC or GL_ALPHA_TEST_REF wi th glGetI ntegerv().
208
voi d glAlphaFunc(GLenum func, GLcl ampf ref);
Sets the reference val ue and compari son functi on for the al pha test. The reference val ue ref i s cl amped
to be between 0 and 1. The possi bl e val ues for funcand thei r meani ng are l i sted i n Table 10−2 .
Parameter Meaning
GL_NEVER Never accept the fragment
GL_ALWAYS Always accept the fragment
GL_LESS Accept fragment if fragment alpha < reference alpha
GL_LEQUAL Accept fragment if fragment alpha ≤ reference alpha
GL_EQUAL Accept fragment if fragment alpha = reference alpha
GL_GEQUAL Accept fragment if fragment alpha ≥ reference alpha
GL_GREATER Accept fragment if fragment alpha > reference alpha
GL_NOTEQUAL Accept fragment if fragment alpha ≠ reference alpha
Table 10−2 Parameter Val ues for Use wi th gl Al phaFunc()
The al pha test i s enabl ed and di sabl ed by passi ng GL_ALPHA_TEST to glEnable() and glDisable(). By
defaul t, the reference val ue i s zero, the compari son functi on i s GL_ALWAYS, and the al pha test i s
di sabl ed.
One appl i cati on for the al pha test i s to i mpl ement a transparency al gori thm. Render your enti re scene
twi ce, the fi rst ti me accepti ng onl y fragments wi th al pha val ues of one, and the second ti me accepti ng
fragments wi th al pha val ues that aren’t equal to one. Turn the depth buffer on duri ng both passes, but
di sabl e depth buffer wri ti ng duri ng the second pass.
Another use mi ght be to make decal s wi th texture maps where you can see through certai n parts of the
decal s. Set the al phas i n the decal s to 0.0 where you want to see through, set them to 1.0 otherwi se, set
the reference val ue to 0.5 (or anythi ng between 0.0 and 1.0), and set the compari son functi on to
GL_GREATER. The decal has see−through parts, and the val ues i n the depth buffer aren’t affected.
Thi s techni que, cal l ed bi l l boardi ng, i s descri bed i n "Sample Uses of Blending."
Stencil Test
The stenci l test takes pl ace onl y i f there i s a stenci l buffer. (I f there i s no stenci l buffer, the stenci l test
al ways passes.) Stenci l i ng appl i es a test that compares a reference val ue wi th the val ue stored at a
pi xel i n the stenci l buffer. Dependi ng on the resul t of the test, the val ue i n the stenci l buffer i s modi fi ed.
You can choose the parti cul ar compari son functi on used, the reference val ue, and the modi fi cati on
performed wi th the glStencilFunc() and glStencilOp() commands.
voi d glStencilFunc(GLenum func, GLi nt ref, GLui nt mask);
Sets the compari son functi on (func), reference val ue (ref), and a mask (mask) for use wi th the stenci l
test. The reference val ue i s compared to the val ue i n the stenci l buffer usi ng the compari son functi on,
but the compari son appl i es onl y to those bi ts where the correspondi ng bi ts of the mask are 1. The
functi on can be GL_NEVER, GL_ALWAYS, GL_LESS, GL_LEQUAL, GL_EQUAL, GL_GEQUAL,
GL_GREATER, or GL_NOTEQUAL. I f i t’s GL_LESS, for exampl e, then the fragment passes i f ref i s
l ess than the val ue i n the stenci l buffer. I f the stenci l buffer contai ns s bi tpl anes, the l ow−order s bi ts of
mask are bi twi se ANDed wi th the val ue i n the stenci l buffer and wi th the reference val ue before the
compari son i s performed. The masked val ues are al l i nterpreted as nonnegati ve val ues. The stenci l test
i s enabl ed and di sabl ed by passi ng GL_STENCI L_TEST to glEnable() and glDisable(). By defaul t, func
i s GL_ALWAYS, ref i s 0, mask i s al l 1s, and stenci l i ng i s di sabl ed.
voi d glStencilOp(GLenum fail, GLenum zfail, GLenum zpass);
Speci fi es how the data i n the stenci l buffer i s modi fi ed when a fragment passes or fai l s the stenci l test.
The three functi ons fail, zfail, and zpasscan be GL_KEEP, GL_ZERO, GL_REPLACE, GL_I NCR,
GL_DECR, or GL_I NVERT. They correspond to keepi ng the current val ue, repl aci ng i t wi th zero,
209
repl aci ng i t wi th the reference val ue, i ncrementi ng i t, decrementi ng i t, and bi twi se−i nverti ng i t. The
resul t of the i ncrement and decrement functi ons i s cl amped to l i e between 0 and the maxi mum
unsi gned i nteger val ue (2
s
−1 i f the stenci l buffer hol ds s bi ts). The fail functi on i s appl i ed i f the
fragment fai l s the stenci l test; i f i t passes, then zfail i s appl i ed i f the depth test fai l s and zpassi f the
depth test passes, or i f no depth test i s performed. (See "Depth Test.") By defaul t, al l three stenci l
operati ons are GL_KEEP.
Stencil Queries
You can obtai n the val ues for al l si x stenci l −rel ated parameters by usi ng the query functi on
glGetI ntegerv() and one of the val ues shown i n Table 10−3 . You can al so determi ne whether the stenci l
test i s enabl ed by passi ng GL_STENCI L_TEST to glI sEnabled().
Query Value Meaning
GL_STENCIL_FUNC Stencil function
GL_STENCIL_REF Stencil reference value
GL_STENCIL_VALUE_MASK Stencil mask
GL_STENCIL_FAIL Stencil fail action
GL_STENCIL_PASS_DEPTH_FAIL Stencil pass and depth buffer fail action
GL_STENCIL_PASS_DEPTH_PASS Stencil pass and depth buffer pass action
Table 10−3 Query Val ues for the Stenci l Test
Stencil Examples
Probabl y the most typi cal use of the stenci l test i s to mask out an i rregul arl y shaped regi on of the
screen to prevent drawi ng from occurri ng wi thi n i t (as i n the wi ndshi el d exampl e i n "Buffers and
Their Uses"). To do thi s, fi l l the stenci l mask wi th 0, and then draw the desi red shape i n the stenci l
buffer wi th 1. You can’t draw di rectl y i nto the stenci l buffer, but you can achi eve the same resul t by
drawi ng i nto the col or buffer and choosi ng a sui tabl e val ue for the zpassfuncti on (such as
GL_REPLACE). Whenever drawi ng occurs, a val ue i s al so wri tten i nto the stenci l buffer (i n thi s case,
the reference val ue). To prevent the stenci l −buffer drawi ng from affecti ng the contents of the col or
buffer, set the col or mask to zero (or GL_FALSE). You mi ght al so want to di sabl e wri ti ng i nto the depth
buffer.
After you’ve defi ned the stenci l area, set the reference val ue to 1, and the compari son functi on such
that the fragment passes i f the reference val ue i s equal to the stenci l −pl ane val ue. Duri ng drawi ng,
don’t modi fy the contents of the stenci l pl anes.
Example 10−1 demonstrates how to use the stenci l test i n thi s way. Two tori are drawn, wi th a
di amond−shaped cutout i n the center of the scene. Wi thi n the di amond−shaped stenci l mask, a sphere
i s drawn. I n thi s exampl e, drawi ng i nto the stenci l buffer takes pl ace onl y when the wi ndow i s redrawn,
so the col or buffer i s cl eared after the stenci l mask has been created.
Example 10−1 Usi ng the Stenci l Test: stenci l .c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
#define YELLOWMAT 1
#define BLUEMAT 2
void myinit (void)
{
GLfloat yellow_diffuse[] = { 0.7, 0.7, 0.0, 1.0 };
GLfloat yellow_specular[] = { 1.0, 1.0, 1.0, 1.0 };
210
GLfloat blue_diffuse[] = { 0.1, 0.1, 0.7, 1.0 };
GLfloat blue_specular[] = { 0.1, 1.0, 1.0, 1.0 };
GLfloat position_one[] = { 1.0, 1.0, 1.0, 0.0 };
glNewList(YELLOWMAT, GL_COMPILE);
glMaterialfv(GL_FRONT, GL_DIFFUSE, yellow_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, yellow_specular);
glMaterialf(GL_FRONT, GL_SHININESS, 64.0);
glEndList();
glNewList(BLUEMAT, GL_COMPILE);
glMaterialfv(GL_FRONT, GL_DIFFUSE, blue_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, blue_specular);
glMaterialf(GL_FRONT, GL_SHININESS, 45.0);
glEndList();
glLightfv(GL_LIGHT0, GL_POSITION, position_one);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glClearStencil(0x0);
glEnable(GL_STENCIL_TEST);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* draw blue sphere where the stencil is 1 */
glStencilFunc (GL_EQUAL, 0x1, 0x1);
glCallList (BLUEMAT);
auxSolidSphere (0.5);
/* draw the tori where the stencil is not 1 */
glStencilFunc (GL_NOTEQUAL, 0x1, 0x1);
glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
glPushMatrix();
glRotatef (45.0, 0.0, 0.0, 1.0);
glRotatef (45.0, 0.0, 1.0, 0.0);
glCallList (YELLOWMAT);
auxSolidTorus (0.275, 0.85);
glPushMatrix();
glRotatef (90.0, 1.0, 0.0, 0.0);
auxSolidTorus (0.275, 0.85);
glPopMatrix();
glPopMatrix();
}
void myReshape(GLsizei w, GLsizei h)
211
{
glViewport(0, 0, w, h);
glClear(GL_STENCIL_BUFFER_BIT);
/* create a diamond−shaped stencil area */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(−3.0, 3.0, −3.0, 3.0, −1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glStencilFunc (GL_ALWAYS, 0x1, 0x1);
glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE);
glBegin(GL_QUADS);
glVertex3f (−1.0, 0.0, 0.0);
glVertex3f (0.0, 1.0, 0.0);
glVertex3f (1.0, 0.0, 0.0);
glVertex3f (0.0, −1.0, 0.0);
glEnd();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, (GLfloat) w/(GLfloat) h, 3.0, 7.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, −5.0);
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA
| AUX_DEPTH | AUX_STENCIL);
auxInitPosition (0, 0, 400, 400);
auxInitWindow (argv[0]);
myinit ();
auxReshapeFunc (myReshape);
auxMainLoop(display);
}
The fol l owi ng exampl es i l l ustrate other uses of the stenci l test. See Chapter 13 for addi ti onal i deas.
• Cappi ngSuppose you’re drawi ng a cl osed convex object (or several of them, as l ong as they don’t
i ntersect or encl ose each other) made up of several pol ygons, and you have a cl i ppi ng pl ane that
may or may not sl i ce off a pi ece of i t. Suppose that i f the pl ane does i ntersect the object, you want to
cap the object wi th some constant−col ored surface, rather than seei ng the i nsi de of i t. To do thi s,
cl ear the stenci l buffer to 0, and begi n drawi ng wi th stenci l i ng enabl ed and the stenci l compari son
functi on set to al ways accept fragments. I nvert the val ue i n the stenci l pl anes each ti me a fragment
i s accepted. After al l the objects are drawn, regi ons of the screen where no cappi ng i s requi red have
0 i n the stenci l pl anes, and regi ons requi ri ng cappi ng are nonzero. Reset the stenci l functi on so that
i t draws onl y where the stenci l val ue i s nonzero, and draw a l arge pol ygon of the cappi ng col or
across the enti re screen.
• Overl appi ng transl ucent pol ygonsSuppose you have a transl ucent surface that’s made up of
pol ygons that overl ap sl i ghtl y. I f you si mpl y use al pha bl endi ng, porti ons of the underl yi ng objects
are covered by more than one transparent surface, whi ch doesn’t l ook ri ght. Use the stenci l pl anes
212
to make sure that each fragment i s covered by at most one porti on of the transparent surface. Do
thi s by cl eari ng the stenci l pl anes to zero, drawi ng onl y when the stenci l pl ane i s zero, and
i ncrementi ng the val ue i n the stenci l pl ane when you draw.
• Sti ppl i ngSuppose you want to draw an i mage wi th a sti ppl e pattern (see "Displaying Points,
Lines, and Polygons" for more i nformati on about sti ppl i ng). You can do thi s by wri ti ng the
sti ppl e pattern i nto the stenci l buffer, and then drawi ng condi ti onal l y on the contents of the stenci l
buffer. After the ori gi nal sti ppl e pattern i s drawn, the stenci l buffer aren’t al tered whi l e drawi ng
the i mage, so the object gets sti ppl ed by the pattern i n the stenci l pl anes.
Depth Test
For each pi xel on the screen, the depth buffer keeps track of the di stance between the vi ewpoi nt and
the object occupyi ng that pi xel . Then, i f the speci fi ed depth test passes, the i ncomi ng depth val ue
repl aces the one al ready i n the depth buffer.
The depth buffer i s usual l y used for hi dden−surface el i mi nati on. I f a new candi date col or for that pi xel
appears, i t’s drawn onl y i f the correspondi ng object i s cl oser than the previ ous object. I n thi s way, onl y
objects that aren’t obscured by other i tems remai n after the enti re scene has been rendered. Duri ng
i ni ti al i zati on, the depth buffer i s typi cal l y fi l l ed wi th a val ue that’s as far from the vi ewpoi nt as
possi bl e, so any object i s nearer than that. I f thi s i s how you want to use the depth buffer, you si mpl y
have to enabl e i t by passi ng GL_DEPTH_TEST to glEnable() and remember to cl ear the depth buffer
before you redraw each frame (see "Clearing Buffers"). You can al so choose a di fferent compari son
functi on for the depth test wi th glDepthFunc().
voi d glDepthFunc(GLenum func);
Sets the compari son functi on for the depth test. The val ue for funcmust be GL_NEVER, GL_ALWAYS,
GL_LESS, GL_LEQUAL, GL_EQUAL, GL_GEQUAL, GL_GREATER, or GL_NOTEQUAL. An
i ncomi ng fragment passes the depth test i f i ts z val ue has the speci fi ed rel ati on to the val ue al ready
stored i n the depth buffer. The defaul t i s GL_LESS, whi ch means that an i ncomi ng fragment passes
the test i f i ts z val ue i s l ess than that al ready stored i n the depth buffer. I n thi s case, the z val ue
represents the di stance from the object to the vi ewpoi nt, and smal l er val ues mean the correspondi ng
objects are cl oser to the vi ewpoi nt.
Blending, Dithering, and Logical Operations
Once an i ncomi ng fragment has passed al l the tests descri bed i n the previ ous secti on, i t can be
combi ned wi th the current contents of the col or buffer i n one of several ways. The si mpl est way, whi ch
i s al so the defaul t, i s to overwri te the exi sti ng val ues. Al ternati vel y, i f you’re usi ng RGBA mode and
you want the fragment to be transl ucent or anti al i ased, you mi ght average i ts val ue wi th the val ue
al ready i n the buffer (bl endi ng). On systems wi th a smal l number of avai l abl e col ors, you mi ght want to
di ther col or val ues to i ncrease the number of col ors avai l abl e at the cost of a l oss i n resol uti on. Fi nal l y,
i n col or−i ndex mode, you can use arbi trary bi twi se l ogi cal operati ons to combi ne the i ncomi ng fragment
and the pi xel that’s al ready wri tten.
Blending
Bl endi ng combi nes the i ncomi ng fragment’s R, G, B, and al pha val ues wi th those of the pi xel al ready
stored at the l ocati on. Di fferent bl endi ng operati ons can be appl i ed, and the bl endi ng that occurs
depends on the val ues of the i ncomi ng al pha val ue and the al pha val ue (i f any) stored at the pi xel .
Bl endi ng i s di scussed extensi vel y i n "Blending."
Dithering
On systems wi th a smal l number of col or bi tpl anes, you can i mprove the col or resol uti on at the expense
of spati al resol uti on by di theri ng the col or i n the i mage. Di theri ng i s l i ke hal ftoni ng i n newspapers.
Al though a newspaper has onl y two col orsbl ack and whi tei t can show photographs by representi ng
213
the shades of gray wi th combi nati ons of bl ack and whi te dots. Compari ng a newspaper i mage of a photo
(havi ng no shades of gray) wi th the ori gi nal photo (wi th grayscal e) makes the l oss of spati al resol uti on
obvi ous. Si nce even the l owest−qual i ty col or di spl ays typi cal l y have at l east a few di fferent val ues of
red, green, and bl ue avai l abl e (not just two as i n a newspaper), there’s l ess l oss i n spati al resol uti on i n
exchange for a better range of col ors.
The di theri ng operati on that takes pl ace i s hardware−dependent; al l OpenGL al l ows you to do i s to turn
i t on and off. I n fact, on some machi nes, enabl i ng di theri ng mi ght do nothi ng at al l , whi ch makes sense
i f the machi ne al ready has hi gh col or resol uti on. To enabl e and di sabl e di theri ng, pass GL_DI THER to
glEnable() and glDisable(). Di theri ng i s enabl ed by defaul t.
Di theri ng appl i es i n both RGBA and col or−i ndex mode: The col ors or col or i ndi ces al ternate i n some
hardware−dependent way between the two nearest possi bi l i ti es. For exampl e, i n col or−i ndex mode, i f
di theri ng i s enabl ed and the col or i ndex to be pai nted i s 4.4, then si x−tenths of the pi xel s are pai nted
wi th i ndex 4 and four−tenths of the pi xel s wi th i ndex 5. I n RGBA mode, di theri ng i s performed
separatel y for each component (i ncl udi ng al pha). To use di theri ng i n col or−i ndex mode, you general l y
need to arrange the col ors i n the col or map appropri atel y i n ramps, or bi zarre i mages mi ght resul t.
I n RGBA mode, di theri ng i s the fi nal step before the resul ti ng val ues are wri tten i nto the col or buffers;
i n col or−i ndex mode, you can perform one of the l ogi cal operati ons descri bed i n the next secti on.
Logical Operations
I n col or−i ndex mode, the col or i ndi ces can be i nterpreted as i ntegers or as bi t patterns. For shadi ng and
di theri ng, the i nteger i nterpretati on i s usual l y best, but for i mages composed as combi nati ons of
drawi ngs on di fferent l ayersfor i nstance, i f you’re usi ng wri temasks to l i mi t drawi ng to di fferent sets
of bi tpl anesa bi t−pattern i nterpretati on makes more sense. Logi cal operati ons, such as OR or XOR,
are appl i ed to the i ncomi ng fragment val ues and/or those currentl y i n the col or buffer.
Such fragment operati ons are especi al l y useful on bi t−bl t−type machi nes, on whi ch the pri mary
graphi cs operati on i s copyi ng a rectangl e of data from one pl ace i n the wi ndow to another, from the
wi ndow to processor memory, or from memory to the wi ndow. Typi cal l y, the copy doesn’t wri te the data
di rectl y i nto memory but i nstead al l ows you to perform an arbi trary l ogi cal operati on on the i ncomi ng
data and the data al ready present; then i t repl aces the exi sti ng data wi th the resul ts of the operati on.
Si nce thi s process can be i mpl emented fai rl y cheapl y i n hardware, many such machi nes are avai l abl e.
As an exampl e of usi ng a l ogi cal operati on, XOR can be used to draw on an i mage i n an undoabl e way;
si mpl y XOR the same drawi ng agai n, and the ori gi nal i mage i s restored.
You choose among the si xteen l ogi cal operati ons wi th glLogicOp(), and you enabl e and di sabl e l ogi cal
operati ons by passi ng GL_LOGI C_OP to glEnable() and glDisable().
voi d glLogicOp(GLenum opcode);
I n col or−i ndex mode, sel ects the l ogi cal operati on to be performed, gi ven an i ncomi ng (source) fragment
and the pi xel currentl y stored i n the col or buffer (desti nati on). Table 10−4 shows the possi bl e val ues
for opcodeand thei r meani ng (s represents source and d desti nati on). The defaul t val ue i s GL_COPY.
Paramter Operation Parameter Operatio
n
GL_CLEAR 0 GL_AND s ∧ d
GL_COPY s GL_OR s ∨ d
GL_NOOP d GL_NAND ¬(s ∧ d)
GL_SET 1 GL_NOR ¬(s ∨ d)
GL_COPY_INVERTE D ¬s GL_XOR s XOR d
GL_INVERT ¬d GL_EQUIV ¬(s XOR
d)
GL_AND_REVERSE s ∧ ¬d GL_AND_INVERTED ¬s ∧ d
GL_OR_REVERSE s ∨ ¬d GL_OR_INVERTED ¬s ∨ d
214
Table 10−4 The Si xteen Logi cal Operati ons
The Accumulation Buffer
Advanced
The accumul ati on buffer can be used for such thi ngs as scene anti al i asi ng, moti on bl ur, si mul ati ng
photographi c depth of fi el d, and cal cul ati ng the soft shadows that resul t from mul ti pl e l i ght sources.
Other techni ques are possi bl e, especi al l y i n combi nati on wi th some of the other buffers. (For more
i nformati on on the uses for the accumul ati on buffer, see TheAccumulation Buffer: HardwareSupport
for High−Quality Rendering by Paul Haeberl i and Kurt Akel ey (SI GGRAPH 1990 Proceedi ngs, p.
309−318).
OpenGL graphi cs operati ons don’t wri te di rectl y i nto the accumul ati on buffer. Typi cal l y, a seri es of
i mages i s generated i n one of the standard col or buffers, and these are accumul ated, one at a ti me, i nto
the accumul ati on buffer. When the accumul ati on i s fi ni shed, the resul t i s copi ed back i nto a col or buffer
for vi ewi ng. To reduce roundi ng errors, the accumul ati on buffer may have hi gher preci si on (more bi ts
per col or) than the standard col or buffers. Renderi ng a scene several ti mes obvi ousl y takes l onger than
renderi ng i t once, but the resul t i s hi gher qual i ty. You can deci de what trade−off between qual i ty and
renderi ng ti me i s appropri ate for your appl i cati on.
You can use the accumul ati on buffer the same way a photographer can use fi l m for mul ti pl e exposures.
A photographer typi cal l y creates a mul ti pl e exposure by taki ng several pi ctures of the same scene
wi thout advanci ng the fi l m. I f anythi ng i n the scene moves, that object appears bl urred. Not
surpri si ngl y, a computer can do more wi th an i mage than a photographer can do wi th a camera. For
exampl e, a computer has exqui si te control over the vi ewpoi nt, but a photographer can’t shake a camera
a predi ctabl e and control l ed amount.
See "Clearing Buffers" for i nformati on about how to cl ear the accumul ati on buffer; use glAccum() to
control i t.
voi d glAccum(GLenum op, GLfl oat value);
Control s the accumul ati on buffer. The op parameter sel ects the operati on, and valuei s a number to be
used i n that operati on. The possi bl e operati ons are GL_ACCUM, GL_LOAD, GL_RETURN, GL_ADD,
and GL_MULT:
• GL_ACCUM reads each pi xel from the buffer currentl y sel ected for readi ng wi th glReadBuffer()
(see Chapter 8 ), mul ti pl i es the R, G, B, and al pha val ues by value, and adds the resul t to the
accumul ati on buffer.
• GL_LOAD does the same thi ng, except that the val ues repl ace those i n the accumul ati on buffer
rather than bei ng added to them.
• GL_RETURN takes val ues from the accumul ati on buffer, mul ti pl i es them by value, and pl aces the
resul t i n the col or buffer(s) enabl ed for wri ti ng.
• GL_ADD and GL_MULT si mpl y add or mul ti pl y the val ue of each pi xel i n the accumul ati on buffer
by value, and then return i t to the accumul ati on buffer. For GL_MULT, valuei s cl amped to be i n
the range [−1.0,1.0]. For GL_ADD, no cl ampi ng occurs.
Scene Antialiasing
To perform scene anti al i asi ng, fi rst cl ear the accumul ati on buffer and enabl e the front buffer for
readi ng and wri ti ng. Then l oop several ti mes (say, n) through code that draws the i mage i n a sl i ghtl y
di fferent posi ti on, accumul ati ng the data wi th
glAccum(GL_ACCUM, 1.0/n);
and fi nal l y cal l i ng
215
glAccum(GL_RETURN, 1.0);
Note that thi s method i s a bi t faster i f, on the fi rst pass through the l oop, GL_LOAD i s used and
cl eari ng the accumul ati on buffer i s omi tted. See the secti on on "Logical Operations" l ater i n thi s
chapter for possi bl e ji tteri ng val ues. Wi th thi s code, the i mage i s drawn n ti mes before the fi nal i mage
i s drawn. I f you want to avoi d showi ng the user the i ntermedi ate i mages, draw i nto a col or buffer that’s
not di spl ayed, accumul ate from that, and use the GL_RETURN cal l to draw i nto a di spl ayed buffer (or
i nto a back buffer that you subsequentl y swap to the front).
You coul d i nstead present a user i nterface that shows the vi ewed i mage i mprovi ng as each addi ti onal
pi ece i s accumul ated and that al l ows the user to hal t the process when the i mage i s good enough. To
accompl i sh thi s, i n the l oop that draws successi ve i mages, cal l glAccum() wi th GL_RETURN after each
accumul ati on, usi ng 16.0/1.0, 16.0/2.0, 16.0/3.0, ... as the second argument. Wi th thi s techni que, after
one pass, 1/16 of the fi nal i mage i s shown, after two passes, 2/16 i s shown, and so on. After the
GL_RETURN, the code shoul d check to see i f the user wants to i nterrupt the process. Thi s i nterface i s
sl i ghtl y sl ower, si nce the resul tant i mage must be copi ed i n after each pass.
To deci de what n shoul d be, you need to trade off speed (the more ti mes you draw the scene, the l onger
i t takes to obtai n the fi nal i mage) and qual i ty (the more ti mes you draw the scene, the smoother i t gets,
unti l you make maxi mum use of the accumul ati on buffer’s resol uti on). Figure J −30 and Figure J −32
show i mprovements made usi ng scene anti al i asi ng.
Example 10−2 defi nes two routi nes for ji tteri ng that you mi ght fi nd useful : accPerspective() and
accFrustum(). The routi ne accPerspective() i s used i n pl ace of gluPerspective(), and the fi rst four
parameters of both routi nes are the same. To ji tter the vi ewi ng frustum for scene anti al i asi ng, pass the
x and y ji tter val ues (of l ess than one pi xel ) to the fi fth and si xth parameters of accPerspective(). Al so,
pass 0.0 for the seventh and ei ghth parameters to accPerspective() and a nonzero val ue for the ni nth
parameter (to prevent di vi si on by zero i nsi de accPerspective()). These l ast three parameters are used
for depth−of−fi el d effects, whi ch are descri bed l ater i n thi s chapter.
Example 10−2 Useful Routi nes for Ji tteri ng the Vi ewi ng Vol ume: accpersp.c
void accFrustum(GLdouble left, GLdouble right, GLdouble bottom,
GLdouble top, GLdouble near, GLdouble far, GLdouble pixdx,
GLdouble pixdy, GLdouble eyedx, GLdouble eyedy,
GLdouble focus)
{
GLdouble xwsize, ywsize;
GLdouble dx, dy;
GLint viewport[4];
glGetIntegerv (GL_VIEWPORT, viewport);
xwsize = right − left;
ywsize = top − bottom;
dx = −(pixdx*xwsize/(GLdouble) viewport[2] +
eyedx*near/focus);
dy = −(pixdy*ywsize/(GLdouble) viewport[3] +
eyedy*near/focus);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum (left + dx, right + dx, bottom + dy, top + dy,
near, far);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef (−eyedx, −eyedy, 0.0);
216
}
void accPerspective(GLdouble fovy, GLdouble aspect,
GLdouble near, GLdouble far, GLdouble pixdx, GLdouble pixdy,
GLdouble eyedx, GLdouble eyedy, GLdouble focus)
{
GLdouble fov2,left,right,bottom,top;
fov2 = ((fovy*PI_) / 180.0) / 2.0;
top = near / (fcos(fov2) / fsin(fov2));
bottom = −top;
right = top * aspect;
left = −right;
accFrustum (left, right, bottom, top, near, far,
pixdx, pixdy, eyedx, eyedy, focus);
}
Example 10−3 uses these two routi nes to perform scene anti al i asi ng.
Example 10−3 Scene Anti al i asi ng: accpersp.c
#include <GL/gl.h>
#include <GL/glu.h>
#include <math.h>
#include "aux.h"
#include "jitter.h"
void myinit(void)
{
GLfloat mat_ambient[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat light_position[] = { 0.0, 0.0, 10.0, 1.0 };
GLfloat lm_ambient[] = { 0.2, 0.2, 0.2, 1.0 };
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialf(GL_FRONT, GL_SHININESS, 50.0);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lm_ambient);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glShadeModel (GL_FLAT);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClearAccum(0.0, 0.0, 0.0, 0.0);
}
void displayObjects(void)
{
GLfloat torus_diffuse[] = { 0.7, 0.7, 0.0, 1.0 };
GLfloat cube_diffuse[] = { 0.0, 0.7, 0.7, 1.0 };
GLfloat sphere_diffuse[] = { 0.7, 0.0, 0.7, 1.0 };
GLfloat octa_diffuse[] = { 0.7, 0.4, 0.4, 1.0 };
217
glPushMatrix ();
glTranslatef (0.0, 0.0, −5.0);
glRotatef (30.0, 1.0, 0.0, 0.0);
glPushMatrix ();
glTranslatef (−0.80, 0.35, 0.0);
glRotatef (100.0, 1.0, 0.0, 0.0);
glMaterialfv(GL_FRONT, GL_DIFFUSE, torus_diffuse);
auxSolidTorus (0.275, 0.85);
glPopMatrix ();
glPushMatrix ();
glTranslatef (−0.75, −0.50, 0.0);
glRotatef (45.0, 0.0, 0.0, 1.0);
glRotatef (45.0, 1.0, 0.0, 0.0);
glMaterialfv(GL_FRONT, GL_DIFFUSE, cube_diffuse);
auxSolidCube (1.5);
glPopMatrix ();
glPushMatrix ();
glTranslatef (0.75, 0.60, 0.0);
glRotatef (30.0, 1.0, 0.0, 0.0);
glMaterialfv(GL_FRONT, GL_DIFFUSE, sphere_diffuse);
auxSolidSphere (1.0);
glPopMatrix ();
glPushMatrix ();
glTranslatef (0.70, −0.90, 0.25);
glMaterialfv(GL_FRONT, GL_DIFFUSE, octa_diffuse);
auxSolidOctahedron (1.0);
glPopMatrix ();
glPopMatrix ();
}
#define ACSIZE 8
void display(void)
{
GLint viewport[4];
int jitter;
glGetIntegerv (GL_VIEWPORT, viewport);
glClear(GL_ACCUM_BUFFER_BIT);
for (jitter = 0; jitter < ACSIZE; jitter++) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
accPerspective (50.0,
(GLdouble) viewport[2]/(GLdouble) viewport[3],
1.0, 15.0, j8[jitter].x, j8[jitter].y,
0.0, 0.0, 1.0);
displayObjects ();
glAccum(GL_ACCUM, 1.0/ACSIZE);
218
}
glAccum (GL_RETURN, 1.0);
glFlush();
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA
| AUX_ACCUM | AUX_DEPTH);
auxInitPosition (0, 0, 250, 250);
auxInitWindow (argv[0]);
myinit();
auxReshapeFunc (myReshape);
auxMainLoop(display);
}
You don’t have to use a perspecti ve projecti on to perform scene anti al i asi ng. You can anti al i as a scene
wi th orthographi c projecti on si mpl y by usi ng glTranslate*() to ji tter the scene. Keep i n mi nd that
glTranslate*() operates i n worl d coordi nates, but you want the apparent moti on of the scene to be l ess
than one pi xel , measured i n screen coordi nates. Thus, you must reverse the worl d−coordi nate mappi ng
by cal cul ati ng the ji tteri ng transl ati on val ues, usi ng i ts wi dth or hei ght i n worl d coordi nates di vi ded by
i ts vi ewport si ze. Then, mul ti pl y that worl d−coordi nate val ue by the amount of ji tter to determi ne how
much the scene shoul d be moved i n worl d coordi nates to get a predi ctabl e ji tter of l ess than one pi xel .
Example 10−4 shows how the display() and myReshape() routi nes mi ght l ook wi th a worl d−coordi nate
wi dth and hei ght of 4.5.
Example 10−4 Ji tteri ng wi th an Orthographi c Projecti on: accanti .c
#define ACSIZE 8
void display(void)
{
GLint viewport[4];
int jitter;
glGetIntegerv (GL_VIEWPORT, viewport);
glClear(GL_ACCUM_BUFFER_BIT);
for (jitter = 0; jitter < ACSIZE; jitter++) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* Note that 4.5 is the distance in world space between
* left and right and bottom and top. The following formula
* converts fractional pixel movement to world coordinates.
*/
glPushMatrix ();
glTranslatef (j8[jitter].x*4.5/viewport[2],
j8[jitter].y*4.5/viewport[3], 0.0);
displayObjects ();
glPopMatrix ();
219
glAccum(GL_ACCUM, 1.0/ACSIZE);
}
glAccum (GL_RETURN, 1.0);
glFlush();
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho (−2.25, 2.25, −2.25*h/w, 2.25*h/w, −10.0, 10.0);
else
glOrtho (−2.25*w/h, 2.25*w/h, −2.25, 2.25, −10.0, 10.0);
glMatrixMode(GL_MODELVIEW);
}
Motion Blur
Si mi l ar methods can be used to si mul ate moti on bl ur, as shown i n Figure J −7 and Figure 10−2.
Suppose your scene has some stati onary and some movi ng objects i n i t, and you want to make a
moti on−bl urred i mage extendi ng over a smal l i nterval of ti me. Set up the accumul ati on buffer i n the
same way, but i nstead of spati al l y ji tteri ng the i mages, ji tter them temporal l y. The enti re scene can be
made successi vel y di mmer by cal l i ng
glAccum (GL_MULT, decayFactor);
as the scene i s drawn i nto the accumul ati on buffer, where decayFactor i s a number between 0.0 and
1.0. Smal l er numbers for decayFactor cause the object to appear to be movi ng faster. You can transfer
the compl eted scene wi th the object’s current posi ti on and "vapor trai l " of previ ous posi ti ons from the
accumul ati on buffer to the standard col or buffer wi th
glAccum (GL_RETURN, 1.0);
The i mage l ooks correct even i f the i tems move at di fferent speeds, or i f some of them are accel erated.
As before, the more ji tter poi nts you use, the better the fi nal i mage, at l east up to the poi nt where you
begi n to l ose resol uti on due to fi ni te preci si on i n the accumul ati on buffer. You can combi ne moti on bl ur
wi th anti al i asi ng by ji tteri ng i n both the spati al and temporal domai ns, but you pay for hi gher qual i ty
wi th l onger renderi ng ti mes.
Figure 10−2 A Moti on−Bl urred Object
220
Depth of Field
A photograph made wi th a camera i s i n perfect focus onl y for i tems l yi ng on a si ngl e pl ane a certai n
di stance from the fi l m. The farther an i tem i s from thi s pl ane, the more out of focus i t i s. The depth of
fi el d for a camera i s a regi on about the pl ane of perfect focus where i tems are out of focus by a smal l
enough amount.
Under normal condi ti ons, everythi ng you draw wi th OpenGL i s i n focus (unl ess your moni tor’s bad, i n
whi ch case everythi ng i s out of focus). The accumul ati on buffer can be used to approxi mate what you
woul d see i n a photograph where i tems are more and more bl urred as thei r di stance from a pl ane of
perfect focus i ncreases. I t i sn’t an exact si mul ati on of the effects produced i n a camera, but the resul t
l ooks si mi l ar to what a camera woul d produce.
To achi eve thi s resul t, draw the scene repeatedl y usi ng cal l s wi th di fferent argument val ues to
glFrustum(). Choose the arguments so that the posi ti on of the vi ewpoi nt vari es sl i ghtl y around i ts true
posi ti on and so that each frustum shares a common rectangl e that l i es i n the pl ane of perfect focus, as
shown i n Figure 10−3. The resul ts of al l the renderi ngs shoul d be averaged i n the usual way usi ng the
accumul ati on buffer.
Figure 10−3 A Ji ttered Vi ewi ng Vol ume for Depth−of−Fi el d Effects
Figure J −10shows an i mage of fi ve teapots drawn usi ng the depth−of−fi el d effect. The gol d teapot
(second from the l eft) i s i n focus, and the other teapots get progressi vel y bl urri er, dependi ng upon thei r
di stance from the focal pl ane (gol d teapot). The code to draw thi s i mage i s shown i n Example 10−5
(whi ch assumes accPerspective() and accFrustum() are defi ned as descri bed i n Example 10−2 ). The
scene i s drawn ei ght ti mes, each wi th a sl i ghtl y ji ttered vi ewi ng vol ume, by cal l i ng accPerspective(). As
221
you recal l , wi th scene anti al i asi ng, the fi fth and si xth parameters ji tter the vi ewi ng vol umes i n the x
and y di recti ons. For the depth−of−fi el d effect, however, you want to ji tter the vol ume whi l e hol di ng i t
stati onary at the focal pl ane. The focal pl ane i s the depth val ue defi ned by the ni nth (l ast) parameter to
accPerspective(), whi ch i s z = 0 i n thi s exampl e. The amount of bl ur i s determi ned by mul ti pl yi ng the x
and y ji tter val ues (seventh and ei ghth parameters of accPerspective()) by a constant. Determi ni ng the
constant i s not a sci ence; experi ment wi th val ues unti l the depth of fi el d i s as pronounced as you want.
(Note that i n Example 10−5 , the fi fth and si xth parameters to accPerspective() are set to 0.0, so scene
anti al i asi ng i s turned off.)
Example 10−5 Creati ng a Depth−of−Fi el d Effect: dof.c
#include <GL/gl.h>
#include <GL/glu.h>
#include <math.h>
#include "aux.h"
#include "jitter.h"
void myinit(void)
{
GLfloat ambient[] = { 0.0, 0.0, 0.0, 1.0 };
GLfloat diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat position[] = { 0.0, 3.0, 3.0, 0.0 };
GLfloat lmodel_ambient[] = { 0.2, 0.2, 0.2, 1.0 };
GLfloat local_view[] = { 0.0 };
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
glLightfv(GL_LIGHT0, GL_POSITION, position);
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, local_view);
glFrontFace (GL_CW);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_AUTO_NORMAL);
glEnable(GL_NORMALIZE);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
glClearColor(0.0, 0.0, 0.0, 0.0);
glClearAccum(0.0, 0.0, 0.0, 0.0);
}
void renderTeapot (GLfloat x, GLfloat y, GLfloat z,
GLfloat ambr, GLfloat ambg, GLfloat ambb,
GLfloat difr, GLfloat difg, GLfloat difb,
GLfloat specr, GLfloat specg, GLfloat specb, GLfloat shine)
{
222
float mat[3];
glPushMatrix();
glTranslatef (x, y, z);
mat[0] = ambr; mat[1] = ambg; mat[2] = ambb;
glMaterialfv (GL_FRONT, GL_AMBIENT, mat);
mat[0] = difr; mat[1] = difg; mat[2] = difb;
glMaterialfv (GL_FRONT, GL_DIFFUSE, mat);
mat[0] = specr; mat[1] = specg; mat[2] = specb;
glMaterialfv (GL_FRONT, GL_SPECULAR, mat);
glMaterialf (GL_FRONT, GL_SHININESS, shine*128.0);
auxSolidTeapot(0.5);
glPopMatrix();
}
void display(void)
{
int jitter;
GLint viewport[4];
glGetIntegerv (GL_VIEWPORT, viewport);
glClear(GL_ACCUM_BUFFER_BIT);
for (jitter = 0; jitter < 8; jitter++) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
accPerspective (45.0,
(GLdouble) viewport[2]/(GLdouble) viewport[3],
1.0, 15.0, 0.0, 0.0,
0.33*j8[jitter].x, 0.33*j8[jitter].y, 5.0);
renderTeapot (−1.1, −0.5, −4.5, 0.1745, 0.01175,
0.01175, 0.61424, 0.04136, 0.04136,
0.727811, 0.626959, 0.626959, 0.6);
renderTeapot (−0.5, −0.5, −5.0, 0.24725, 0.1995, 0.0745,
0.75164, 0.60648, 0.22648, 0.628281,
0.555802, 0.366065, 0.4);
renderTeapot (0.2, −0.5, −5.5, 0.19225, 0.19225,
0.19225, 0.50754, 0.50754, 0.50754,
0.508273, 0.508273, 0.508273, 0.4);
renderTeapot (1.0, −0.5, −6.0, 0.0215, 0.1745, 0.0215,
0.07568, 0.61424, 0.07568, 0.633,
0.727811, 0.633, 0.6);
renderTeapot (1.8, −0.5, −6.5, 0.0, 0.1, 0.06, 0.0,
0.50980392, 0.50980392, 0.50196078,
0.50196078, 0.50196078, .25);
glAccum (GL_ACCUM, 0.125);
}
glAccum (GL_RETURN, 1.0);
glFlush();
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
223
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA
| AUX_ACCUM | AUX_DEPTH);
auxInitPosition (0, 0, 400, 400);
auxInitWindow (argv[0]);
myinit();
auxReshapeFunc (myReshape);
auxMainLoop(display);
}
Soft Shadows
To accumul ate soft shadows due to mul ti pl e l i ght sources, render the shadows wi th one l i ght turned on
at a ti me, and accumul ate them together. Thi s can be combi ned wi th spati al ji tteri ng to anti al i as the
scene at the same ti me. See "Shadows" for more i nformati on about drawi ng shadows.
J ittering
I f you need to take ni ne or si xteen sampl es to anti al i as an i mage, you mi ght thi nk that the best choi ce
of poi nts i s an equal l y spaced gri d across the pi xel . Surpri si ngl y, thi s i s not necessari l y true. I n fact,
someti mes i t’s a good i dea to take poi nts that l i e i n adjacent pi xel s. You mi ght want a uni form
di stri buti on or a normal i zed di stri buti on, cl usteri ng toward the center of the pi xel . The SI GGRAPH
paper di scusses these i ssues. I n addi ti on, Table 10−5 shows a few sets of reasonabl e ji tteri ng val ues
to be used for some sel ected sampl e counts. Most of the exampl es i n the tabl e are uni forml y di stri buted
i n the pi xel , and al l l i e wi thi n the pi xel .
Count Values
2 {0.25, 0.75}, {0.75, 0.25}
3 {0.5033922635, 0.8317967229}, {0.7806016275, 0.2504380877},
{0.2261828938, 0.4131553612}
4 {0.375, 0.25}, {0.125, 0.75}, {0.875, 0.25}, {0.625, 0.75}
5 {0.5, 0.5}, {0.3, 0.1}, {0.7, 0.9}, {0.9, 0.3}, {0.1, 0.7}
6 {0.4646464646, 0.4646464646}, {0.1313131313, 0.7979797979},
{0.5353535353, 0.8686868686}, {0.8686868686, 0.5353535353},
{0.7979797979, 0.1313131313}, {0.2020202020, 0.2020202020}
8 {0.5625, 0.4375}, {0.0625, 0.9375}, {0.3125, 0.6875}, {0.6875, 0.8125}, {0.8125, 0.1875}, {0.9375,
0.5625}, {0.4375, 0.0625}, {0.1875, 0.3125}
9 {0.5, 0.5}, {0.1666666666, 0.9444444444}, {0.5, 0.1666666666},
{0.5, 0.8333333333}, {0.1666666666, 0.2777777777},
{0.8333333333, 0.3888888888}, {0.1666666666, 0.6111111111},
{0.8333333333, 0.7222222222}, {0.8333333333, 0.0555555555}
12 {0.4166666666, 0.625}, {0.9166666666, 0.875}, {0.25, 0.375},
{0.4166666666, 0.125}, {0.75, 0.125}, {0.0833333333, 0.125}, {0.75, 0.625},
{0.25, 0.875}, {0.5833333333, 0.375}, {0.9166666666, 0.375},
{0.0833333333, 0.625}, { 0.583333333, 0.875}
16 {0.375, 0.4375}, {0.625, 0.0625}, {0.875, 0.1875}, {0.125, 0.0625},
{0.375, 0.6875}, {0.875, 0.4375}, {0.625, 0.5625}, {0.375, 0.9375},
{0.625, 0.3125}, {0.125, 0.5625}, {0.125, 0.8125}, {0.375, 0.1875},
{0.875, 0.9375}, {0.875, 0.6875}, {0.125, 0.3125}, {0.625, 0.8125}
Table 10−5 Sampl e Ji tteri ng Val ues
224
Chapter 11
Evaluators and NURBS
Chapter Objectives
Advanced
After readi ng thi s chapter, you’l l be abl e to do the fol l owi ng:
• Use OpenGL’s eval uator commands to draw basi c curves and surfaces
• Use the GLU’s hi gher−l evel NURBS faci l i ty to draw more compl ex curves and surfaces
Note that thi s chapter presumes a number of prerequi si tes; they’re l i sted i n "Prerequisites".
At the l owest l evel , graphi cs hardware draws poi nts, l i ne segments, and pol ygons, whi ch are usual l y
tri angl es and quadri l ateral s. Smooth curves and surfaces are drawn by approxi mati ng them wi th l arge
numbers of smal l l i ne segments or pol ygons. However, many useful curves and surfaces can be
descri bed mathemati cal l y by a smal l number of parameters such as a few control points. Savi ng the
si xteen control poi nts for a surface requi res much l ess storage than savi ng 1000 tri angl es together wi th
the normal vector i nformati on at each vertex. I n addi ti on, the 1000 tri angl es onl y approxi mate the true
surface, but the control poi nts can accuratel y descri be the real surface.
Eval uators provi de a way to speci fy poi nts on a curve or surface (or part of one) usi ng onl y the control
poi nts. The curve or surface can then be rendered at any preci si on. I n addi ti on, normal vectors can be
cal cul ated for surfaces automati cal l y. You can use the poi nts generated by an eval uator i n many ways
to draw dots where the surface woul d be, to draw a wi reframe versi on of the surface, or to draw a
ful l y l i ghted and shaded versi on.
You can use eval uators to descri be any pol ynomi al or rati onal pol ynomi al spl i nes or surfaces of any
degree. These i ncl ude al most al l spl i nes and spl i ne surfaces i n use today, i ncl udi ng B−spl i nes, NURBS
(Non−Uni form Rati onal B−Spl i ne) surfaces, Bézi er curves and surfaces, and Hermi te spl i nes. Si nce
eval uators provi de onl y a l ow−l evel descri pti on of the poi nts on a curve or surface, however, they’re
typi cal l y used underneath uti l i ty l i brari es that provi de a hi gher−l evel i nterface to the programmer. The
GLU’s NURBS faci l i ty i s such a hi gher−l evel i nterfacethe NURBS routi nes encapsul ate l ots of
compl i cated code, but the fi nal renderi ng i s done wi th eval uators.
Thi s chapter contai ns the fol l owi ng major secti ons:
• "Prerequisites"di scusses what knowl edge i s assumed for thi s chapter. I t al so gi ves several
references where you can obtai n thi s i nformati on.
• "Evaluators"expl ai ns how eval uators work and how to control them usi ng the appropri ate
OpenGL commands.
• "The GLU NURBS Interface"descri bes the GLU routi nes for creati ng NURBS surfaces.
Prerequisites
Eval uators make spl i nes and surfaces that are based on a Bézi er (or Bernstei n) basi s. The defi ni ng
formul as for the functi ons i n thi s basi s are gi ven i n thi s chapter, but the di scussi on doesn’t i ncl ude
deri vati ons or even l i sts of al l thei r i nteresti ng mathemati cal properti es. I f you want to use eval uators
to draw curves and surfaces usi ng other bases, you must know how to convert your basi s to a Bézi er
basi s. I n addi ti on, when you render a Bézi er surface or part of i t usi ng eval uators, you need to
determi ne the granul ari ty of your subdi vi si on. Your deci si on needs to take i nto account the trade−off
between hi gh−qual i ty (hi ghl y subdi vi ded) i mages and hi gh speed. Determi ni ng an appropri ate
subdi vi si on strategy can be qui te compl i cated, and i t’s not di scussed here.
Si mi l arl y, a compl ete di scussi on of NURBS i s beyond the scope of thi s book. The GLU NURBS i nterface
i s documented here, however, and programmi ng exampl es are provi ded for readers who al ready
225
understand the subject. I n what fol l ows, we assume that you know about NURBS control poi nts, knot
sequences, and tri mmi ng curves.
I f you l ack some of these prerequi si tes, the fol l owi ng references wi l l hel p.
• Burns, Derri ck. Dynamic Trimmed SurfaceRendering. Ph.D. di ssertati on, Stanford Uni versi ty,
1993.
• de Boor, Carl . A Practical Guideto Splines. New York: Spri nger−Verl ag, 1985.
• Fari n, Geral d. Curves and Surfaces for Computer−Aided Geometric Design. San Di ego, Cal i f:
Academi c Press, 1990.
• Mortenson, Mi chael . Geometric Modeling. New York: John Wi l ey & Sons, 1985.
• Newman, Wi l l i am and Sproul l , Robert. Principles of I nteractiveComputer Graphics. New York:
McGraw−Hi l l , 1979.
Note: Some of the terms used i n thi s chapter mi ght have sl i ghtl y di fferent meani ngs i n other books
on spl i ne curves and surfaces, si nce there i sn’t total agreement among the practi ti oners of thi s
art. General l y, the OpenGL meani ngs are a bi t more restri cti ve. For exampl e, OpenGL
eval uators al ways use Bézi er bases; i n other contexts, eval uators mi ght refer to the same
concept, but wi th an arbi trary basi s.
Evaluators
A Bézi er curve i s a vector−val ued functi on of one vari abl e
C(u) = [X(u) Y(u) Z(u)]
where u vari es i n some domai n (say [0,1]). A Bézi er surface patch i s a vector−val ued functi on of two
vari abl es
S(u,v) = [X(u,v) Y(u,v) Z(u,v)]
where u and v can both vary i n some domai n. The range i sn’t necessari l y three−di mensi onal as shown
here. You mi ght want two−di mensi onal output for curves on a pl ane or texture coordi nates, or you
mi ght want four−di mensi onal output to speci fy RGBA i nformati on. Even one−di mensi onal output may
make sense for gray l evel s, for exampl e.
For each u (or u and v, i n the case of a surface), the formul a for C() (or S()) cal cul ates a poi nt on the
curve (or surface). To use an eval uator, fi rst defi ne the functi on C() or S(), enabl e i t, and then use the
glEvalCoord1() or glEvalCoord2() command i nstead of glVertex(). Thi s way, the curve or surface
verti ces can be used l i ke any other verti cesto form poi nts or l i nes, for exampl e. I n addi ti on, other
commands automati cal l y generate seri es of verti ces that produce a regul ar mesh uni forml y spaced i n u
(or i n u and v). One− and two−di mensi onal eval uators are si mi l ar, but the descri pti on i s somewhat
si mpl er i n one di mensi on, so that case i s di scussed fi rst.
One−Dimensional Evaluators
Thi s secti on presents an exampl e of usi ng one−di mensi onal eval uators to draw a curve. I t then
descri bes the commands and equati ons that control eval uators.
One−Dimensional Example: A Simple Bézier Curve
The program shown i n Example 11−1 draws a cubi c Bézi er curve usi ng four control poi nts, as shown
i n Figure 11−1.
226
Figure 11−1 A Bézi er Curve
Example 11−1 Drawi ng a Bézi er Curve Usi ng Four Control Poi nts: bezcurve.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
GLfloat ctrlpoints[4][3] = {
{ −4.0, −4.0, 0.0}, { −2.0, 4.0, 0.0},
{2.0, −4.0, 0.0}, {4.0, 4.0, 0.0}};
void myinit(void)
{
glClearColor(0.0, 0.0, 0.0, 1.0);
glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4,&ctrlpoints[0][0]);
glEnable(GL_MAP1_VERTEX_3);
glShadeModel(GL_FLAT);
}
void display(void)
{
int i;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_LINE_STRIP);
for (i = 0; i <= 30; i++)
glEvalCoord1f((GLfloat) i/30.0);
glEnd();
/* The following code displays the control points as dots. */
glPointSize(5.0);
glColor3f(1.0, 1.0, 0.0);
glBegin(GL_POINTS);
for (i = 0; i < 4; i++)
227
glVertex3fv(&ctrlpoints[i][0]);
glEnd();
glFlush();
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho(−5.0, 5.0, −5.0*(GLfloat)h/(GLfloat)w,
5.0*(GLfloat)h/(GLfloat)w, −5.0, 5.0);
else
glOrtho(−5.0*(GLfloat)w/(GLfloat)h,
5.0*(GLfloat)w/(GLfloat)h, −5.0, 5.0, −5.0, 5.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
auxInitPosition (0, 0, 500, 500);
auxInitWindow (argv[0]);
myinit();
auxReshapeFunc (myReshape);
auxMainLoop(display);
}
A cubi c Bézi er curve i s descri bed by four control poi nts, whi ch appear i n thi s exampl e i n the
ctrlpoints[][] array. Thi s array i s one of the arguments to glMap1f(). Al l the arguments for thi s
command are as fol l ows:
GL_MAP1_VERTEX_3
Three−di mensi onal verti ces are produced
0 Low val ue of parameter u
1 Hi gh val ue of parameter u
3 The number of fl oati ng−poi nt val ues to advance i n the data between one control poi nt
and the next
4 The order of the spl i ne, whi ch i s the degree+1; i n thi s case, the degree i s 3 (si nce the
curve i s a cubi c)
&ctrl poi nts[0][0]
Poi nter to the fi rst control poi nt’s data
Note that the second and thi rd arguments control the parameteri zati on of the curveas the vari abl e u
ranges from 0 to 1, the curve goes from one end to the other. The cal l to glEnable() enabl es the
one−di mensi onal eval uator for two−di mensi onal verti ces.
The curve i s drawn i n the routi ne display() between the glBegin() and glEnd() cal l s. Si nce the eval uator
i s enabl ed, the command glEvalCoord1f() i s just l i ke i ssui ng a glVertex() command wi th coordi nates
that are the coordi nates of a vertex on the curve correspondi ng to the i nput parameter u.
Defining and Evaluating a One−Dimensional Evaluator
The Bernstei n pol ynomi al of degree n (or order n+1) i s gi ven by
228
I f Pi represents a set of control poi nts (one−, two−, three−, or even four− di mensi onal ), then the
equati on
represents a Bézi er curve as u vari es from 0 to 1. To represent the same curve but al l owi ng u to vary
between u
1
and u
2
i nstead of 0 and 1, eval uate
The command glMap1() defi nes a one−di mensi onal eval uator that uses these equati ons.
voi d glMap1{fd}(GLenum target, TYPEu1, TYPEu2, GLi nt stride, GLi nt order, const TYPE*points);
Defi nes a one−di mensi onal eval uator. The target parameter speci fi es what the control poi nts represent,
as shown i n Table 11−1 , and therefore how many val ues need to be suppl i ed i n points. The poi nts can
represent verti ces, RGBA col or data, normal vectors, or texture coordi nates. Forexampl e, wi th
GL_MAP1_COLOR_4, the eval uator generates col or data al ong a curve i n four−di mensi onal (RGBA)
col or space. You al so use the parameter val ues l i sted i n Table 11−1 to enabl e each defi ned eval uator
before you i nvoke i t. Pass the appropri ate val ue to glEnable() or glDisable() to enabl e or di sabl e the
eval uator.
The second two parameters for glMap1*(), u1 and u2, i ndi cate the range for the vari abl e u. The vari abl e
stridei s the number of si ngl e− or doubl e−preci si on val ues (as appropri ate) i n each bl ock of storage.
Thus, i t’s an offset val ue between the begi nni ng of one control poi nt and the begi nni ng of the next.
The order i s the degree pl us one, and i t shoul d agree wi th the number of control poi nts. The points
parameter poi nts to the fi rst coordi nate of the fi rst control poi nt. Usi ng the exampl e data structure for
glMap1*(), use the fol l owi ng for points:
(GLfl oat *)(&ctl poi nts[0].x)
Parameter Meaning
GL_MAP1_VERTEX_3 x, y, z vertex coordinates
GL_MAP1_VERTEX_4 x, y, z, w vertex coordinates
GL_MAP1_INDEX color index
GL_MAP1_COLOR_4 R, G, B, A
GL_MAP1_NORMAL normal coordinates
GL_MAP1_TEXTURE_COORD_1 s texture coordinates
GL_MAP1_TEXTURE_COORD_2 s, t texture coordinates
229
GL_MAP1_TEXTURE_COORD_3 s, t, r texture coordinates
GL_MAP1_TEXTURE_COORD_4 s, t, r, q texture coordinates
Table 11−1 Types of Control Poi nts for Use wi th gl Map1*()
More than one eval uator can be eval uated at a ti me. I f you have both a GL_MAP1_VERTEX_3 and a
GL_MAP1_COLOR_4 eval uator defi ned and enabl ed, for exampl e, then cal l s to glEvalCoord1()
generate both a posi ti on and a col or. Onl y one of the vertex eval uators can be enabl ed at a ti me,
al though you mi ght have defi ned both of them. Si mi l arl y, onl y one of the texture eval uators can be
acti ve. Other than that, however, eval uators can be used to generate any combi nati on of vertex,
normal , col or, and texture−coordi nate data. I f more than one eval uator of the same type i s defi ned and
enabl ed, the one of hi ghest di mensi on i s used.
Use glEvalCoord1*() to eval uate a defi ned and enabl ed one−di mensi onal map.
voi d glEvalCoord1{fd}{v}(TYPE u);
Causes eval uati on of the enabl ed one−di mensi onal maps. The argument u i s the val ue (or a poi nter to
the val ue, i n the vector versi on of the command) that’s the domai n coordi nate.
Defining Evenly Spaced Coordinate Values in One Dimension
You can use glEvalCoord1() wi th any val ues for u, but by far the most common use i s wi th evenl y
spaced val ues, as shown previ ousl y i n Example 11−1 . To obtai n evenl y spaced val ues, defi ne a
one−di mensi onal gri d usi ng glMapGrid1*() and then appl y i t usi ng glEvalMesh1().
voi d glMapGrid1{fd}(GLi nt n, TYPEu1, TYPEu2);
Defi nes a gri d that goes from u1 to u2 i n n steps, whi ch are evenl y spaced.
voi d glEvalMesh1(GLenum mode, GLi nt p1, GLi nt p2);
Appl i es the currentl y defi ned map gri d to al l enabl ed eval uators. The modecan be ei ther GL_POI NT or
GL_LI NE, dependi ng on whether you want to draw poi nts or a connected l i ne al ong the curve. The cal l
has exactl y the same effect as i ssui ng a glEvalCoord1() for each of the steps between and i ncl udi ng p1
and p2, where 0 <= p1, p2 <= n. Programati cal l y, i t’s equi val ent to the fol l owi ng:
glBegin(GL_POINTS); /* OR glBegin(GL_LINE_STRIP); */
for (i = p1; i <= p2; i++)
glEvalCoord1(u1 + i*(u2−u1)/n);
glEnd();
except that i f i = 0 or i = n, then glEvalCoord() i s cal l ed wi th exactl y u1 or u2 as i ts parameter.
Two−Dimensional Evaluators
I n two di mensi ons, everythi ng i s si mi l ar to the one−di mensi onal case, except that al l the commands
must take two parameters, u and v, i nto account. Poi nts, col ors, normal s, or texture coordi nates must
be suppl i ed over a surface i nstead of a curve. Mathemati cal l y, the defi ni ti on of a Bézi er surface patch i s
gi ven by
230
where P
i j
are a set of m*n control poi nts, and the B
i
are the same Bernstei n pol ynomi al s for one
di mensi on. As before, the Pij can represent verti ces, normal s, col ors, or texture coordi nates.
The procedure to use two−di mensi onal eval uators i s si mi l ar to the procedure for one di mensi on:
1. Defi ne the eval uator(s) wi th glMap2*().
2. Enabl e them by passi ng the appropri ate val ue to glEnable().
3. I nvoke them ei ther by cal l i ng glEvalCoord2() between a glBegin() and glEnd() pai r, or by speci fyi ng
and then appl yi ng a mesh wi th glMapGrid2() and glEvalMesh2().
Defining and Evaluating a Two−Dimensional Evaluator
Use glMap2*() and glEvalCoord2*() to defi ne and then i nvoke a two−di mensi onal eval uator.
voi d glMap2{fd}(GLenum target, TYPEu1, TYPEu2, GLi nt ustride, GLi nt uorder, TYPEv1, TYPEv2,
GLi nt vstride, GLi nt vorder, TYPE points);
The target parameter can have any of the val ues i n Table 11−1 , except that the stri ng MAP1 i s
repl aced wi th MAP2. As before, these val ues are al so used wi th glEnable() to enabl e the correspondi ng
eval uator. Mi ni mum and maxi mum val ues for both u and v are provi ded as u1, u2, v1, and v2. The
parameters ustrideand vstridei ndi cate the number of si ngl e− or doubl e−preci si on val ues (as
appropri ate) between i ndependent setti ngs for these val ues al l ows users to sel ect a subrectangl e of
control poi nts out of a much l arger array. For exampl e, i f the data appears i n the form
GLfloat ctlpoints[100][100][3];
and you want to use the 4x4 subset begi nni ng at ctl poi nts[20][30], choose ustrideto be 100*3, and
vstrideto be 3. The starti ng poi nt, points, shoul d be set to &ctl poi nts[20][30][0]. Fi nal l y, the order
parameters, uorder and vorder, can be di fferent, al l owi ng patches that are cubi c i n one di recti on and
quadrati c i n the other, for exampl e.
voi d glEvalCoord2{fd}{v}(TYPE u, TYPE v);
Causes eval uati on of the enabl ed two−di mensi onal maps. The arguments u and v are the val ues (or a
poi nter to the val ue, i n the vector versi on of the command) for the domai n coordi nates. I f ei ther of the
vertex eval uators i s enabl ed (GL_MAP2_VERTEX_3 or GL_MAP2_VERTEX_4), then the normal to the
surface i s computed anal yti cal l y. Thi s normal i s associ ated wi th the generated vertex i f automati c
normal generati on has been enabl ed by passi ng GL_AUTO_NORMAL to glEnable(). I f i t’s di sabl ed, the
correspondi ng enabl ed normal map i s used to produce a normal . I f no such map exi sts, the current
normal i s used.
Two−Dimensional Example: A Bézier Surface
Example 11−2 draws a wi reframe Bézi er surface usi ng eval uators, as shown i n Figure 11−2. I n thi s
exampl e, the surface i s drawn wi th ni ne curved l i nes i n each di recti on. Each curve i s drawn as 30
segments. To get the whol e program, add the myReshape() and main() routi nes from Example 11−1 .
231
Figure 11−2 A Bézi er Surface
Example 11−2 Drawi ng a Bézi er Surface: bezsurf.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
GLfloat ctrlpoints[4][4][3] = {
{{−1.5, −1.5, 4.0}, {−0.5, −1.5, 2.0},
{0.5, −1.5, −1.0}, {1.5, −1.5, 2.0}},
{{−1.5, −0.5, 1.0}, {−0.5, −0.5, 3.0},
{0.5, −0.5, 0.0}, {1.5, −0.5, −1.0}},
{{−1.5, 0.5, 4.0}, {−0.5, 0.5, 0.0},
{0.5, 0.5, 3.0}, {1.5, 0.5, 4.0}},
{{−1.5, 1.5, −2.0}, {−0.5, 1.5, −2.0},
{0.5, 1.5, 0.0}, {1.5, 1.5, −1.0}}
};
void display(void)
{
int i, j;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
glPushMatrix ();
glRotatef(85.0, 1.0, 1.0, 1.0);
for (j = 0; j <= 8; j++) {
glBegin(GL_LINE_STRIP);
for (i = 0; i <= 30; i++)
glEvalCoord2f((GLfloat)i/30.0, (GLfloat)j/8.0);
glEnd();
glBegin(GL_LINE_STRIP);
for (i = 0; i <= 30; i++)
glEvalCoord2f((GLfloat)j/8.0, (GLfloat)i/30.0);
glEnd();
}
232
glPopMatrix ();
glFlush();
}
void myinit(void)
{
glClearColor (0.0, 0.0, 0.0, 1.0);
glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4,
0, 1, 12, 4, &ctrlpoints[0][0][0]);
glEnable(GL_MAP2_VERTEX_3);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_FLAT);
}
Defining Evenly Spaced Coordinate Values in Two Dimensions
I n two di mensi ons, the glMapGrid2*() and glEvalMesh2() commands are si mi l ar to the
one−di mensi onal versi ons, except that both u and v i nformati on must be i ncl uded.
voi d glMapGrid2{fd}(GLi nt nu, TYPEu1, TYPEu2, GLi nt nv, TYPEv1, TYPEv2);
voi d glEvalMesh2(GLenum mode, GLi nt p1, GLi nt p2, GLi nt q2, GLi nt q2);
Defi nes a two−di mensi onal map gri d that goes from u1 to u2 i n nu evenl y spaced steps and from v1 to v2
i n nv steps (glMapGrid2*()), and then appl i es thi s gri d to al l enabl ed eval uators (glEvalMesh2()). The
onl y si gni fi cant di fference from the one−di mensi onal versi ons of these two commands i s that i n
glEvalMesh2(), the modeparameter can be GL_FI LL as wel l as GL_POI NT or GL_LI NE. GL_FI LL
generates fi l l ed pol ygons usi ng the quad−mesh pri mi ti ve. Stated preci sel y, glEvalMesh2() i s nearl y
equi val ent to one of the fol l owi ng three code fragments. (I t’s nearl y equi val ent because when i i s equal
to nu or j to nv, the parameter i s exactl y equal to u2 or v2, not to u1+nu*(u2−u1)/ nu, whi ch mi ght be
sl i ghtl y di fferent due to round−off error.)
glBegin(GL_POINTS); /* mode == GL_POINT */
for (i = nu1; i <= nu2; i++)
for (j = nv1; j <= nv2; j++)
glEvalCoord2(u1 + i*(u2−u1)/nu, v1+j*(v2−v1)/nv);
glEnd();
or
for (i = nu1; i <= nu2; i++) { /* mode == GL_LINE */
glBegin(GL_LINES);
for (j = nv1; j <= nv2; j++)
glEvalCoord2(u1 + i*(u2−u1)/nu, v1+j*(v2−v1)/nv);
glEnd();
}
for (j = nv1; j <= nv2; j++) {
glBegin(GL_LINES);
for (i = nu1; i <= nu2; i++)
glEvalCoord2(u1 + i*(u2−u1)/nu, v1+j*(v2−v1)/nv);
glEnd();
}
or
for (i = nu1; i < nu2; i++) { /* mode == GL_FILL */
glBegin(GL_QUAD_STRIP);
for (j = nv1; j <= nv2; j++) {
233
for (j = nv1; j <= nv2; j++) {
glEvalCoord2(u1 + i*(u2−u1)/nu, v1+j*(v2−v1)/nv);
glEvalCoord2(u1 + (i+1)*(u2−u1)/nu, v1+j*(v2−v1)/nv);
glEnd();
}
Example 11−3 shows the di fferences necessary to draw the same Bézi er surface as Example 11−2 ,
but usi ng glMapGrid2() and glEvalMesh2() to subdi vi de the square domai n i nto a uni form 8x8 gri d.
Thi s program al so adds l i ghti ng and shadi ng, as shown i n Figure 11−3.
Figure 11−3 A Li t, Shaded Bézi er Surface Drawn Usi ng a Mesh
Example 11−3 Drawi ng a Li t, Shaded Bézi er Surface Usi ng a Mesh: bezmesh.c
void initlights(void)
{
GLfloat ambient[] = { 0.2, 0.2, 0.2, 1.0 };
GLfloat position[] = { 0.0, 0.0, 2.0, 1.0 };
GLfloat mat_diffuse[] = { 0.6, 0.6, 0.6, 1.0 };
GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat mat_shininess[] = { 50.0 };
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT0, GL_POSITION, position);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT_AND_BACK,GL_SHININESS, mat_shininess);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(85.0, 1.0, 1.0, 1.0);
glEvalMesh2(GL_FILL, 0, 8, 0, 8);
234
glPopMatrix();
glFlush();
}
void myinit(void)
{
glClearColor (0.0, 0.0, 0.0, 1.0);
glEnable(GL_DEPTH_TEST);
glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4,
0, 1, 12, 4, &ctrlpoints[0][0][0]);
glEnable(GL_MAP2_VERTEX_3);
glEnable(GL_AUTO_NORMAL);
glMapGrid2f(8, 0.0, 1.0, 8, 0.0, 1.0);
initlights();
}
Example: Using Evaluators for Textures
Example 11−4 enabl es two eval uators at the same ti me: The fi rst generates three−di mensi onal poi nts
on the same Bézi er surface as Example 11−3 , and the second generates texture coordi nates. I n thi s
case, the texture coordi nates are the same as the u and v coordi nates of the surface, but a speci al fl at
Bézi er patch must be created to do thi s.
The fl at patch i s defi ned over a square wi th corners at (0, 0), (0, 1), (1, 0), and (1, 1); i t generates (0, 0) at
corner (0, 0), (0, 1) at corner (0, 1), and so on. Si nce i t’s of order 2 (l i near degree pl us one), eval uati ng
thi s texture at the poi nt (u, v) generates texture coordi nates (s, t). I t’s enabl ed at the same ti me as the
vertex eval uator, so both take effect when the surface i s drawn. See Figure J −26. I f you want the
texture to repeat three ti mes i n each di recti on, change every 1.0 i n the array texpts[][][] to 3.0. Si nce the
texture wraps i n thi s exampl e, the surface i s rendered wi th ni ne copi es of the texture map.
Example 11−4 Usi ng Eval uators for Textures: texturesurf.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
#include <math.h>
GLfloat ctrlpoints[4][4][3] = {
{{ −1.5, −1.5, 4.0}, { −0.5, −1.5, 2.0},
{0.5, −1.5, −1.0}, {1.5, −1.5, 2.0}},
{{ −1.5, −0.5, 1.0}, { −0.5, −0.5, 3.0},
{0.5, −0.5, 0.0}, {1.5, −0.5, −1.0}},
{{ −1.5, 0.5, 4.0}, { −0.5, 0.5, 0.0},
{0.5, 0.5, 3.0}, {1.5, 0.5, 4.0}},
{{ −1.5, 1.5, −2.0}, { −0.5, 1.5, −2.0},
{0.5, 1.5, 0.0}, {1.5, 1.5, −1.0}}
};
GLfloat texpts[2][2][2] = {{{0.0, 0.0}, {0.0, 1.0}},
{{1.0, 0.0}, {1.0, 1.0}}};
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
235
glEvalMesh2(GL_FILL, 0, 20, 0, 20);
glFlush();
}
#define imageWidth 64
#define imageHeight 64
GLubyte image[3*imageWidth*imageHeight];
void loadImage(void)
{
int i, j;
float ti, tj;
for (i = 0; i < imageWidth; i++) {
ti = 2.0*3.14159265*i/imageWidth;
for (j = 0; j < imageHeight; j++) {
tj = 2.0*3.14159265*j/imageHeight;
image[3*(imageHeight*i+j)] =
(GLubyte) 127*(1.0+sin(ti));
image[3*(imageHeight*i+j)+1] =
(GLubyte) 127*(1.0+cos(2*tj));
image[3*(imageHeight*i+j)+2] =
(GLubyte) 127*(1.0+cos(ti+tj));
}
}
}
void myinit(void)
{
glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4,
0, 1, 12, 4, &ctrlpoints[0][0][0]);
glMap2f(GL_MAP2_TEXTURE_COORD_2, 0, 1, 2, 2,
0, 1, 4, 2, &texpts[0][0][0]);
glEnable(GL_MAP2_TEXTURE_COORD_2);
glEnable(GL_MAP2_VERTEX_3);
glMapGrid2f(20, 0.0, 1.0, 20, 0.0, 1.0);
loadImage();
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, 3, imageWidth, imageHeight,
0, GL_RGB, GL_UNSIGNED_BYTE, image);
glEnable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glEnable(GL_NORMALIZE);
glShadeModel (GL_FLAT);
}
236
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho(−4.0, 4.0, −4.0*(GLfloat)h/(GLfloat)w,
4.0*(GLfloat)h/(GLfloat)w, −4.0, 4.0);
else
glOrtho(−4.0*(GLfloat)w/(GLfloat)h,
4.0*(GLfloat)w/(GLfloat)h, −4.0, 4.0, −4.0, 4.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(85.0, 1.0, 1.0, 1.0);
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA | AUX_DEPTH);
auxInitPosition (0, 0, 300, 300);
auxInitWindow (argv[0]);
myinit();
auxReshapeFunc (myReshape);
auxMainLoop(display);
}
The GLU NURBS Interface
Al though eval uators are the onl y OpenGL pri mi ti ve avai l abl e to di rectl y draw curves and surfaces, and
even though they can be i mpl emented very effi ci entl y i n hardware, they’re often accessed by
appl i cati ons through hi gher−l evel l i brari es. The GLU provi des a NURBS (Non−Uni form Rati onal
B−Spl i ne) i nterface bui l t on top of the OpenGL eval uator commands.
A Simple NURBS Example
I f you understand NURBS, wri ti ng OpenGL code to mani pul ate NURBS curves and surfaces i s
rel ati vel y easy, even wi th l i ghti ng and texture mappi ng. Fol l ow these steps to draw NURBS curves or
untri mmed NURBS surfaces. (Tri mmed surfaces are di scussed i n "Trimming.")
1. I f you i ntend to use l i ghti ng wi th a NURBS surface, cal l glEnable() wi th GL_AUTO_NORMAL to
automati cal l y generate surface normal s. (Or you can cal cul ate your own.)
2. Use gluNewNurbsRenderer() to create a poi nter to a NURBS object, whi ch i s referred to when
creati ng your NURBS curve or surface.
3. I f desi red, cal l gluNurbsProperty() to choose renderi ng val ues, such as the maxi mum si ze of l i nes or
pol ygons that are used to render your NURBS object.
4. Cal l gluNurbsCallback() i f you want to be noti fi ed when an error i s encountered. (Error checki ng
may sl i ghtl y degrade performance.)
5. Start your curve or surface by cal l i ng gluBeginCurve() or gluBeginSurface().
6. Generate and render your curve or surface. Cal l gluNurbsCurve() or gluNurbsSurface() at l east
237
once wi th the control poi nts (rati onal or nonrati onal ), knot sequence, and order of the pol ynomi al
basi s functi on for your NURBS object. You mi ght cal l these functi ons addi ti onal ti mes to speci fy
surface normal s and/or texture coordi nates.
7. Cal l gluEndCurve() or gluEndSurface() to compl ete the curve or surface.
Example 11−5 renders a NURBS surface i n the shape of a symmetri cal hi l l wi th control poi nts
rangi ng from −3.0 to 3.0. The basi s functi on i s a cubi c B−spl i ne, but the knot sequence i s nonuni form,
wi th a mul ti pl i ci ty of 4 at each endpoi nt, causi ng the basi s functi on to behave l i ke a Bézi er curve i n
each di recti on. The surface i s l i ghted, wi th a dark gray di ffuse refl ecti on and whi te specul ar hi ghl i ghts.
Figure 11−4 shows the surface as a wi reframe and l i ghted.
Figure 11−4 A NURBS Surface
Example 11−5 Drawi ng a NURBS Surface: surface.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
GLfloat ctlpoints[4][4][3];
GLUnurbsObj *theNurb;
void init_surface(void)
{
int u, v;
for (u = 0; u < 4; u++) {
for (v = 0; v < 4; v++) {
ctlpoints[u][v][0] = 2.0*((GLfloat)u − 1.5);
ctlpoints[u][v][1] = 2.0*((GLfloat)v − 1.5);
if ( (u == 1 || u == 2) && (v == 1 || v == 2))
ctlpoints[u][v][2] = 3.0;
else
ctlpoints[u][v][2] = −3.0;
}
}
}
238
void myinit(void)
{
GLfloat mat_diffuse[] = { 0.7, 0.7, 0.7, 1.0 };
GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat mat_shininess[] = { 100.0 };
glClearColor (0.0, 0.0, 0.0, 1.0);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glEnable(GL_AUTO_NORMAL);
glEnable(GL_NORMALIZE);
init_surface();
theNurb = gluNewNurbsRenderer();
gluNurbsProperty(theNurb, GLU_SAMPLING_TOLERANCE, 25.0);
gluNurbsProperty(theNurb, GLU_DISPLAY_MODE, GLU_FILL);
}
void display(void)
{
GLfloat knots[8] = {0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0};
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(330.0, 1.,0.,0.);
glScalef (0.5, 0.5, 0.5);
gluBeginSurface(theNurb);
gluNurbsSurface(theNurb,
8, knots,
8, knots,
4 * 3,
3,
&ctlpoints[0][0][0],
4, 4,
GL_MAP2_VERTEX_3);
gluEndSurface(theNurb);
glPopMatrix();
glFlush();
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
239
gluPerspective (45.0, (GLdouble)w/(GLdouble)h, 3.0, 8.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef (0.0, 0.0, −5.0);
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
auxInitPosition (0, 0, 500, 500);
auxInitWindow (argv[0]);
myinit();
auxReshapeFunc (myReshape);
auxMainLoop(display);
}
As shown i n Example 11−5 , gluNewNurbsRenderer() returns a new NURBS object, whose type i s a
poi nter to a GLUnurbsObj structure. The gluBeginSurface() and gluEndSurface() pai r bracket the
renderi ng routi ne, savi ng and restori ng the eval uator state. These three routi nes are summari zed i n
Appendix C . The more compl ex routi nes, gluNurbsProperty() and gluNurbsSurface(), are di scussed i n
thi s secti on.
voi d gluNurbsProperty(GLUnurbsObj *nobj, GLenum property, GLfl oat value);
Control s attri butes of a NURBS object, nobj. The property argument speci fi es the property and can be
GLU_SAMPLI NG_TOLERANCE, GLU_DI SPLAY_MODE, GLU_CULLI NG, or
GLU_AUTO_LOAD_MATRI X. The valueargument i ndi cates what the property shoul d be. Si nce a
NURBS object i s rendered as pri mi ti ves, i t’s sampl ed at di fferent val ues of i ts parameter(s) (u and v)
and broken down i nto smal l l i ne segments or pol ygons for renderi ng. GLU_SAMPLI NG_TOLERANCE
control s how often the NURBS object i s sampl ed. The defaul t val ue of 50.0 makes the l argest sampl ed
l i ne segment or pol ygon edge 50.0 pi xel s l ong.
The defaul t val ue for GLU_DI SPLAY_MODE i s GLU_FI LL, whi ch causes the surface to be rendered as
pol ygons. I f GLU_OUTLI NE_POLYGON i s used for the di spl ay−mode property, the outl i nes of
pol ygons are rendered. Fi nal l y, GLU_OUTLI NE_PATCH renders the outl i nes of patches and tri mmi ng
curves (see the next secti on on tri mmi ng).
GLU_CULLI NG can speed up performance by not performi ng tessel l ati on i f the NURBS object fal l s
compl etel y outsi de the vi ewi ng vol ume; set thi s property to GL_TRUE to enabl e cul l i ng (the defaul t i s
GL_FALSE). The GLU_AUTO_LOAD_MATRI X property determi nes whether the projecti on matri x,
model vi ew matri x, and vi ewport are downl oaded from the OpenGL server (GL_TRUE, the defaul t), or
whether the appl i cati on must suppl y these matri ces wi th gluLoadSamplingMatrices() (GL_FALSE).
voi d gluNurbsSurface(GLUnurbsObj *nobj, GLi nt uknot_count, GLfl oat *uknot, GLi nt vknot_count,
GLfl oat *vknot, GLi nt u_stride, GLi nt v_stride, GLfl oat *ctlarray, GLi nt uorder, GLi nt vorder, GLenum
type);
Descri bes the verti ces (or surface normal s or texture coordi nates) of a NURBS surface, nobj. Several of
the val ues must be speci fi ed for both u and v parametri c di recti ons, such as the knot sequences (uknot
and vknot), knot counts (uknot_count and vknot_count), and order of the pol ynomi al (uorder and vorder)
for the NURBS surface. Note that the number of control poi nts i sn’t speci fi ed. I nstead, i t’s deri ved by
determi ni ng the number of control poi nts al ong each parameter as the number of knots mi nus the
order. Then, the number of control poi nts for the surface i s equal to the number of control poi nts i n
each parametri c di recti on, mul ti pl i ed by one another. The ctlarray argument poi nts to an array of
240
control poi nts.
The l ast parameter, type, i s one of the two−di mensi onal eval uator types. Commonl y, you mi ght use
GL_MAP2_VERTEX_3 for nonrati onal or GL_MAP2_VERTEX_4 for rati onal control poi nts,
respecti vel y. You mi ght al so use other types, such as GL_MAP2_TEXTURE_COORD_* or
GL_MAP2_NORMAL to cal cul ate and assi gn texture coordi nates or surface normal s.
The u_strideand v_stridearguments represent the number of fl oati ng−poi nt val ues between control
poi nts i n each parametri c di recti on. The eval uator type, as wel l as i ts order, affects the u_strideand
v_strideval ues. I n Example 11−5 , u_stridei s 12 (4 * 3) because there are three coordi nates for each
vertex (set by GL_MAP2_VERTEX_3) and four control poi nts i n the parametri c v di recti on; v_stridei s 3
because each vertex had three coordi nates, and v control poi nts are adjacent to one another.
Drawi ng a NURBS curve i s si mi l ar to drawi ng a surface, except that al l cal cul ati ons are done wi th one
parameter, u, rather than two. Al so, for curves, gluBeginCurve() and gluEndCurve() are the bracketi ng
routi nes.
voi d gluNurbsCurve(GLUnurbsObj *nobj, GLi nt uknot_count, GLfl oat *uknot, GLi nt u_stride, GLfl oat *
ctlarray, GLi nt uorder, GLenum type);
Defi nes a NURBS curve for the object nobj. The arguments have the same meani ng as those for
gluNurbsSurface(). Note that thi s routi ne requi res onl y one knot sequence, and one decl arati on of the
order of the NURBS object. I f thi s curve i s defi ned wi thi n a gluBeginCurve()/ gluEndCurve() pai r, then
the type can be any of the val i d one−di mensi onal eval uator types (such as GL_MAP1_VERTEX_3 or
GL_MAP1_VERTEX_4).
Trimming
To create a tri mmed NURBS surface wi th OpenGL, start as i f you were creati ng an untri mmed
surface. After cal l i ng gluBeginSurface() and gluNurbsSurface() but before cal l i ng gluEndSurface(), start
a tri m by cal l i ng gluBeginTrim(). You can create two ki nds of tri mmi ng curves, a pi ecewi se l i near curve
wi th gluPwlCurve() or a NURBS curve wi th gluNurbsCurve(). A pi ecewi se l i near curve doesn’t l ook l i ke
what’s conventi onal l y cal l ed a curve, because i t’s a seri es of strai ght l i nes. A NURBS curve for
tri mmi ng must l i e wi thi n the uni t square of parametri c (u, v) space. The type for a NURBS tri mmi ng
curve i s usual l y GLU_MAP1_TRI M2. Less often, the type i s GLU_MAP1_TRI M3, where the curve i s
descri bed i n a two−di mensi onal homogeneous space (u’, v’, w’) by (u, v) = (u’/ w’, v’/ w’).
voi d gluPwlCurve(GLUnurbsObj *nobj, GLi nt count, GLfl oat *array, GLi nt stride, GLenum type);
Descri bes a pi ecewi se l i near tri mmi ng curve for the NURBS object nobj. There are count poi nts on the
curve, and they’re gi ven by array. The typecan be ei ther GLU_MAP1_TRI M_2 (the most common) or
GLU_MAP1_TRI M_3 ((u, v, w) homogeneous parameter space). The type affects whether stride, the
number of fl oati ng−poi nt val ues to the next vertex, i s 2 or 3.
You need to consi der the ori entati on of tri mmi ng curvesthat i s, whether they’re countercl ockwi se or
cl ockwi seto make sure you i ncl ude the desi red part of the surface. I f you i magi ne wal ki ng al ong a
curve, everythi ng to the l eft i s i ncl uded and everythi ng to the ri ght i s tri mmed away. For exampl e, i f
your tri m consi sts of a si ngl e countercl ockwi se l oop, everythi ng i nsi de the l oop i s i ncl uded. I f the tri m
consi sts of two noni ntersecti ng countercl ockwi se l oops wi th noni ntersecti ng i nteri ors, everythi ng i nsi de
ei ther of them i s i ncl uded. I f i t consi sts of a countercl ockwi se l oop wi th two cl ockwi se l oops i nsi de i t, the
tri mmi ng regi on has two hol es i n i t. The outermost tri mmi ng curve must be countercl ockwi se. Often,
you run a tri mmi ng curve around the enti re uni t square to i ncl ude everythi ng wi thi n i t, whi ch i s what
you get by defaul t by not speci fyi ng any tri mmi ng curves.
Tri mmi ng curves must be cl osed and noni ntersecti ng. You can combi ne tri mmi ng curves, so l ong as the
endpoi nts of the tri mmi ng curves meet to form a cl osed curve. You can nest curves, creati ng i sl ands
that fl oat i n space. Be sure to get the curve ori entati ons ri ght. For exampl e, an error resul ts i f you
speci fy a tri mmi ng regi on wi th two countercl ockwi se curves, one encl osed wi thi n another: The regi on
241
between the curves i s to the l eft of one and to the ri ght of the other, so i t must be both i ncl uded and
excl uded, whi ch i s i mpossi bl e. Figure 11−5 i l l ustrates a few val i d possi bi l i ti es.
Figure 11−5 Parametri c Tri mmi ng Curves
Figure 11−6shows the same smal l hi l l as i n Figure 11−4 , thi s ti me wi th a tri mmi ng curve that’s a
combi nati on of a pi ecewi se l i near curve and a NURBS curve. The program that creates thi s fi gure i s
si mi l ar to that shown i n Example 11−5 ; the di fferences are i n the routi nes shown i n Example 11−6 .
242
Figure 11−6 A Tri mmed NURBS Surface
Example 11−6 Tri mmi ng a NURBS Surface: tri m.c
void myinit(void)
{
GLfloat mat_diffuse[] = { 0.6, 0.6, 0.6, 1.0 };
GLfloat mat_specular[] = { 0.9, 0.9, 0.9, 1.0 };
GLfloat mat_shininess[] = { 128.0 };
glClearColor (0.0, 0.0, 0.0, 1.0);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glEnable(GL_AUTO_NORMAL);
glEnable(GL_NORMALIZE);
init_surface();
theNurb = gluNewNurbsRenderer();
gluNurbsProperty(theNurb, GLU_SAMPLING_TOLERANCE, 50.0);
gluNurbsProperty(theNurb, GLU_DISPLAY_MODE, GLU_FILL);
}
void display(void)
{
GLfloat knots[8] = {0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0};
GLfloat edgePt[5][2] = /* counter clockwise */
{{0.0, 0.0}, {1.0, 0.0}, {1.0, 1.0}, {0.0, 1.0},
{0.0, 0.0}};
GLfloat curvePt[4][2] = /* clockwise */
{{0.25, 0.5}, {0.25, 0.75}, {0.75, 0.75}, {0.75, 0.5}};
GLfloat curveKnots[8] =
{0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0};
GLfloat pwlPt[4][2] = /* clockwise */
{{0.75, 0.5}, {0.5, 0.25}, {0.25, 0.5}};
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(330.0, 1.,0.,0.);
glScalef (0.5, 0.5, 0.5);
gluBeginSurface(theNurb);
gluNurbsSurface(theNurb,
8, knots,
8, knots,
4 * 3,
3,
&ctlpoints[0][0][0],
4, 4,
243
GL_MAP2_VERTEX_3);
gluBeginTrim (theNurb);
gluPwlCurve(theNurb, 5, &edgePt[0][0], 2,
GLU_MAP1_TRIM_2);
gluEndTrim (theNurb);
gluBeginTrim (theNurb);
gluNurbsCurve(theNurb, 8, curveKnots, 2,
&curvePt[0][0], 4, GLU_MAP1_TRIM_2);
gluPwlCurve (theNurb, 3, &pwlPt[0][0], 2,
GLU_MAP1_TRIM_2);
gluEndTrim (theNurb);
gluEndSurface(theNurb);
glPopMatrix();
glFlush();
}
I n Example 11−6 , gluBeginTrim() and gluEndTrim() bracket each tri mmi ng curve. The fi rst tri m,
wi th verti ces defi ned by the array edgePt[][], goes countercl ockwi se around the enti re uni t square of
parametri c space. Thi s ensures that everythi ng i s drawn, provi ded i t i sn’t removed by a cl ockwi se
tri mmi ng curve i nsi de of i t. The second tri m i s a combi nati on of a NURBS tri mmi ng curve and a
pi ecewi se l i near tri mmi ng curve. The NURBS curve ends at the poi nts (0.9, 0.5) and (0.1, 0.5), where i t
i s met by the pi ecewi se l i near curve, formi ng a cl osed cl ockwi se curve.
Chapter 12
Selection and Feedback
Chapter Objectives
After readi ng thi s chapter, you’l l be abl e to do the fol l owi ng:
• Create appl i cati ons that al l ow the user to sel ect a regi on of the screen or pi ck an object drawn on
the screen
• Use OpenGL’s feedback mode to obtai n the resul ts of renderi ng cal cul ati ons
Some graphi cs appl i cati ons si mpl y draw stati c i mages of two− and three−di mensi onal objects. Other
appl i cati ons al l ow the user to i denti fy objects on the screen and then to move, modi fy, del ete, or
otherwi se mani pul ate those objects. OpenGL i s desi gned to support exactl y such i nteracti ve
appl i cati ons. Si nce objects drawn on the screen typi cal l y undergo mul ti pl e rotati ons, transl ati ons, and
perspecti ve transformati ons, i t can be di ffi cul t for you to determi ne whi ch object a user i s sel ecti ng i n a
three−di mensi onal scene. To hel p you, OpenGL provi des a sel ecti on mechani sm that automati cal l y tel l s
you whi ch objects are drawn i nsi de a speci fi ed regi on of the wi ndow. You can use thi s mechani sm
together wi th a speci al uti l i ty routi ne to determi ne whi ch object wi thi n the regi on the user i s speci fyi ng,
or picking, wi th the cursor.
Sel ecti on i s actual l y a mode of operati on for OpenGL; feedback i s another such mode. I n feedback
mode, you use your graphi cs hardware and OpenGL to perform the usual renderi ng cal cul ati ons.
I nstead of usi ng the cal cul ated resul ts to draw an i mage on the screen, however, OpenGL returns (or
feeds back) the drawi ng i nformati on to you. I f you want to draw three−di mensi onal objects on a pl otter
rather than the screen, for exampl e, you woul d draw the i tems i n feedback mode, col l ect the drawi ng
i nstructi ons, and then convert them to commands the pl otter can understand.
I n both sel ecti on and feedback modes, drawi ng i nformati on i s returned to the appl i cati on rather than
bei ng sent to the framebuffer, as i t i s i n renderi ng mode. Thus, the screen remai ns frozenno drawi ng
occurswhi l e OpenGL i s i n sel ecti on or feedback mode. Thi s chapter expl ai ns each of these modes i n
i ts own secti on:
244
• "Selection"di scusses how to use sel ecti on mode and rel ated routi nes to al l ow a user of your
appl i cati on to pi ck an object drawn on the screen.
• "Feedback"descri bes how to obtai n i nformati on about what woul d be drawn on the screen and
how that i nformati on i s formatted.
Selection
Typi cal l y, when you’re pl anni ng to use OpenGL’s sel ecti on mechani sm, you fi rst draw your scene i nto
the framebuffer and then you enter sel ecti on mode and redraw the scene. Once you’re i n sel ecti on
mode, however, the contents of the framebuffer don’t change unti l you exi t sel ecti on mode. When you
exi t, OpenGL returns a l i st of the pri mi ti ves that woul d have i ntersected the vi ewi ng vol ume
(remember that the vi ewi ng vol ume i s defi ned by the current model vi ew and projecti on matri ces and
any cl i ppi ng pl anes you’ve speci fi ed, as expl ai ned i n "Additional Clipping Planes.") Each pri mi ti ve
that i ntersects the vi ewi ng vol ume causes a sel ecti on hit. The l i st of pri mi ti ves i s actual l y returned as
an array of i nteger−val ued names and rel ated datathe hit recordsthat correspond to the current
contents of the namestack. You construct the name stack by l oadi ng names onto i t as you i ssue
pri mi ti ve drawi ng commands whi l e i n sel ecti on mode. Thus, when the l i st of names i s returned, you
can use i t to determi ne whi ch pri mi ti ves mi ght have been sel ected on the screen by the user.
I n addi ti on to thi s sel ecti on mechani sm, OpenGL provi des a uti l i ty routi ne desi gned to si mpl i fy
sel ecti on i n some cases by restri cti ng drawi ng to a smal l regi on of the vi ewport. Typi cal l y, you use thi s
routi ne to determi ne whi ch objects are drawn near the cursor, so that you can i denti fy whi ch object the
user i s pi cki ng. You can al so del i mi t a sel ecti on regi on by speci fyi ng addi ti onal cl i ppi ng pl anes; see
"Additional Clipping Planes" for more i nformati on about how to do thi s. Si nce pi cki ng i s a speci al
case of sel ecti on, sel ecti on i s descri bed fi rst i n thi s chapter, and then pi cki ng.
The Basic Steps
To use the sel ecti on mechani sm, you need to perform the fol l owi ng steps.
1. Speci fy the array to be used for the returned hi t records wi th glSelectBuffer().
2. Enter sel ecti on mode by speci fyi ng GL_SELECT wi th glRenderMode().
3. I ni ti al i ze the name stack usi ng glI nitNames() and glPushName().
4. Defi ne the vi ewi ng vol ume you want to use for sel ecti on. Usual l y, thi s i s di fferent from the vi ewi ng
vol ume you used to draw the scene ori gi nal l y, so you probabl y want to save and then restore the
current transformati on state wi th glPushMatrix() and glPopMatrix().
5. Al ternatel y i ssue pri mi ti ve drawi ng commands and commands to mani pul ate the name stack so
that each pri mi ti ve of i nterest has an appropri ate name assi gned.
6. Exi t sel ecti on mode and process the returned sel ecti on data (the hi t records).
The fol l owi ng paragraphs descri be glSelectBuffer() and glRenderMode(). I n the next secti on, the
commands to mani pul ate the name stack are descri bed.
voi d glSelectBuffer(GLsi zei size, GLui nt *buffer);
Speci fi es the array to be used for the returned sel ecti on data. The buffer argument i s a poi nter to an
array of unsi gned i ntegers i nto whi ch the data i s put, and sizei ndi cates the maxi mum number of
val ues that can be stored i n the array. You need to cal l glSelectBuffer() before enteri ng sel ecti on mode.
GLi nt glRenderMode(GLenum mode);
Control s whether the appl i cati on i s i n renderi ng, sel ecti on, or feedback mode. The modeargument can
be one of GL_RENDER (the defaul t), GL_SELECT, or GL_FEEDBACK. The appl i cati on remai ns i n a
245
gi ven mode unti l glRenderMode() i s cal l ed agai n wi th a di fferent argument. Before enteri ng sel ecti on
mode, glSelectBuffer() must be cal l ed to speci fy the sel ecti on array. Si mi l arl y, before enteri ng feedback
mode, glFeedbackBuffer() must be cal l ed to speci fy the feedback array. The return val ue for
glRenderMode() has meani ng i f the current render mode (that i s, not the modeparameter) i s ei ther
GL_SELECT or GL_FEEDBACK: The return val ue i s the number of sel ecti on hi ts or the number of
val ues pl aced i n the feedback array when ei ther mode i s exi ted; a negati ve val ue means that the
sel ecti on or feedback array has overfl owed. You can use GL_RENDER_MODE wi th glGetI ntegerv() to
obtai n the current mode.
Creating the Name Stack
As menti oned i n the previ ous secti on, the name stack forms the basi s for the sel ecti on i nformati on
that’s returned to you. To create the name stack, fi rst you i ni ti al i ze i t wi th glI nitNames(), whi ch si mpl y
cl ears the stack, and then you add i nteger names to i t as you i ssue correspondi ng drawi ng commands.
As you mi ght expect, the commands to mani pul ate the stack al l ow you to push a name onto i t (
glPushName()), pop a name off of i t (glPopName()), and repl ace the name on the top of the stack wi th a
di fferent one (glLoadName()). Example 12−1 shows what your name−stack mani pul ati on code mi ght
l ook l i ke wi th these commands.
Example 12−1 Creati ng a Name Stack
glInitNames();
glPushName(−1);
glPushMatrix(); /* save the current transformation state */
/* create your desired viewing volume here */
glLoadName(1);
drawSomeObject();
glLoadName(2);
drawAnotherObject();
glLoadName(3);
drawYetAnotherObject();
drawJustOneMoreObject();
glPopMatrix (); /* restore the previous transformation state*/
I n thi s exampl e, the fi rst two objects to be drawn have thei r own names, and the thi rd and fourth
objects share a si ngl e name. Wi th thi s setup, i f ei ther or both of the thi rd and fourth objects causes a
sel ecti on hi t, onl y one hi t record i s returned to you. You can have mul ti pl e objects share the same name
i f you don’t need to di fferenti ate between them when processi ng the hi t records.
voi d glI nitNames(voi d);
Cl ears the name stack so that i t’s empty.
voi d glPushName(GLui nt name);
Pushes nameonto the name stack. Pushi ng a name beyond the capaci ty of the stack generates the error
GL_STACK_OVERFLOW. The name stack’s depth can vary among di fferent OpenGL
i mpl ementati ons, but i t must be abl e to contai n at l east si xty−four names. You can use the parameter
GL_NAME_STACK_DEPTH wi th glGetI ntegerv() to obtai n the depth of the name stack.
voi d glPopName(voi d);
246
Pops one name off the top of the name stack. Poppi ng an empty stack generates the error
GL_STACK_UNDERFLOW.
voi d glLoadName(GLui nt name);
Repl aces the val ue on the top of the name stack wi th name. I f the stack i s empty, whi ch i t i s ri ght after
glI nitNames() i s cal l ed, glLoadName() generates the error GL_I NVALI D_OPERATI ON. To avoi d thi s,
i f the stack i s i ni ti al l y empty, cal l glPushName() at l east once to put somethi ng on the name stack
before cal l i ng glLoadName().
Cal l s to glPushName(), glPopName(), and glLoadName() are i gnored i f you’re not i n sel ecti on mode. You
mi ght fi nd that i t si mpl i fi es your code to use these cal l s throughout your drawi ng code, and then use
the same drawi ng code for both sel ecti on and normal renderi ng modes.
The Hit Record
I n sel ecti on mode, a pri mi ti ve that i ntersects the vi ewi ng vol ume causes a sel ecti on hi t. Whenever a
name−stack mani pul ati on command i s executed or glRenderMode() i s cal l ed, OpenGL wri tes a hi t
record i nto the sel ecti on array i f there’s been a hi t si nce the l ast ti me the stack was mani pul ated or
glRenderMode() was cal l ed. Wi th thi s process, objects that share the same namefor exampl e, an
object that’s composed of more than one pri mi ti vedon’t generate mul ti pl e hi t records. Al so, hi t
records aren’t guaranteed to be wri tten i nto the array unti l glRenderMode() i s cal l ed.
Note: I n addi ti on to pri mi ti ves, val i d coordi nates produced by glRasterPos() can cause a sel ecti on hi t.
I n the case of pol ygons, no hi t occurs i f the pol ygon woul d have been cul l ed.
Each hi t record consi sts of four i tems, i n order:
• The number of names on the name stack when the hi t occurred.
• Both the mi ni mum and maxi mum wi ndow−coordi nate z val ues of al l verti ces of the pri mi ti ves that
i ntersected the vi ewi ng vol ume si nce the l ast recorded hi t. These two val ues, whi ch l i e i n the range
[0,1], are each mul ti pl i ed by 2
32
−1 and rounded to the nearest unsi gned i nteger.
• The contents of the name stack at the ti me of the hi t, wi th the bottommost el ement fi rst.
When you enter sel ecti on mode, OpenGL i ni ti al i zes a poi nter to the begi nni ng of the sel ecti on array.
Each ti me a hi t record i s wri tten i nto the array, the poi nter i s updated accordi ngl y. I f wri ti ng a hi t
record woul d cause the number of val ues i n the array to exceed the sizeargument speci fi ed wi th
glSelectBuffer(), OpenGL wri tes as much of the record as fi ts i n the array and sets an overfl ow fl ag.
When you exi t sel ecti on mode wi th glRenderMode(), thi s command returns the number of hi t records
that were wri tten (i ncl udi ng a parti al record i f there was one), cl ears the name stack, resets the
overfl ow fl ag, and resets the stack poi nter. I f the overfl ow fl ag had been set, the return val ue i s −1.
A Selection Example
I n Example 12−2 , four tri angl es (green, red, and two yel l ow ones) are drawn i n sel ecti on mode, and
the correspondi ng hi t records are processed. The fi rst tri angl e generates a hi t, the second one doesn’t,
and the thi rd and fourth ones together generate a si ngl e hi t. Routi nes are defi ned to draw a tri angl e (
drawTriangle()) and to draw a wi reframe box representi ng the vi ewi ng vol ume (drawViewVolume()).
The processHits() routi ne pri nts out the sel ecti on array. Fi nal l y, selectObjects() draws the tri angl es i n
sel ecti on mode to generate the hi t records.
Example 12−2 A Sel ecti on Exampl e: sel ect.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
void drawTriangle (GLfloat x1, GLfloat y1, GLfloat x2,
247
GLfloat y2, GLfloat x3, GLfloat y3, GLfloat z)
{
glBegin (GL_TRIANGLES);
glVertex3f (x1, y1, z);
glVertex3f (x2, y2, z);
glVertex3f (x3, y3, z);
glEnd ();
}
void drawViewVolume (GLfloat x1, GLfloat x2, GLfloat y1,
GLfloat y2, GLfloat z1, GLfloat z2)
{
glColor3f (1.0, 1.0, 1.0);
glBegin (GL_LINE_LOOP);
glVertex3f (x1, y1, −z1);
glVertex3f (x2, y1, −z1);
glVertex3f (x2, y2, −z1);
glVertex3f (x1, y2, −z1);
glEnd ();
glBegin (GL_LINE_LOOP);
glVertex3f (x1, y1, −z2);
glVertex3f (x2, y1, −z2);
glVertex3f (x2, y2, −z2);
glVertex3f (x1, y2, −z2);
glEnd ();
glBegin (GL_LINES); /* 4 lines */
glVertex3f (x1, y1, −z1);
glVertex3f (x1, y1, −z2);
glVertex3f (x1, y2, −z1);
glVertex3f (x1, y2, −z2);
glVertex3f (x2, y1, −z1);
glVertex3f (x2, y1, −z2);
glVertex3f (x2, y2, −z1);
glVertex3f (x2, y2, −z2);
glEnd ();
}
void drawScene (void)
{
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluPerspective (40.0, 4.0/3.0, 0.01, 100.0);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
gluLookAt (7.5, 7.5, 12.5, 2.5, 2.5, −5.0, 0.0, 1.0, 0.0);
glColor3f (0.0, 1.0, 0.0); /* green triangle */
drawTriangle (2.0, 2.0, 3.0, 2.0, 2.5, 3.0, −5.0);
glColor3f (1.0, 0.0, 0.0); /* red triangle */
drawTriangle (2.0, 7.0, 3.0, 7.0, 2.5, 8.0, −5.0);
glColor3f (1.0, 1.0, 0.0); /* yellow triangles */
drawTriangle (2.0, 2.0, 3.0, 2.0, 2.5, 3.0, 0.0);
248
drawTriangle (2.0, 2.0, 3.0, 2.0, 2.5, 3.0, −10.0);
drawViewVolume (0.0, 5.0, 0.0, 5.0, 0.0, 10.0);
}
void processHits (GLint hits, GLuint buffer[])
{
unsigned int i, j;
GLuint names, *ptr;
printf ("hits = %d\n", hits);
ptr = (GLuint *) buffer;
for (i = 0; i < hits; i++) { /* for each hit */
names = *ptr;
printf(" number of names for hit = %d\n", names); ptr++;
printf (" z1 is %u;", *ptr); ptr++;
printf (" z2 is %u\n", *ptr); ptr++;
printf (" the name is ");
for (j = 0; j < names; j++) { /* for each name */
printf ("%d ", *ptr); ptr++;
}
printf ("\n");
}
}
#define BUFSIZE 512
void selectObjects(void)
{
GLuint selectBuf[BUFSIZE];
GLint hits, viewport[4];
glSelectBuffer (BUFSIZE, selectBuf);
(void) glRenderMode (GL_SELECT);
glInitNames();
glPushName(−1);
glPushMatrix ();
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glOrtho (0.0, 5.0, 0.0, 5.0, 0.0, 10.0);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
glLoadName(1);
drawTriangle (2.0, 2.0, 3.0, 2.0, 2.5, 3.0, −5.0);
glLoadName(2);
drawTriangle (2.0, 7.0, 3.0, 7.0, 2.5, 8.0, −5.0);
glLoadName(3);
drawTriangle (2.0, 2.0, 3.0, 2.0, 2.5, 3.0, 0.0);
drawTriangle (2.0, 2.0, 3.0, 2.0, 2.5, 3.0, −10.0);
glPopMatrix ();
glFlush ();
hits = glRenderMode (GL_RENDER);
249
processHits (hits, selectBuf);
}
void myinit (void)
{
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_FLAT);
}
void display(void)
{
glClearColor (0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawScene ();
selectObjects ();
glFlush();
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA | AUX_DEPTH);
auxInitPosition (0, 0, 200, 200);
auxInitWindow (argv[0]);
myinit ();
auxMainLoop(display);
}
Picking
As an extensi on of the process descri bed i n the previ ous secti on, you can use sel ecti on mode to
determi ne i f objects are pi cked. To do thi s, you use a speci al pi cki ng matri x i n conjuncti on wi th the
projecti on matri x to restri ct drawi ng to a smal l regi on of the vi ewport, typi cal l y near the cursor. Then
you al l ow some form of i nput, such as cl i cki ng a mouse button, to i ni ti ate sel ecti on mode. Wi th
sel ecti on mode establ i shed and wi th the speci al pi cki ng matri x used, objects that are drawn near the
cursor cause sel ecti on hi ts. Thus, duri ng pi cki ng you’re typi cal l y determi ni ng whi ch objects are drawn
near the cursor.
Pi cki ng i s set up al most exactl y l i ke regul ar sel ecti on mode i s, wi th the fol l owi ng major di fferences:
• Pi cki ng i s usual l y tri ggered by an i nput devi ce. I n the fol l owi ng code exampl es, pressi ng the l eft
mouse button i nvokes a functi on that performs pi cki ng.
• You use the uti l i ty routi ne gluPickMatrix() to mul ti pl y a speci al projecti on matri x onto the current
matri x. Thi s routi ne shoul d be cal l ed pri or to mul ti pl yi ng a projecti on matri x onto the stack.
Another, compl etel y di fferent way to perform pi cki ng i s descri bed i n "Object Selection Using the
Back Buffer." Thi s techni que uses col or val ues to i denti fy di fferent components of an object.
voi d gluPickMatrix(GLdoubl e x, GLdoubl e y, GLdoubl e width, GLdoubl e height, GLi nt viewport[4]);
Creates a projecti on matri x that restri cts drawi ng to a smal l regi on of the vi ewport and mul ti pl i es that
matri x onto the current matri x stack. The center of the pi cki ng regi on i s (x, y) i n wi ndow coordi nates,
typi cal l y the cursor l ocati on. width and height defi ne the si ze of the pi cki ng regi on i n screen
coordi nates. (You can thi nk of the wi dth and hei ght as the sensi ti vi ty of the pi cki ng devi ce.) viewport[]
i ndi cates the current vi ewport boundari es, whi ch can be obtai ned by cal l i ng
250
glGetIntegerv(GL_VIEWPORT, GLint *viewport);
Advanced
The net resul t of the matri x created by gluPickMatrix() i s to transform the cl i ppi ng regi on i nto the uni t
cube −1 ≤ (x, y, z) ≤ 1 (or −w≤ (wx, wy, wz) ≤w). The pi cki ng matri x effecti vel y performs an orthogonal
transformati on that maps a subregi on of thi s uni t cube to the uni t cube. Si nce the transformati on i s
arbi trary, you can make pi cki ng work for di fferent sorts of regi onsfor exampl e, for rotated
rectangul ar porti ons of the wi ndow. I n certai n si tuati ons, you mi ght fi nd i t easi er to speci fy addi ti onal
cl i ppi ng pl anes to defi ne the pi cki ng regi on.
Example 12−3 i l l ustrates si mpl e pi cki ng. I t al so demonstrates how to use mul ti pl e names to i denti fy
di fferent components of a pri mi ti ve, i n thi s case the row and col umn of a sel ected object. A 3×3 gri d of
squares i s drawn, wi th each square a di fferent col or. The board[3][3] array mai ntai ns the current
amount of bl ue for each square. When the l eft mouse button i s pressed, the pickSquares() routi ne i s
cal l ed to i denti fy whi ch squares were pi cked by the mouse. Two names i denti fy each square i n the gri d
one i denti fi es the row, and the other the col umn. Al so, when the l eft mouse button i s pressed, the
col or of al l squares under the cursor posi ti on changes.
Example 12−3 A Pi cki ng Exampl e: pi cksquare.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
int board[3][3]; /* amount of color for each square */
/* Clear color value for every square on the board */
void myinit(void)
{
int i, j;
for (i = 0; i < 3; i++)
for (j = 0; j < 3; j ++)
board[i][j] = 0;
glClearColor (0.0, 0.0, 0.0, 0.0);
}
void drawSquares(GLenum mode)
{
GLuint i, j;
for (i = 0; i < 3; i++) {
if (mode == GL_SELECT)
glLoadName (i);
for (j = 0; j < 3; j ++) {
if (mode == GL_SELECT)
glPushName (j);
glColor3f ((GLfloat) i/3.0, (GLfloat) j/3.0,
(GLfloat) board[i][j]/3.0);
glRecti (i, j, i+1, j+1);
if (mode == GL_SELECT)
glPopName ();
}
}
}
void processHits (GLint hits, GLuint buffer[])
251
{
unsigned int i, j;
GLuint ii, jj, names, *ptr;
printf ("hits = %d\n", hits);
ptr = (GLuint *) buffer;
for (i = 0; i < hits; i++) { /* for each hit */
names = *ptr;
printf (" number of names for this hit = %d\n", names);
ptr++;
printf (" z1 is %u;", *ptr); ptr++;
printf (" z2 is %u\n", *ptr); ptr++;
printf (" names are ");
for (j = 0; j < names; j++) { /* for each name */
printf ("%d ", *ptr);
if (j == 0) /* set row and column */
ii = *ptr;
else if (j == 1)
jj = *ptr;
ptr++;
}
printf ("\n");
board[ii][jj] = (board[ii][jj] + 1) % 3;
}
}
#define BUFSIZE 512
void pickSquares(AUX_EVENTREC *event)
{
GLuint selectBuf[BUFSIZE];
GLint hits;
GLint viewport[4];
int x, y;
x = event−>data[AUX_MOUSEX];
y = event−>data[AUX_MOUSEY];
glGetIntegerv (GL_VIEWPORT, viewport);
glSelectBuffer (BUFSIZE, selectBuf);
(void) glRenderMode (GL_SELECT);
glInitNames();
glPushName(−1);
glMatrixMode (GL_PROJECTION);
glPushMatrix ();
glLoadIdentity ();
/* create 5x5 pixel picking region near cursor location */
gluPickMatrix((GLdouble) x,
(GLdouble) (viewport[3] − y), 5.0, 5.0, viewport);
gluOrtho2D (0.0, 3.0, 0.0, 3.0);
drawSquares (GL_SELECT);
glPopMatrix ();
252
glFlush ();
hits = glRenderMode (GL_RENDER);
processHits (hits, selectBuf);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
drawSquares (GL_RENDER);
glFlush();
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D (0.0, 3.0, 0.0, 3.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
auxInitPosition (0, 0, 100, 100);
auxInitWindow (argv[0]);
myinit ();
auxMouseFunc (AUX_LEFTBUTTON, AUX_MOUSEDOWN, pickSquares);
auxReshapeFunc (myReshape);
auxMainLoop(display);
}
Picking with Multiple Names and a Hierarchical Model
Mul ti pl e names can al so be used to choose parts of a hi erarchi cal object i n a scene. For exampl e, i f you
were renderi ng an assembl y l i ne of automobi l es, you mi ght want the user to move the mouse to pi ck the
thi rd bol t on the l eft front ti re of the thi rd car i n l i ne. A di fferent name can be used to i denti fy each
l evel of hi erarchy: whi ch car, whi ch ti re, and fi nal l y whi ch bol t. As another exampl e, one name can be
used to descri be a si ngl e mol ecul e among other mol ecul es, and addi ti onal names can di fferenti ate
i ndi vi dual atoms wi thi n that mol ecul e.
Example 12−4 i s a modi fi cati on of Example 3−4 that draws an automobi l e wi th four i denti cal
wheel s, each of whi ch has fi ve i denti cal bol ts. Code has been added to mani pul ate the name stack wi th
the object hi erarchy.
Example 12−4 Creati ng Mul ti pl e Names
draw_wheel_and_bolts()
{
long i;
draw_wheel_body();
253
for (i = 0; i < 5; i++) {
glPushMatrix();
glRotate(72.0*i, 0.0, 0.0, 1.0);
glTranslatef(3.0, 0.0, 0.0);
glPushName(i);
draw_bolt_body();
glPopName();
glPopMatrix();
}
}
draw_body_and_wheel_and_bolts()
{
draw_car_body();
glPushMatrix();
glTranslate(40, 0, 20); /* first wheel position*/
glPushName(1); /* name of wheel number 1 */
draw_wheel_and_bolts();
glPopName();
glPopMatrix();
glPushMatrix();
glTranslate(40, 0, −20); /* second wheel position */
glPushName(2); /* name of wheel number 2 */
draw_wheel_and_bolts();
glPopName();
glPopMatrix();
/* draw last two wheels similarly */
}
Example 12−5 uses the routi nes i n Example 12−4 to draw three di fferent cars, numbered 1, 2, and
3.
Example 12−5 Usi ng Mul ti pl e Names
draw_three_cars()
{
glInitNames();
glPushMatrix();
translate_to_first_car_position();
glPushName(1);
draw_body_and_wheel_and_bolts();
glPopName();
glPopMatrix();
glPushMatrix();
translate_to_second_car_position();
glPushName(2);
draw_body_and_wheel_and_bolts();
glPopName();
glPopMatrix();
glPushMatrix();
translate_to_third_car_position();
glPushName(3);
254
draw_body_and_wheel_and_bolts();
glPopName();
glPopMatrix();
}
Assumi ng that pi cki ng i s performed, the fol l owi ng are some possi bl e name−stack return val ues and
thei r i nterpretati ons. I n these exampl es, at most one hi t record i s returned; al so, d1 and d2 are depth
val ues.
empty The pi ck was outsi de al l cars
2 d1d2 2 1 Car 2, wheel 1
1 d1d2 3 Car 3 body
3 d1d2 1 1 0 Bol t 0 on wheel 1 on car 1
The l ast i nterpretati on assumes that the bol t and wheel don’t occupy the same pi cki ng regi on. A user
mi ght wel l pi ck both the wheel and the bol t, yi el di ng two hi ts. I f you recei ve mul ti pl e hi ts, you have to
deci de whi ch hi t to process, perhaps by usi ng the depth val ues to determi ne whi ch pi cked object i s
cl osest to the vi ewpoi nt. The use of depth val ues i s expl ored further i n the next secti on.
Picking and Depth Values
Example 12−6 demonstrates how to use depth val ues when pi cki ng to determi ne whi ch object i s
pi cked. Thi s program draws three overl appi ng rectangl es i n normal renderi ng mode. When the l eft
mouse button i s pressed, the pickRects() routi ne i s cal l ed. Thi s routi ne returns the cursor posi ti on,
enters sel ecti on mode, i ni ti al i zes the name stack, and mul ti pl i es the pi cki ng matri x onto the stack
before the orthographi c projecti on matri x. A sel ecti on hi t occurs for each rectangl e the cursor i s over
when the l eft mouse button i s cl i cked. Fi nal l y, the contents of the sel ecti on buffer i s exami ned to
i denti fy whi ch named objects were wi thi n the pi cki ng regi on near the cursor.
The rectangl es i n thi s program are drawn at di fferent depth, or z, val ues. Si nce onl y one name i s used
to i denti fy al l three rectangl es, onl y one hi t can be recorded. However, i f more than one rectangl e i s
pi cked, that si ngl e hi t has di fferent mi ni mum and maxi mum z val ues.
Example 12−6 Pi cki ng wi th Depth Val ues: pi ckdepth.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
void myinit(void)
{
glClearColor (0.0, 0.0, 0.0, 0.0);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_FLAT);
glDepthRange (0.0, 1.0); /* The default z mapping */
}
void drawRects(GLenum mode)
{
if (mode == GL_SELECT)
glLoadName (1);
glBegin (GL_QUADS);
glColor3f (1.0, 1.0, 0.0);
glVertex3i (2, 0, 0);
glVertex3i (2, 6, 0);
255
glVertex3i (6, 6, 0);
glVertex3i (6, 0, 0);
glColor3f (0.0, 1.0, 1.0);
glVertex3i (3, 2, −1);
glVertex3i (3, 8, −1);
glVertex3i (8, 8, −1);
glVertex3i (8, 2, −1);
glColor3f (1.0, 0.0, 1.0);
glVertex3i (0, 2, −2);
glVertex3i (0, 7, −2);
glVertex3i (5, 7, −2);
glVertex3i (5, 2, −2);
glEnd ();
}
void processHits (GLint hits, GLuint buffer[])
{
unsigned int i, j;
GLuint names, *ptr;
printf ("hits = %d\n", hits);
ptr = (GLuint *) buffer;
for (i = 0; i < hits; i++) { /* for each hit */
names = *ptr;
printf (" number of names for hit = %d\n", names);
ptr++;
printf (" z1 is %u;", *ptr); ptr++;
printf (" z2 is %u\n", *ptr); ptr++;
printf (" the name is ");
for (j = 0; j < names; j++) { /* for each name */
printf ("%d ", *ptr); ptr++;
}
printf ("\n");
}
}
#define BUFSIZE 512
void pickRects(AUX_EVENTREC *event)
{
GLuint selectBuf[BUFSIZE];
GLint hits;
GLint viewport[4];
int x, y;
x = event−>data[AUX_MOUSEX];
y = event−>data[AUX_MOUSEY];
glGetIntegerv (GL_VIEWPORT, viewport);
glSelectBuffer (BUFSIZE, selectBuf);
(void) glRenderMode (GL_SELECT);
glInitNames();
glPushName(−1);
256
glMatrixMode (GL_PROJECTION);
glPushMatrix ();
glLoadIdentity ();
/* create 5x5 pixel picking region near cursor location */
gluPickMatrix ((GLdouble) x,
(GLdouble) (viewport[3] − y), 5.0, 5.0, viewport);
glOrtho (0.0, 8.0, 0.0, 8.0, 0.0, 2.0);
drawRects (GL_SELECT);
glPopMatrix ();
glFlush ();
hits = glRenderMode (GL_RENDER);
processHits (hits, selectBuf);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawRects (GL_RENDER);
glFlush();
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho (0.0, 8.0, 0.0, 8.0, 0.0, 2.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA | AUX_DEPTH);
auxInitPosition (0, 0, 100, 100);
auxInitWindow (argv[0]);
myinit ();
auxMouseFunc (AUX_LEFTBUTTON, AUX_MOUSEDOWN, pickRects);
auxReshapeFunc (myReshape);
auxMainLoop(display);
}
Try This
Try This
• Modi fy Example 12−6 to add addi ti onal cal l s to glPushName() so that mul ti pl e names are on the
stack when the sel ecti on hi t occurs. What wi l l the contents of the sel ecti on buffer be?
• By defaul t, glDepthRange() sets the mappi ng of the z val ues to [0.0,1.0]. Try modi fyi ng the
glDepthRange() val ues and see how i t affects the z val ues that are returned i n the sel ecti on array.
257
Hints for Writing a Program That Uses Selection
Most programs that al l ow a user to i nteracti vel y edi t some geometry provi de a mechani sm for the user
to pi ck i tems or groups of i tems for edi ti ng. For two−di mensi onal drawi ng programs (for exampl e, text
edi tors, page−l ayout programs, ci rcui t−desi gn programs), i t mi ght be easi er to do your own pi cki ng
cal cul ati ons i nstead of usi ng the OpenGL pi cki ng mechani sm. Often, i t’s easy to fi nd boundi ng boxes
for two−di mensi onal objects and to organi ze them i n some hi erarchi cal data structure to speed up
searches. For exampl e, OpenGL−styl e pi cki ng i n a VLSI l ayout program that has mi l l i ons of rectangl es
can be rel ati vel y sl ow. However, usi ng si mpl e boundi ng−box i nformati on when rectangl es are typi cal l y
al i gned wi th the screen coul d make pi cki ng i n such a program extremel y fast. The code i s probabl y
si mpl er to wri te, too.
As another exampl e, si nce onl y geometri c objects cause hi ts, you mi ght want to create your own method
for pi cki ng text. Setti ng the current raster posi ti on i s a geometri c operati on, but i t effecti vel y creates
onl y a si ngl e pi ckabl e poi nt at the current raster posi ti on, whi ch i s typi cal l y at the l ower l eft−hand
corner of the text. I f your edi tor needs to mani pul ate i ndi vi dual characters wi thi n a text stri ng, some
other pi cki ng mechani sm must be used. You coul d draw l i ttl e rectangl es around each character duri ng
pi cki ng mode, but i t’s al most certai nl y easi er to handl e text as a speci al case.
I f you deci de to use OpenGL pi cki ng, organi ze your program and i ts data structures so that i t’s easy to
draw appropri ate l i sts of objects i n ei ther sel ecti on or normal drawi ng mode. Thi s way, when the user
pi cks somethi ng, you can use the same data structures for the pi ck operati on that you use to di spl ay
the i tems on the screen. Al so, consi der whether you want to al l ow the user to sel ect mul ti pl e objects.
One way to do thi s i s to store a bi t for each i tem i ndi cati ng whether i t’s sel ected, but wi th thi s method,
you have to traverse your enti re l i st of i tems to fi nd the sel ected i tems. You mi ght fi nd i t useful to
mai ntai n a l i st of poi nters to sel ected i tems to speed up thi s search. I t’s probabl y a good i dea to keep the
sel ecti on bi t for each i tem as wel l , si nce when you’re drawi ng the enti re pi cture, you mi ght want to
draw sel ected i tems di fferentl y (for exampl e, i n a di fferent col or or wi th a sel ecti on box around them).
Fi nal l y, consi der the sel ecti on user i nterface. You mi ght want to al l ow the user to do the fol l owi ng:
• Sel ect an i tem
• Sweep−sel ect a group of i tems (see the next paragraphs for a descri pti on of thi s behavi or)
• Add an i tem to the sel ecti on
• Add a sweep sel ecti on to the current sel ecti ons
• Del ete an i tem from a sel ecti on
• Choose a si ngl e i tem from a group of overl appi ng i tems
A typi cal sol uti on for a two−di mensi onal drawi ng program mi ght work as fol l ows.
1. Al l sel ecti on i s done by poi nti ng wi th the mouse cursor and usi ng the l eft mouse button. I n what
fol l ows, cursor means the cursor ti ed to the mouse, and button means the l eft mouse button.
2. Cl i cki ng on an i tem sel ects i t and desel ects al l other currentl y sel ected i tems. I f the cursor i s on top
of mul ti pl e i tems, the smal l est i s sel ected. (I n three di mensi ons, many other strategi es work to
di sambi guate a sel ecti on.)
3. Cl i cki ng down where there i s no i tem, hol di ng the button down whi l e draggi ng the cursor, and then
rel easi ng the button sel ects al l the i tems i n a screen−al i gned rectangl e whose corners are
determi ned by the cursor posi ti ons when the button went down and where i t came up. Thi s i s cal l ed
a sweep selection. Al l i tems not i n the swept−out regi on are desel ected. (You must deci de whether
an i tem i s sel ected onl y i f i t’s compl etel y wi thi n the sweep regi on, or i f any part of i t fal l s wi thi n the
regi on. The compl etel y wi thi n strategy usual l y works best.)
4. I f the Shi ft key i s hel d down and the user cl i cks on an i tem that i sn’t currentl y sel ected, that i tem i s
added to the sel ected l i st. I f the cl i cked−upon i tem i s sel ected, i t’s del eted from the sel ecti on l i st.
5. I f a sweep sel ecti on i s performed wi th the Shi ft key pressed, the i tems swept out are added to the
current sel ecti on.
6. I n an extremel y cl uttered regi on, i t’s often hard to do a sweep sel ecti on. When the button goes
down, the cursor mi ght l i e on top of some i tem, and normal l y, that i tem woul d be sel ected. You can
258
make any operati on a sweep sel ecti on, but a typi cal user i nterface i nterprets a button−down on an
i tem pl us a mouse moti on as a sel ect−pl us−drag operati on. To sol ve thi s probl em, you can have an
enforced sweep sel ecti on by hol di ng down, say, the Al t key. Wi th thi s, the fol l owi ng set of
operati ons consti tutes a sweep sel ecti on: Al t−button down, sweep, button up. I tems under the
cursor when the button goes down are i gnored.
7. I f the Shi ft key i s hel d duri ng thi s sweep sel ecti on, the i tems encl osed i n the sweep regi on are added
to the current sel ecti on.
8. Fi nal l y, i f the user cl i cks on mul ti pl e i tems, sel ect just one of them. I f the cursor i sn’t moved (or
maybe not moved more than a pi xel ), and the user cl i cks agai n i n the same pl ace, desel ect the i tem
ori gi nal l y sel ected, and sel ect a di fferent i tem under the cursor. Use repeated cl i cks at the same
poi nt to cycl e through al l the possi bi l i ti es.
Di fferent rul es can appl y i n parti cul ar si tuati ons. I n a text edi tor, you probabl y don’t have to worry
about characters on top of each other, and sel ecti ons of mul ti pl e characters are al ways conti guous
characters i n the document. Thus, you need to mark onl y the fi rst and l ast sel ected characters to
i denti fy the compl ete sel ecti on. Wi th text, often the best way to handl e sel ecti on i s to i denti fy the
posi ti ons between characters rather than the characters themsel ves. Thi s al l ows you to have an empty
sel ecti on when the begi nni ng and end of the sel ecti on are between the same pai r of characters, and to
put the cursor before the fi rst character i n the document or after the fi nal one wi th no speci al −case
code.
I n three−di mensi onal edi tors, you mi ght provi de ways to rotate and zoom between sel ecti ons, so
sophi sti cated schemes for cycl i ng through the possi bl e sel ecti ons mi ght be unnecessary. On the other
hand, sel ecti on i n three di mensi ons i s di ffi cul t because the cursor’s posi ti on on the screen usual l y gi ves
no i ndi cati on of i ts depth.
Feedback
Feedback i s si mi l ar to sel ecti on i n that once you’re i n ei ther mode, no pi xel s are produced and the
screen i s frozen. I nstead of drawi ng occurri ng, i nformati on about pri mi ti ves that woul d have been
rendered i s sent back to the appl i cati on. The key di fference between sel ecti on and feedback modes i s
what i nformati on i s sent back. I n sel ecti on mode, assi gned names are returned to an array of i nteger
val ues. I n feedback mode, i nformati on about transformed pri mi ti ves i s sent back to an array of
fl oati ng−poi nt val ues. The val ues sent back to the feedback array consi st of tokens that speci fy what
type of pri mi ti ve (poi nt, l i ne, pol ygon, i mage, or bi tmap) has been processed and transformed, fol l owed
by vertex, col or, or other data for that pri mi ti ve. The val ues returned are ful l y transformed by l i ghti ng
and vi ewi ng operati ons. Feedback mode i s i ni ti ated by cal l i ng glRenderMode() wi th GL_FEEDBACK as
the argument.
Here’s how you enter and exi t feedback mode:
1. Cal l glFeedbackBuffer() to speci fy the array to hol d the feedback i nformati on. The arguments to thi s
command descri be what type of data and how much of i t gets wri tten i nto the array.
2. Cal l glRenderMode() wi th GL_FEEDBACK as the argument to enter feedback mode. (You can
i gnore the val ue returned by glRenderMode().) After thi s poi nt, unti l you exi t feedback mode,
pri mi ti ves aren’t rasteri zed to produce pi xel s, and the contents of the framebuffer don’t change.
3. Draw your pri mi ti ves. As you i ssue drawi ng commands, you can make several cal l s to
glPassThrough() to i nsert markers i nto the returned feedback data to hel p you parse i t more easi l y.
4. Exi t feedback mode by cal l i ng glRenderMode(), wi th GL_RENDER as the argument i f you want to
return to normal drawi ng mode. The i nteger val ue returned by glRenderMode() i s the number of
val ues stored i n the feedback array.
5. Parse the data i n the feedback array.
259
voi d glFeedbackBuffer(GLsi zei size, GLenum type, GLfl oat *buffer);
Establ i shes a buffer for the feedback data: buffer i s a poi nter to an array where the data i s stored. The
sizeargument i ndi cates the maxi mum number of val ues that can be stored i n the array. The type
argument descri bes the i nformati on fed back for each vertex i n the feedback array; i ts possi bl e val ues
and thei r meani ng are shown i n Table 12−1 . glFeedbackBuffer() must be cal l ed before feedback mode
i s entered. I n the tabl e, k i s 1 i n col or−i ndex mode and 4 i n RGBA mode.
Type Argument Coordinates Color Texture Total Values
GL_2D x, y − − 2
GL_3D x, y, z − − 3
GL_3D_COLOR x, y, z k − 3 + k
GL_3D_COLOR_TEXTURE x, y, z k 4 7 + k
GL_4D_COLOR_TEXTURE x, y, z, w k 4 8 + k
Table 12−1 Val ues for the Type Argument to gl FeedbackBuffer()
The Feedback Array
I n feedback mode, each pri mi ti ve that woul d be rasteri zed (or each cal l to glDrawPixels() or
glCopyPixels(), i f the raster posi ti on i s val i d) generates a bl ock of val ues that’s copi ed i nto the feedback
array. The number of val ues i s determi ned by the typeargument to glFeedbackBuffer(), as l i sted i n
Table 12−1 . Use the appropri ate val ue for the type of pri mi ti ves you’re drawi ng: GL_2D or GL_3D for
unl i t two− or three−di mensi onal pri mi ti ves, GL_3D_COLOR for l i t, three−di mensi onal pri mi ti ves, and
GL_3D_COLOR_TEXTURE or GL_4D_COLOR_TEXTURE for l i t, textured, three− or
four−di mensi onal pri mi ti ves.
Each bl ock of feedback val ues begi ns wi th a code i ndi cati ng the pri mi ti ve type, fol l owed by val ues that
descri be the pri mi ti ve’s verti ces and associ ated data. Entri es are al so wri tten for pi xel rectangl es. I n
addi ti on, pass−through markers that you’ve expl i ci tl y created can be returned i n the array; the next
secti on expl ai ns these markers i n more detai l . Table 12−2 shows the syntax for the feedback array;
remember that the data associ ated wi th each returned vertex i s as descri bed i n Table 12−1 . Note that
a pol ygon can have n verti ces returned. Al so, the x, y, z coordi nates returned by feedback are wi ndow
coordi nates; i f w i s returned, i t’s i n cl i p coordi nates. For bi tmaps and pi xel rectangl es, the coordi nates
returned are those of the current raster posi ti on. I n the tabl e, note that GL_LI NE_RESET_TOKEN i s
returned onl y when the l i ne sti ppl e i s reset for that l i ne segment.
Primitive Type Code Associated Data
Point GL_POINT_TOKEN vertex
Line GL_LINE_TOKEN or
GL_LINE_RESET_TOKEN
vertex vertex
Polygon GL_POLYGON_TOKEN n vertex vertex ... vertex
Bitmap GL_BITMAP_TOKEN vertex
Pixel Rectangle GL_DRAW_PIXEL_TOKEN or
GL_COPY_PIXEL_TOKEN
vertex
Pass−through GL_PASS_THROUGH_TOKE N a floating−point number
Table 12−2 Feedback Array Syntax
Using Markers in Feedback Mode
Feedback occurs after transformati ons, l i ghti ng, pol ygon cul l i ng, and i nterpretati on of pol ygons by
glPolygonMode(). I t mi ght al so occur after pol ygons wi th more than three edges are broken up i nto
tri angl es (i f your parti cul ar OpenGL i mpl ementati on renders pol ygons by performi ng thi s
decomposi ti on). Thus, i t mi ght be hard for you to recogni ze the pri mi ti ves you drew i n the feedback
data you recei ve. To hel p yoursel f parse the feedback data, cal l glPassThrough() as needed i n your
sequence of drawi ng commands to i nsert a marker. You mi ght use the markers to separate the
260
feedback val ues returned from di fferent pri mi ti ves, for exampl e. Thi s command causes
GL_PASS_THROUGH_TOKEN to be wri tten i nto the feedback array, fol l owed by the fl oati ng−poi nt
val ue you pass i n as an argument.
voi d glPassThrough(GLfl oat token);
I nserts a marker i nto the stream of val ues wri tten i nto the feedback array, i f cal l ed i n feedback mode.
The marker consi sts of the code GL_PASS_THROUGH_TOKEN fol l owed by a si ngl e fl oati ng−poi nt
val ue, token. Thi s command has no effect when cal l ed outsi de of feedback mode. Cal l i ng
glPassThrough() between glBegin() and glEnd() generates a GL_I NVALI D_OPERATI ON error.
A Feedback Example
Example 12−7 demonstrates the use of feedback mode. Thi s program draws a l i t, three−di mensi onal
scene i n normal renderi ng mode. Then, feedback mode i s entered, and the scene i s redrawn. Si nce the
program draws l i t, untextured, three−di mensi onal objects, the type of feedback data i s
GL_3D_COLOR. Si nce RGBA mode i s used, each uncl i pped vertex generates seven val ues for the
feedback buffer: x, y, z, r, g, b, and a.
I n feedback mode, the program draws two l i nes as part of a l i ne stri p and then i nserts a pass−through
marker. Next, a poi nt i s drawn at (−100.0, −100.0, −100.0), whi ch fal l s outsi de the orthographi c
vi ewi ng vol ume and thus doesn’t put any val ues i nto the feedback array. Fi nal l y, another pass−through
marker i s i nserted, and another poi nt i s drawn.
Example 12−7 Usi ng Feedback Mode: feedback.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
void myinit(void)
{
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
}
void drawGeometry (GLenum mode)
{
glBegin (GL_LINE_STRIP);
glNormal3f (0.0, 0.0, 1.0);
glVertex3f (30.0, 30.0, 0.0);
glVertex3f (50.0, 60.0, 0.0);
glVertex3f (70.0, 40.0, 0.0);
glEnd ();
if (mode == GL_FEEDBACK)
glPassThrough (1.0);
glBegin (GL_POINTS);
glVertex3f (−100.0, −100.0, −100.0);
glEnd ();
if (mode == GL_FEEDBACK)
glPassThrough (2.0);
glBegin (GL_POINTS);
glNormal3f (0.0, 0.0, 1.0);
glVertex3f (50.0, 50.0, 0.0);
261
glEnd ();
}
void print3DcolorVertex (GLint size, GLint *count,
GLfloat *buffer)
{
int i;
printf (" ");
for (i = 0; i < 7; i++) {
printf ("%4.2f ", buffer[size−(*count)]);
*count = *count − 1;
}
printf ("\n");
}
void printBuffer(GLint size, GLfloat *buffer)
{
GLint count;
GLfloat token;
count = size;
while (count) {
token = buffer[size−count]; count−−;
if (token == GL_PASS_THROUGH_TOKEN) {
printf ("GL_PASS_THROUGH_TOKEN\n");
printf (" %4.2f\n", buffer[size−count]);
count−−;
}
else if (token == GL_POINT_TOKEN) {
printf ("GL_POINT_TOKEN\n");
print3DcolorVertex (size, &count, buffer);
}
else if (token == GL_LINE_TOKEN) {
printf ("GL_LINE_TOKEN\n");
print3DcolorVertex (size, &count, buffer);
print3DcolorVertex (size, &count, buffer);
}
else if (token == GL_LINE_RESET_TOKEN) {
printf ("GL_LINE_RESET_TOKEN\n");
print3DcolorVertex (size, &count, buffer);
print3DcolorVertex (size, &count, buffer);
}
}
}
void display(void)
{
GLfloat feedBuffer[1024];
GLint size;
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glOrtho (0.0, 100.0, 0.0, 100.0, 0.0, 1.0);
262
glClearColor (0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
drawGeometry (GL_RENDER);
glFeedbackBuffer (1024, GL_3D_COLOR, feedBuffer);
(void) glRenderMode (GL_FEEDBACK);
drawGeometry (GL_FEEDBACK);
size = glRenderMode (GL_RENDER);
printBuffer (size, feedBuffer);
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
auxInitPosition (0, 0, 100, 100);
auxInitWindow (argv[0]);
myinit ();
auxMainLoop(display);
}
Runni ng thi s program generates the fol l owi ng output:
GL_LINE_RESET_TOKEN
30.00 30.00 0.00 0.84 0.84 0.84 1.00
50.00 60.00 0.00 0.84 0.84 0.84 1.00
GL_LINE_TOKEN
50.00 60.00 0.00 0.84 0.84 0.84 1.00
70.00 40.00 0.00 0.84 0.84 0.84 1.00
GL_PASS_THROUGH_TOKEN
1.00
GL_PASS_THROUGH_TOKEN
2.00
GL_POINT_TOKEN
50.00 50.00 0.00 0.84 0.84 0.84 1.00
Thus, the l i ne stri p drawn wi th these commands resul ts i n two pri mi ti ves:
glBegin(GL_LINE_STRIP);
glNormal3f (0.0, 0.0, 1.0);
glVertex3f (30.0, 30.0, 0.0);
glVertex3f (50.0, 60.0, 0.0);
glVertex3f (70.0, 40.0, 0.0);
glEnd();
The fi rst pri mi ti ve begi ns wi th GL_LI NE_RESET_TOKEN, whi ch i ndi cates that the pri mi ti ve i s a l i ne
segment and that the l i ne sti ppl e i s reset. The second pri mi ti ve begi ns wi th GL_LI NE_TOKEN, so i t’s
al so a l i ne segment, but the l i ne sti ppl e i sn’t reset and hence conti nues from where the previ ous l i ne
segment l eft off. Each of the two verti ces for these l i nes generates seven val ues for the feedback array.
Note that the RGBA val ues for al l four verti ces i n these two l i nes are (0.84, 0.84, 0.84, 1.0), whi ch i s a
very l i ght gray col or wi th the maxi mum al pha val ue. These col or val ues are a resul t of the i nteracti on
of the surface normal and l i ghti ng parameters.
Si nce no feedback data i s generated between the fi rst and second pass−through markers, you can
263
deduce that any pri mi ti ves drawn between the fi rst two cal l s to glPassThrough() were cl i pped out of the
vi ewi ng vol ume. Fi nal l y, the poi nt at (50.0, 50.0, 0.0) i s drawn, and i ts associ ated data i s copi ed i nto the
feedback array.
Try This
Try This
Make changes to Example 12−7 and see how they affect the feedback val ues that are returned. For
exampl e, change the coordi nate val ues of glOrtho(). Change the l i ghti ng vari abl es, or el i mi nate l i ghti ng
al together and change the feedback type to GL_3D. Or add more pri mi ti ves to see what other geometry
(such as fi l l ed pol ygons) contri butes to the feedback array.
Chapter 13
Now That You Know
Chapter Objectives
Thi s chapter doesn’t have objecti ves i n the same way that previ ous chapters do. I t’s si mpl y a col l ecti on
of topi cs that descri be i deas you mi ght fi nd useful for your appl i cati on.
OpenGL i s ki nd of a bag of l ow−l evel tool s; now that you know about those tool s, you can use them to
i mpl ement hi gher−l evel functi ons. Thi s chapter presents several exampl es of such hi gher−l evel
capabi l i ti es.
Thi s chapter di scusses a vari ety of techni ques based on OpenGL commands that i l l ustrate some of the
not−so−obvi ous uses to whi ch you can put these commands. The exampl es are i n no parti cul ar order
and aren’t rel ated to each other. The i dea i s to read the secti on headi ngs and ski p to the exampl es that
you fi nd i nteresti ng. For your conveni ence, the headi ngs are l i sted and expl ai ned bri efl y here.
Note: Most of the exampl es i n the rest of thi s gui de are compl ete and can be compi l ed and run as i s.
I n thi s chapter, however, there are no compl ete programs, and you have to do a bi t of work on
your own to make them run.
• "Cheesy Translucency"expl ai ns how to use pol ygon sti ppl i ng to achi eve transl ucency; thi s i s
parti cul arl y useful when you don’t have bl endi ng hardware avai l abl e.
• "An Easy Fade Effect"shows how to use pol ygon sti ppl i ng to create the effect of a fade i nto the
background.
• "Object Selection Using the Back Buffer"descri bes how to use the back buffer i n a
doubl e−buffered system to handl e si mpl e object pi cki ng.
• "Cheap Image Transformation"di scusses how to draw a di storted versi on of a bi tmapped i mage
by drawi ng each pi xel as a quadri l ateral .
• "Displaying Layers"expl ai ns how to di spl ay mul ti pl e di fferent l ayers of materi al s and i ndi cate
where the materi al s overl ap.
• "Antialiased Characters"descri bes how to draw smoother fonts.
• "Drawing Round Points"descri bes how to draw near−round poi nts.
• "Interpolating Images"shows how to smoothl y bl end from one i mage to the another.
• "Making Decals"expl ai ns how to draw two i mages, where one i s a sort of decal that shoul d al ways
appear on top of the other.
• "Drawing Filled, Concave Polygons Using the Stencil Buffer"tel l s you how to draw concave
pol ygons, nonsi mpl e pol ygons, and pol ygons wi th hol es by usi ng the stenci l buffer.
• "Finding Interference Regions"descri bes how to determi ne where three−di mensi onal pi eces
overl ap.
• "Shadows"descri bes how to draw shadows of l i t objects.
• "Hidden−Line Removal"di scusses how to draw a wi reframe object wi th hi dden l i nes removed by
usi ng the stenci l buffer.
264
• "Texture−Mapping Applications"descri bes several cl ever uses for texture mappi ng, such as
rotati ng and warpi ng i mages.
• "Drawing Depth−Buffered Images"tel l s you how to combi ne i mages i n a depth−buffered
envi ronment.
• "Dirichlet Domains"expl ai ns how to fi nd the Di ri chl et domai n of a set of poi nts usi ng the depth
buffer.
• "Life in the Stencil Buffer"expl ai ns how to i mpl ement the Game of Li fe usi ng the stenci l buffer.
• "Alternative Uses for glDrawPixels() and glCopyPixels()"descri bes how to use these two
commands for such effects as fake vi deo, ai rbrushi ng, and transposed i mages.
Cheesy Translucency
You can use pol ygon sti ppl i ng to si mul ate a transl ucent materi al . Thi s i s an especi al l y good sol uti on for
systems that don’t have bl endi ng hardware. Si nce pol ygon sti ppl e patterns are 32x32 bi ts, or 1024 bi ts,
you can go from opaque to transparent i n 1023 steps. For exampl e, i f you want a surface that l ets
through 29 percent of the l i ght, si mpl y make up a sti ppl e pattern where 29 percent (roughl y 297) of the
pi xel s i n the mask are 0 and the rest are 1. Even i f your surfaces have the same transl ucency, don’t use
the same sti ppl e pattern for each one, as they cover exactl y the same bi ts on the screen. Make up a
di fferent pattern for each by randoml y sel ecti ng the appropri ate number of pi xel s to be 0. See
"Displaying Points, Lines, and Polygons" for more i nformati on about pol ygon sti ppl i ng.
I f you don’t l i ke the effect wi th random pi xel s turned on, you can use regul ar patterns, but they don’t
work as wel l when transparent surfaces are stacked. Thi s i s often not a probl em because most scenes
have rel ati vel y few transl ucent regi ons that overl ap. I n a pi cture of an automobi l e wi th transl ucent
wi ndows, your l i ne of si ght can go through at most two wi ndows, and usual l y i t’s onl y one.
An Easy Fade Effect
Suppose you have an i mage that you want to fade gradual l y to some background col or. Defi ne a seri es
of pol ygon sti ppl e patterns, each of whi ch has more bi ts turned on so that they represent denser and
denser patterns. Then use these patterns repeatedl y wi th a pol ygon l arge enough to cover the regi on
over whi ch you want to fade. For exampl e, suppose you want to fade to bl ack i n si xteen steps. Fi rst
defi ne si xteen di fferent pattern arrays:
GLubyte stips[16][4*32];
Then l oad them i n such a way that each has one−si xteenth of the pi xel s i n a 32x32 sti ppl e pattern
turned on. After that, the fol l owi ng code does the tri ck:
draw_the_picture();
glColor3f(0.0, 0.0, 0.0); /* set color to black */
for (i = 0; i < 16; i++) {
glPolygonStipple(&stips[i][0]);
draw_a_polygon_large_enough_to_cover_the_whole_region();
}
I n some OpenGL i mpl ementati ons, you mi ght get better performance by fi rst compi l i ng the sti ppl e
patterns i nto di spl ay l i sts. Duri ng your i ni ti al i zati on, do somethi ng l i ke thi s:
#define STIP_OFFSET 100
for (i = 0; i < 16; i++) {
glNewList(i+STIP_OFFSET, GL_COMPILE);
glPolygonStipple(&stips[i][0]);
glEndList();
}
265
Then, repl ace thi s l i ne i n the fi rst code fragment
glPolygonStipple(&stips[i][0]);
wi th
glCallList(i);
By compi l i ng the command to set the sti ppl e i nto a di spl ay l i st, OpenGL mi ght be abl e to rearrange the
data i n the sti ps[ ][ ] array i nto the hardware−speci fi c form requi red for maxi mum sti ppl e−setti ng
speed.
Another appl i cati on for thi s techni que i s i f you’re drawi ng a changi ng pi cture, and you want to l eave
some bl ur behi nd that gradual l y fades out to gi ve some i ndi cati on of past moti on. For exampl e, suppose
you’re si mul ati ng a pl anetary system, and you want to l eave trai l s on the pl anets to show a recent
porti on of thei r path. Agai n, assumi ng you want to fade i n si xteen steps, set up the sti ppl e patterns as
before (usi ng the di spl ay−l i st versi on, say), and have the mai n si mul ati on l oop l ook somethi ng l i ke thi s:
current_stipple = 0;
while (1) { /* loop forever */
draw_the_next_frame();
glCallList(current_stipple++);
if (current_stipple == 16) current_stipple = 0;
glColor3f(0.0, 0.0, 0.0); /* set color to black */
draw_a_polygon_large_enough_to_cover_the_whole_region();
}
Each ti me through the l oop, you cl ear one−si xteenth of the pi xel s. Any pi xel that hasn’t had a pl anet on
i t for si xteen frames i s certai n to be cl eared to bl ack. Of course, i f your system supports bl endi ng i n
hardware, i t’s easi er to bl end i n a certai n amount of background col or wi th each frame.
See "Displaying Points, Lines, and Polygons" for pol ygon sti ppl i ng detai l s, Chapter 4, "Display
Lists," for more i nformati on about di spl ay l i sts, and "Blending" for i nformati on about bl endi ng.
Object Selection Using the Back Buffer
Al though OpenGL’s sel ecti on mechani sm (see "Selection") i s powerful and fl exi bl e, i t can be
cumbersome to use. Often, the si tuati on i s si mpl e: Your appl i cati on draws a scene composed of a
substanti al number of objects; the user poi nts to an object wi th the mouse, and the appl i cati on needs to
fi nd the i tem under the ti p of the cursor.
One way to do thi s requi res your appl i cati on to be runni ng i n doubl e−buffer mode. When the user pi cks
an object, the appl i cati on redraws the enti re scene i n the back buffer, but i nstead of usi ng the normal
col ors for objects, i t encodes some ki nd of object i denti fi er for each object’s col or. The appl i cati on then
si mpl y reads back the pi xel under the cursor, and the val ue of that pi xel encodes the number of the
pi cked object.
Note that thi s scheme has an advantage over standard sel ecti on i n that i t pi cks the object that’s i n
front, i f mul ti pl e objects appear at the same pi xel , one behi nd the other. Si nce the i mage wi th fal se
col ors i s drawn i n the back buffer, the user never sees i t; you can redraw the back buffer (or copy i t from
the front buffer) before swappi ng the buffers. I n col or−i ndex mode, the encodi ng i s si mpl esend the
object i denti fi er as the i ndex. I n RGBA mode, encode the bi ts of the i denti fi er i nto the R, G, and B
components.
Be aware that you can run out of i denti fi ers i f there are too many objects i n the scene. For exampl e,
suppose you’re runni ng i n col or−i ndex mode on a system that has 4−bi t buffers for col or−i ndex
i nformati on (si xteen possi bl e di fferent i ndi ces) i n each of the col or buffers, but the scene has thousands
of pi ckabl e i tems. To address thi s i ssue, the pi cki ng can be done i n a few passes. For defi ni teness,
266
assume there are fewer than 4096 i tems, so al l the object i denti fi ers can be encoded i n 12 bi ts. I n the
fi rst pass, draw the scene usi ng i ndi ces composed of the 4 hi gh−order bi ts, then use the second and
thi rd passes to draw the mi ddl e 4 bi ts and the 4 l ow−order bi ts. After each pass, read the pi xel under
the cursor, extract the bi ts, and pack them together at the end to get the object i denti fi er.
Wi th thi s method, the pi cki ng takes three ti mes as l ong, but that’s often acceptabl e. Note that after you
have the hi gh−order 4 bi ts, you el i mi nate fi fteen of the si xteen possi bl e objects, so you real l y onl y need
to draw one−si xteenth of them for the second pass. Si mi l arl y, after the second pass, 255 of the 256
possi bl e i tems have been el i mi nated. The fi rst pass thus takes about as l ong as drawi ng a si ngl e frame
does, but the second and thi rd passes can be up to 16 and 256 ti mes as fast.
I f you’re tryi ng to wri te portabl e code that works on di fferent systems, break up your object i denti fi ers
i nto chunks that fi t on the l owest common denomi nator of those systems. Al so, keep i n mi nd that your
system mi ght perform automati c di theri ng i n RGB mode. I f thi s i s the case, turn off di theri ng.
Cheap Image Transformation
Suppose you want to draw a di storted versi on of a bi tmapped i mage (perhaps si mpl y stretched or
rotated, or perhaps drasti cal l y modi fi ed by some mathemati cal functi on). I n many cases, you can
achi eve good resul ts by drawi ng the i mage of each pi xel as a quadri l ateral . Al though thi s scheme
doesn’t produce i mages as ni ce as those you woul d get by appl yi ng a sophi sti cated fi l teri ng al gori thm
(and i t mi ght not be suffi ci ent for sophi sti cated users), i t’s a l ot qui cker.
To make the probl em more concrete, assume that the ori gi nal i mage i s m pi xel s by n pi xel s, wi th
coordi nates chosen from [0, m−1] × [0, n−1]. Let the di storti on functi ons be x(m,n) and y(m,n). For
exampl e, i f the di storti on i s si mpl y a zoomi ng by a factor of 3.2, then x(m,n) = 3.2*m and y(m,n) = 3.2*n.
The fol l owi ng code draws the di storted i mage:
glShadeModel(GL_FLAT);
glScale(3.2, 3.2, 1.0);
for (j=0; j < n; j++) {
glBegin(GL_QUAD_STRIP);
for (i=0; i <= m; i++) {
glVertex2i(i,j);
glVertex2i(i, j+1);
set_color(i,j);
}
glEnd();
}
Thi s code draws each transformed pi xel i n a sol i d col or equal to that pi xel ’s col or and scal es the i mage
si ze by 3.2. The routi ne set_color() stands for whatever the appropri ate OpenGL command i s to set the
col or of the i mage pi xel .
The fol l owi ng i s a sl i ghtl y more compl ex versi on that di storts the i mage usi ng the functi ons x(i,j) and y(
i,j):
glShadeModel(GL_FLAT);
for (j=0; j < n; j++) {
glBegin(GL_QUAD_STRIP);
for (i=0; i <= m; i++) {
glVertex2i(x(i,j), y(i,j));
glVertex2i(x(i,j+1), y(i,j+1));
set_color(i,j);
}
glEnd();
}
267
An even better di storted i mage can be drawn wi th the fol l owi ng code:
glShadeModel(GL_SMOOTH);
for (j=0; j < (n−1); j++) {
glBegin(GL_QUAD_STRIP);
for (i=0; i < m; i++) {
set_color(i,j);
glVertex2i(x(i,j), y(i,j));
set_color(i,j+1);
glVertex2i(x(i,j+1), y(i,j+1));
}
glEnd();
}
Thi s code smoothl y i nterpol ates col or across each quadri l ateral . Note that thi s versi on produces one
fewer quadri l ateral i n each di mensi on than do the fl at−shaded versi ons because the col or i mage i s bei ng
used to speci fy col ors at the quadri l ateral verti ces. I n addi ti on, you can anti al i as the pol ygons wi th the
appropri ate bl endi ng functi on (GL_SRC_ALPHA, GL_ONE) to get an even ni cer i mage.
Displaying Layers
I n some appl i cati ons such as semi conductor l ayout programs, you want to di spl ay mul ti pl e di fferent
l ayers of materi al s and i ndi cate where the materi al s overl ap each other.
As a si mpl e exampl e, suppose you have three di fferent substances that can be l ayered. At any poi nt,
ei ght possi bl e combi nati ons of l ayers can occur, as shown i n Table 13−1 .
Layer 1 Layer 2 Layer 3 Color
0 absent absent absent black
1 present absent absent red
2 absent present absent green
3 present present absent blue
4 absent absent present pink
5 present absent present yellow
6 absent present present white
7 present present present gray
Table 13−1 Ei ght Combi nati ons of Layers
You want your program to di spl ay ei ght di fferent col ors, dependi ng on the l ayers present. One
arbi trary possi bi l i ty i s shown i n the l ast col umn of the tabl e. To use thi s method, use col or−i ndex mode
and l oad your col or map so that entry 0 i s bl ack, entry 1 i s red, entry 2 i s green, and so on. Note that i f
the numbers from 0 through 7 are wri tten i n bi nary, the 4 bi t i s turned on whenever l ayer 3 appears,
the 2 bi t whenever l ayer 2 appears, and the 1 bi t whenever l ayer 1 appears.
To cl ear the wi ndow, set the wri temask to 7 (al l three l ayers) and set the cl eari ng col or to 0. To draw
your i mage, set the col or to 7, and then when you want to draw somethi ng i n l ayer n, set the wri temask
to n. I n other types of appl i cati ons, i t mi ght be necessary to sel ecti vel y erase i n a l ayer, i n whi ch case
you woul d use the same wri temasks as above, but set the col or to 0 i nstead of 7.
See "Masking Buffers" for more i nformati on about wri temasks.
Antialiased Characters
Usi ng the standard techni que for drawi ng characters wi th glBitmap(), drawi ng each pi xel of a
268
character i s an al l −or−nothi ng affai rthe pi xel i s ei ther turned on or not. I f you’re drawi ng bl ack
characters on a whi te background, for exampl e, the resul ti ng pi xel s are ei ther bl ack or whi te, never a
shade of gray. Much smoother, hi gher−qual i ty i mages can be achi eved i f i ntermedi ate col ors are used
when renderi ng characters (grays, i n thi s exampl e).
Assumi ng that you’re drawi ng bl ack characters on a whi te background, i magi ne a hi ghl y magni fi ed
pi cture of the pi xel s on the screen, wi th a hi gh−resol uti on character outl i ne superi mposed on i t, as
shown i n the l eft si de of Figure 13−1.
Figure 13−1 Anti al i ased Characters
Noti ce that some of the pi xel s are compl etel y encl osed by the character’s outl i ne and shoul d be pai nted
bl ack; some pi xel s are compl etel y outsi de the outl i ne and shoul d be pai nted whi te; but many pi xel s
shoul d i deal l y be pai nted some shade of gray, where the darkness of the gray corresponds to the
amount of bl ack i n the pi xel . I f thi s techni que i s used, the resul ti ng i mage on the screen l ooks better.
I f speed and memory usage are of no concern, each character can be drawn as a smal l i mage i nstead of
as a bi tmap. I f you’re usi ng RGBA mode, however, thi s method mi ght requi re up to 32 bi ts per pi xel of
the character to be stored and drawn, i nstead of the one bi t per pi xel i n a standard character.
Al ternati vel y, you coul d use one 8−bi t i ndex per pi xel and convert these i ndi ces to RGBA by tabl e
l ookup duri ng transfer. I n many cases, a compromi se i s possi bl e that al l ows you to draw the character
wi th a few gray l evel s between bl ack and whi te (say, two or three), and the resul ti ng font descri pti on
requi res onl y 2 or 3 bi ts per pi xel of storage.
The numbers i n the ri ght si de of Figure 13−1 i ndi cate the approxi mate percentage coverage of each
pi xel : 0 means approxi matel y empty, 1 means approxi matel y one−thi rd coverage, 2 means two−thi rds,
and 3 means compl etel y covered. I f pi xel s l abel ed 0 are pai nted whi te, pi xel s l abel ed 3 are pai nted
bl ack, and pi xel s l abel ed 1 and 2 are pai nted one−thi rd and two−thi rds bl ack, respecti vel y, the
resul ti ng character l ooks qui te good. Onl y 2 bi ts are requi red to store the numbers 0, 1, 2, and 3, so for
2 bi ts per pi xel , four l evel s of gray can be saved.
There are basi cal l y two methods to i mpl ement anti al i ased characters, dependi ng on whether you’re i n
RGBA mode.
269
I n RGBA mode, defi ne three di fferent character bi tmaps, correspondi ng to where 1, 2, and 3 appear i n
Figure 13−1. Set the col or to whi te and cl ear for the background. Set the col or to one−thi rd gray (RGB
= (0.666, 0.666, 0.666)) and draw al l the pi xel s wi th a 1 i n them. Then set RGB = (0.333, 0.333, 0.333),
draw wi th the 2 bi tmap, and use RGB = (0.0, 0.0, 0.0) for the 3 bi tmap. What you’re doi ng i s defi ni ng
three di fferent fonts, and redrawi ng the stri ng three ti mes, where each pass fi l l s i n the bi ts of the
appropri ate col or densi ti es.
I n col or−i ndex mode, you can do exactl y the same thi ng, but i f you’re wi l l i ng to set up the col or map
correctl y and use wri temasks, you can get away wi th onl y two bi tmaps per character and two passes
per stri ng. I n the precedi ng exampl e, set up one bi tmap that has a 1 wherever 1 or 3 appears i n the
character. Set up a second bi tmap that has a 1 wherever a 2 or a 3 appears. Load the col or map so that
0 gi ves whi te, 1 gi ves l i ght gray, 2 gi ves dark gray, and 3 gi ves bl ack. Set the col or to 3 (11 i n bi nary)
and the wri temask to 1, and draw the fi rst bi tmap. Then change the wri temask to 2, and draw the
second. Where 0 appears i n Figure 13−1, nothi ng i s drawn i n the framebuffer. Where 1, 2, and 3
appear, 1, 2, and 3 appear i n the framebuffer.
For thi s exampl e wi th onl y four gray l evel s, the savi ngs i s smal ltwo passes i nstead of three. I f ei ght
gray l evel s were used i nstead, the RGBA method woul d requi re seven passes, and the col or−map
maski ng techni que woul d requi re onl y three. Wi th si xteen gray l evel s, the compari son i s fi fteen passes
to four passes.
See "Masking Buffers" for more i nformati on about wri temasks and "Bitmaps and Fonts" for more
i nformati on about drawi ng bi tmaps.
Try This
Try This
• Can you see how to do RGBA renderi ng usi ng no more i mages than the opti mi zed col or−i ndex case?
Hi nt: How are RGB fragments normal l y merged i nto the col or buffer when anti al i asi ng i s desi red?
Drawing Round Points
Draw near−round, al i ased poi nts by enabl i ng poi nt anti al i asi ng, turni ng bl endi ng off, and usi ng an
al pha functi on that passes onl y fragments wi th al pha greater than 0.5.
See "Antialiasing" and "Blending" for more i nformati on about these topi cs.
Interpolating Images
Suppose you have a pai r of i mages (where imagecan mean a bi tmap i mage, or a pi cture generated
usi ng geometry i n the usual way), and you want to smoothl y bl end from one to the other. Thi s can be
done easi l y usi ng the al pha component and appropri ate bl endi ng operati ons. Let’s say you want to
accompl i sh the bl endi ng i n ten steps, where i mage A i s shown i n frame 0 and i mage B i s shown i n
frame 9. The obvi ous approach i s to draw i mage A wi th al pha equal to (9−i)/9 and i mage B wi th an
al pha of i/9 i n frame i.
The probl em wi th thi s method i s that both i mages must be drawn i n each frame. A faster approach i s to
draw i mage A i n frame 0. To get frame 1, bl end i n 1/9 of i mage B and 8/9 of what’s there. For frame 2,
bl end i n 1/8 of i mage B wi th 7/8 of what’s there. For frame 3, bl end i n 1/7 of i mage B wi th 6/7 of what’s
there, and so on. For the l ast step, you’re just drawi ng 1/1 of i mage B bl ended wi th 0/1 of what’s l eft,
yi el di ng i mage B exactl y.
To see that thi s works, i f for frame i you have
and you bl end i n B/(9−i) wi th (8−i)/(9−i) of what’s there, you get
270
See "Blending."
Making Decals
Suppose you’re drawi ng a compl ex three−di mensi onal pi cture usi ng depth−bufferi ng to el i mi nate the
hi dden surfaces. Suppose further that one part of your pi cture i s composed of copl anar fi gures A and B,
where B i s a sort of decal that shoul d al ways appear on top of fi gure A.
Your fi rst approach mi ght be to draw B after you’ve drawn A, setti ng the depth−bufferi ng functi on to
repl ace on greater or equal . Due to the fi ni te preci si on of the fl oati ng−poi nt representati ons of the
verti ces, however, round−off error can cause pol ygon B to be someti mes a bi t i n front and someti mes a
bi t behi nd fi gure A. Here’s one sol uti on to thi s probl em:
1. Di sabl e the depth buffer for wri ti ng, and render A.
2. Enabl e the depth buffer for wri ti ng, and render B.
3. Di sabl e the col or buffer for wri ti ng, and render A agai n.
4. Enabl e the col or buffer for wri ti ng.
Note that duri ng the enti re process, the depth−buffer test i s enabl ed. I n step 1, A i s rendered wherever
i t shoul d be, but none of the depth−buffer val ues are changed, so i n step 2, wherever B appears over A,
B i s guaranteed to be drawn. Step 3 si mpl y makes sure that al l of the depth val ues under A are
updated correctl y, but si nce RGBA wri tes are di sabl ed, the col or pi xel s are unaffected. Fi nal l y, step 4
returns the system to the defaul t state (wri ti ng i s enabl ed both i n the depth buffer and i n the col or
buffer).
I f a stenci l buffer i s avai l abl e, the fol l owi ng si mpl er techni que works:
1. Confi gure the stenci l buffer to wri te 1 i f the depth test passes, and 0 otherwi se. Render A.
2. Confi gure the stenci l buffer to make no stenci l val ue change, but to render onl y where stenci l
val ues are 1. Di sabl e the depth−buffer test and i ts update. Render B.
Wi th thi s method, i t’s not necessary to i ni ti al i ze the contents of the stenci l buffer at any ti me, because
the stenci l val ue of al l pi xel s of i nterest (that i s, those rendered by A) are set when A i s rendered. Be
sure to reenabl e the depth test and di sabl e the stenci l test before addi ti onal pol ygons are drawn.
See "Selecting Color Buffers for Writing,""Depth Test," and "Stencil Test."
Drawing Filled, Concave Polygons Using the Stencil Buffer
Consi der the concave pol ygon 1234567 shown i n Figure 13−2. I magi ne that i t’s drawn as a seri es of
tri angl es: 123, 134, 145, 156, 167, al l of whi ch are shown i n the fi gure. The heavi er l i ne represents the
ori gi nal pol ygon boundary. Drawi ng al l these tri angl es di vi des the buffer i nto ni ne regi ons A, B, C, ..., I ,
where regi on I i s outsi de al l the tri angl es.
271
Figure 13−2 A Concave Pol ygon
I n the text of the fi gure, each of the regi on names i s fol l owed by a l i st of the tri angl es that cover i t.
Regi ons A, D, and F make up the ori gi nal pol ygon; note that these three regi ons are covered by an odd
number of tri angl es. Every other regi on i s covered by an even number of tri angl es (possi bl y zero).
Thus, to render the i nsi de of the concave pol ygon, you just need to render regi ons that are encl osed by
an odd number of tri angl es. Thi s can be done usi ng the stenci l buffer, wi th a two−pass al gori thm.
Fi rst, cl ear the stenci l buffer and di sabl e wri ti ng i nto the col or buffer. Next, draw each of the tri angl es
i n turn, usi ng the GL_I NVERT functi on i n the stenci l buffer. Thi s fl i ps the val ue between zero and a
nonzero val ue every ti me a tri angl e i s drawn that covers a pi xel . After al l the tri angl es are drawn, i f a
pi xel i s covered an even number of ti mes, the val ue i n the stenci l buffers i s zero; otherwi se, i t’s nonzero.
Fi nal l y, draw a l arge pol ygon over the whol e regi on (or redraw the tri angl es), but al l ow drawi ng onl y
where the stenci l buffer i s nonzero.
Note: There’s a sl i ght general i zati on of the precedi ng techni que, where you don’t need to start wi th a
pol ygon vertex. I n the 1234567 exampl e, l et P be any poi nt on or off the pol ygon. Draw the
tri angl es: P12, P23, P34, P45, P56, P67, and P71. Regi ons covered by an odd number of
tri angl es are i nsi de; other regi ons are outsi de. Thi s i s a general i zati on i n that i f P happens to
be one of the pol ygon’s edges, one of the tri angl es i s empty.
Thi s techni que can be used to fi l l both nonsi mpl e pol ygons (pol ygons whose edges cross each other) and
pol ygons wi th hol es. The fol l owi ng exampl e i l l ustrates how to handl e a compl i cated pol ygon wi th two
regi ons, one four−si ded and one fi ve−si ded. Assume further that there’s a tri angul ar and a four−si ded
hol e (i t doesn’t matter i n whi ch regi ons the hol es l i e). Let the two regi ons be abcd and efghi , and the
272
hol es jkl and mnop. Let z be any poi nt on the pl ane. Draw the fol l owi ng tri angl es:
zab zbc zcd zda zef zfg zgh zhi zi e zjk zkl zl j zmn zno zop zpm
Mark regi ons covered by an odd number of tri angl es as in, and those covered by an even number as out.
See "Stencil Test" for more i nformati on about the stenci l buffer.
Finding Interference Regions
I f you’re desi gni ng a mechani cal part made from smal l er three−di mensi onal pi eces, you often want to
di spl ay regi ons where the pi eces overl ap. I n many cases, such regi ons i ndi cate desi gn errors where
parts of a machi ne i nterfere wi th each other. I n the case of movi ng parts, i t can be even more val uabl e,
si nce a search for i nterferi ng regi ons can be done through a compl ete mechani cal cycl e of the desi gn.
The method for doi ng thi s i s compl i cated, and the descri pti on here mi ght be too bri ef. Compl ete detai l s
can be found i n the paper I nteractiveI nspection of Solids: Cross−sections and I nterferences, by Jarek
Rossi gnac, Abe Megahed, and Bengt−Ol af Schnei der (SI GGRAPH 1992 Proceedi ngs).
The method i s rel ated to the cappi ng al gori thm descri bed i n "Stencil Test." The i dea i s to pass an
arbi trary cl i ppi ng pl ane through the objects that you want to test for i nterference, and then determi ne
when a porti on of the cl i ppi ng pl ane i s i nsi de more than one object at a ti me. For a stati c i mage, the
cl i ppi ng pl ane can be moved manual l y to hi ghl i ght i nterferi ng regi ons; for a dynami c i mage, i t mi ght be
easi er to use a gri d of cl i ppi ng pl anes to search for al l possi bl e i nterferences.
Draw each of the objects you want to check and cl i p them agai nst the cl i ppi ng pl ane. Note whi ch pi xel s
are i nsi de the object at that cl i ppi ng pl ane usi ng an odd−even count i n the stenci l buffer, as expl ai ned
i n the precedi ng secti on. (For properl y formed objects, a poi nt i s i nsi de the object i f a ray drawn from
that poi nt to the eye i ntersects an odd number of surfaces of the object.) To fi nd i nterferences, you need
to fi nd pi xel s i n the framebuffer where the cl i ppi ng pl ane i s i n the i nteri or of two or more regi ons at
once; i n other words, i n the i ntersecti on of the i nteri ors of any pai r of objects.
I f mul ti pl e objects need to be tested for mutual i ntersecti on, store one bi t every ti me some i ntersecti on
appears, and another bi t wherever the cl i ppi ng buffer i s i nsi de any of the objects (the uni on of the
objects’ i nteri ors). For each new object, determi ne i ts i nteri or, fi nd the i ntersecti on of that wi th the
uni on of the i nteri ors of the objects so far tested, and keep track of the i ntersecti on poi nts. Then add the
i nteri or poi nts of the new object to the uni on of the other objects’ i nteri ors.
You can perform the operati ons descri bed i n the precedi ng paragraph by usi ng di fferent bi ts i n the
stenci l buffer together wi th vari ous maski ng operati ons. Three bi ts of stenci l buffer are requi red per
pi xelone for the toggl i ng to determi ne the i nteri or of each object, one for the uni on of al l i nteri ors
di scovered so far, and one for the regi ons where i nterference has occurred so far. For concreteness,
assume the 1 bi t of the stenci l buffer i s for toggl i ng i nteri or/exteri or, the 2 bi t i s the runni ng uni on, and
the 4 bi t i s for i nterferences so far. For each object that you’re goi ng to render, cl ear the 1 bi t (usi ng a
stenci l mask of 1 and cl eari ng to 0), then toggl e the 1 bi t by keepi ng the stenci l mask as 1 and usi ng the
GL_I NVERT stenci l operati on.
You can fi nd i ntersecti ons and uni ons of the bi ts i n the stenci l buffers usi ng the stenci l i ng operati ons.
For exampl e, to make bi ts i n buffer 2 be the uni on of the bi ts i n buffers 1 and 2, mask the stenci l to
those two bi ts, and draw somethi ng over the enti re object wi th the stenci l functi on set to pass i f
anythi ng nonzero occurs. Thi s happens i f the bi ts i n buffer 1, buffer 2, or both are turned on. I f the
compari son succeeds, wri te a 1 i n buffer 2. Al so, make sure that drawi ng i n the col or buffer i s di sabl ed.
An i ntersecti on cal cul ati on i s si mi l arset the functi on to pass onl y i f the val ue i n the two buffers i s
equal to 3 (bi ts turned on i n both buffers 1 and 2). Wri te the resul t i nto the correct buffer.
See "Additional Clipping Planes" and "Stencil Test."
Shadows
273
Every possi bl e projecti on of three−di mensi onal space to three−di mensi onal space can be achi eved wi th
a sui tabl e 4 x 4 i nverti bl e matri x and homogeneous coordi nates. I f the matri x i sn’t i nverti bl e but has
rank 3, i t projects three−di mensi onal space onto a two−di mensi onal pl ane. Every such possi bl e
projecti on can be achi eved wi th a sui tabl e rank−3 4 × 4 matri x. To fi nd the shadow of an arbi trary
object on an arbi trary pl ane from an arbi trary l i ght source (possi bl y at i nfi ni ty), you need to fi nd a
matri x representi ng that projecti on, mul ti pl y i t on the matri x stack, and draw the object i n the shadow
col or. Keep i n mi nd that you need to project onto each pl ane that you’re cal l i ng the "ground."
As a si mpl e i l l ustrati on, assume the l i ght i s at the ori gi n, and the equati on of the ground pl ane i s ax+by
+c+d=0. Gi ven a vertex S=(sx,sy,sz,1), the l i ne from the l i ght through S i ncl udes al l poi nts αS, where α
i s an arbi trary real number. The poi nt where thi s l i ne i ntersects the pl ane occurs when
α(a*sz+b*sy+c*sz) + d = 0,
so
α = −d/(a*sx+b*sy+c*sz).
Pl uggi ng thi s back i nto the l i ne, we get:
−d(sx,sy,sz)/ (a*sx+b*sy+c*sz)
for the poi nt of i ntersecti on.
The matri x that maps S to thi s poi nt for every S i s
Thi s matri x can be used i f you fi rst transl ate the worl d so that the l i ght i s at the ori gi n.
I f the l i ght i s from an i nfi ni te source, al l you have i s a poi nt S and a di recti on D = (dx,dy,dz). Poi nts
al ong the l i ne are gi ven by
S + αD
Proceedi ng as before, the i ntersecti on of thi s l i ne wi th the pl ane i s gi ven by
a(sx+αdx)+b(sy+αdy)+c(sz+αdz)+d = 0
Sol vi ng for α, pl uggi ng that back i nto the equati on for a l i ne, and then determi ni ng a projecti on matri x
gi ves
274
Thi s matri x works gi ven the pl ane and an arbi trary di recti on vector. There’s no need to transl ate
anythi ng fi rst.
See Chapter 3, "Viewing," and Appendix G .
Hidden−Line Removal
I f you want to draw a wi reframe object wi th hi dden l i nes removed, one approach i s to draw the outl i nes
usi ng l i nes, and then fi l l the i nteri ors of the pol ygons maki ng up the surface wi th pol ygons havi ng the
background col or. Wi th depth−bufferi ng enabl ed, thi s i nteri or fi l l covers any outl i nes that woul d be
obscured by faces cl oser to the eye. Thi s method woul d work, except that there’s no guarantee that the
i nteri or of the object fal l s enti rel y i nsi de the pol ygon’s outl i ne, and i n fact i t mi ght overl ap i t i n vari ous
pl aces.
There’s an easy, two−pass sol uti on usi ng the stenci l buffer. For each pol ygon, cl ear the stenci l buffer,
and then draw the outl i ne both i n the framebuffer and i n the stenci l buffer. Then when you fi l l the
i nteri or, enabl e drawi ng onl y where the stenci l buffer i s sti l l cl ear. To avoi d doi ng an enti re
stenci l −buffer cl ear for each pol ygon, an easy way to cl ear i t i s si mpl y to draw 0s i nto the buffer usi ng
the same pol ygon outl i ne. I n thi s way, you need to cl ear the enti re stenci l buffer onl y once.
For exampl e, the fol l owi ng code represents the i nner l oop you mi ght use to perform such hi dden−l i ne
removal . Each pol ygon i s outl i ned i n the foreground col or, fi l l ed wi th the background col or, and then
outl i ned agai n i n the foreground col or. The stenci l buffer i s used to keep the fi l l col or of each pol ygon
from overwri ti ng i ts outl i ne. To opti mi ze performance, the stenci l and col or parameters are changed
onl y twi ce per l oop by usi ng the same val ues both ti mes the pol ygon outl i ne i s drawn.
glEnable(GL_STENCIL_TEST);
glEnable(GL_DEPTH_TEST);
glClear(GL_STENCIL_BUFFER_BIT);
glStencilFunc(GL_ALWAYS, 0, 1);
glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT);
set_color(foreground);
for (i=0; i < max; i++) {
outline_polygon(i);
set_color(background);
glStencilFunc(GL_EQUAL, 0, 1);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
fill_polygon(i);
set_color(foreground);
glStencilFunc(GL_ALWAYS, 0, 1);
glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT);
outline_polygon(i);
}
See "Stencil Test."
Texture−Mapping Applications
Texture mappi ng i s qui te powerful , and i t can be used i n some i nteresti ng ways. Here are a few
advanced appl i cati ons of texture mappi ng:
• Anti al i ased textDefi ne a texture map for each character at a rel ati vel y hi gh resol uti on, and then
map them onto smal l er areas usi ng the fi l teri ng provi ded by texturi ng. Thi s al so makes text appear
correctl y on surfaces that aren’t al i gned wi th the screen, but are ti l ted and have some perspecti ve
di storti on.
275
• Anti al i ased l i nesThese can be done l i ke anti al i ased text: Make the l i ne i n the texture several
pi xel s wi de, and use the texture fi l teri ng to anti al i as the l i nes.
• I mage scal i ng and rotati onI f you put an i mage i nto a texture map and use that texture to map
onto a pol ygon, rotati ng and scal i ng the pol ygon effecti vel y rotates and scal es the i mage.
• I mage warpi ngAs i n the precedi ng exampl e, store the i mage as a texture map, but map i t to some
spl i ne−defi ned surface (use eval uators). As you warp the surface, the i mage fol l ows the warpi ng.
• Projecti ng i magesPut the i mage i n a texture map, and project i t as a spotl i ght, creati ng a sl i de
projector effect. See "The q Coordinate" for more i nformati on about how to model a spotl i ght
usi ng textures.
See Chapter 3 for i nformati on about rotati ng and scal i ng, Chapter 9 for more i nformati on about
creati ng textures, and Chapter 11 for detai l s on eval uators.
Drawing Depth−Buffered Images
For compl ex stati c backgrounds, the renderi ng ti me for the geometri c descri pti on of the background can
be greater than the ti me i t takes to draw a pi xel i mage of the rendered background. I f there’s a fi xed
background and a rel ati vel y si mpl e changi ng foreground, you may want to draw the background and
i ts associ ated depth−buffered versi on as an i mage rather than render i t geometri cal l y. The foreground
mi ght al so consi st of i tems that are ti me−consumi ng to render, but whose framebuffer i mages and
depth buffers are avai l abl e. You can render these i tems i nto a depth−buffered envi ronment usi ng a
two−pass al gori thm.
For exampl e, i f you’re drawi ng a model of a mol ecul e made of spheres, you mi ght have an i mage of a
beauti ful l y rendered sphere and i ts associ ated depth−buffer val ues that were cal cul ated usi ng Phong
shadi ng or ray−traci ng, or usi ng some other scheme that i sn’t di rectl y avai l abl e through OpenGL. To
draw a compl ex model , you mi ght be requi red to draw hundreds of such spheres, whi ch shoul d be
depth−buffered together.
To add a depth−buffered i mage to the scene, fi rst draw the i mage’s depth−buffer val ues i nto the depth
buffer usi ng glDrawPixels(). Then enabl e depth−bufferi ng, set the wri temask to zero so that no drawi ng
occurs, and enabl e stenci l i ng such that the stenci l buffers get drawn whenever a wri te to the depth
buffer occurs.
Then draw the i mage i nto the col or buffer, masked by the stenci l buffer you’ve just wri tten so that
wri ti ng occurs onl y when there’s a 1 i n the stenci l buffer. Duri ng thi s wri te, set the stenci l i ng functi on
to zero out the stenci l buffer so that i t’s automati cal l y cl eared when i t’s ti me to add the next i mage to
the scene. I f the objects are to be moved nearer to or farther from the vi ewer, you need to use an
orthographi c projecti on; i n these cases, you use GL_DEPTH_BI AS wi th glPixelTransfer*() to move the
depth i mage.
See "Hidden−Surface Removal Survival Kit,""Depth Test," see "Stencil Test," and see Chapter
8 for detai l s on glDrawPixels() and glPixelTransfer*().
Dirichlet Domains
Gi ven a set S of poi nts on a pl ane, the Di ri chl et domai n or Voronoi pol ygon of one of the poi nts i s the set
of al l poi nts i n the pl ane cl oser to that poi nt than to any other poi nt i n the set S. These poi nts provi de
the sol uti on to many probl ems i n computati onal geometry. Figure 13−3 shows outl i nes of the
Di ri chl et domai ns for a set of poi nts.
276
Figure 13−3 Di ri chl et Domai ns
I f you draw a depth−buffered cone wi th i ts apex at the poi nt i n a di fferent col or than each of the poi nts
i n S, the Di ri chl et domai n for each poi nt i s drawn i n that col or. The easi est way to do thi s i s to
precompute a cone’s depth i n an i mage, and use the i mage as the depth−buffer val ues as descri bed i n
the precedi ng secti on. You don’t need an i mage to draw i n the framebuffer as i n the case of shaded
spheres, however. Whi l e you’re drawi ng i nto the depth buffer, use the stenci l buffer to record the pi xel s
where drawi ng shoul d occur by fi rst cl eari ng i t, and then wri ti ng nonzero val ues wherever the depth
test succeeds. To draw the Di ri chl et regi on, draw a pol ygon over the enti re wi ndow, but enabl e drawi ng
onl y where the stenci l buffers are nonzero.
You can do thi s perhaps more easi l y by renderi ng cones of uni form col or wi th a si mpl e depth buffer, but
277
You can do thi s perhaps more easi l y by renderi ng cones of uni form col or wi th a si mpl e depth buffer, but
a good cone mi ght requi re thousands of pol ygons. The techni que descri bed i n thi s secti on can render
much hi gher−qual i ty cones much more qui ckl y.
See "Hidden−Surface Removal Survival Kit" and "Depth Test."
Life in the Stencil Buffer
The Game of Li fe, i nvented by John Conway, i s pl ayed on a rectangul ar gri d where each gri d l ocati on i s
"al i ve" or "dead." To cal cul ate the next generati on from the current one, count the number of l i ve
nei ghbors for each gri d l ocati on (the ei ght adjacent gri d l ocati ons are nei ghbors). A gri d l ocati on i s al i ve
i n generati on n+1 i f i t was al i ve i n generati on n and has exactl y two or three l i ve nei ghbors, or i f i t was
dead i n generati on n and has exactl y three l i ve nei ghbors. I n al l other cases, i t i s dead i n generati on n
+1. Thi s game generates some i ncredi bl y i nteresti ng patterns gi ven di fferent i ni ti al confi gurati ons.
(See Marti n Gardner, "Mathemati cal Games," Scientific American, vol . 223, no. 4, October 1970, p.
120−123.) Figure 13−4 shows si x generati ons from a game.
278
Figure 13−4 Si x Generati ons from the Game of Li fe
One way to create thi s game usi ng OpenGL i s to use a mul ti pass al gori thm. Keep the data i n the col or
buffer, one pi xel for each gri d poi nt. Assume that bl ack (al l zeros) i s the background col or, and the col or
of a l i ve pi xel i s nonzero. I ni ti al i ze by cl eari ng the depth and stenci l buffers to zero, set the
depth−buffer wri temask to zero, and set the depth compari son functi on so that i t passes on not−equal .
To i terate, read the i mage off the screen, enabl e drawi ng i nto the depth buffer, and set the stenci l
functi on so that i t i ncrements whenever a depth compari son succeeds but l eaves the stenci l buffer
unchanged otherwi se. Di sabl e drawi ng i nto the col or buffer.
Next, draw the i mage ei ght ti mes, offset one pi xel i n each verti cal , hori zontal , and di agonal di recti on.
When you’re done, the stenci l buffer contai ns a count of the number of l i ve nei ghbors for each pi xel .
Enabl e drawi ng to the col or buffer, set the col or to the col or for l i ve cel l s, and set the stenci l functi on to
draw onl y i f the val ue i n the stenci l buffer i s 3 (three l i ve nei ghbors). I n addi ti on, i f thi s drawi ng occurs,
decrement the val ue i n the stenci l buffer. Then draw a rectangl e coveri ng the i mage; thi s pai nts each
cel l that has exactl y three l i ve nei ghbors wi th the "al i ve" col or.
At thi s poi nt, the stenci l buffers contai n 0, 1, 2, 4, 5, 6, 7, 8, and the val ues under the 2s are correct. The
val ues under 0, 1, 4, 5, 6, 7, and 8 must be cl eared to the "dead" col or. Set the stenci l functi on to draw
whenever the val ue i s not 2, and to zero the stenci l val ues i n al l cases. Then draw a l arge pol ygon of the
"dead" col or across the enti re i mage. You’re done.
For a usabl e demonstrati on program, you mi ght want to zoom the gri d up to a si ze l arger than a si ngl e
pi xel ; i t’s hard to see detai l ed patterns wi th a si ngl e pi xel per gri d poi nt.
See "Hidden−Surface Removal Survival Kit,""Depth Test," and "Stencil Test."
Alternative Uses for glDrawPixels() and glCopyPixels()
You mi ght thi nk of glDrawPixels() as a way to draw a rectangul ar regi on of pi xel s to the screen.
Al though thi s i s often what i t’s used for, some other i nteresti ng uses are outl i ned here.
• Vi deoEven i f your machi ne doesn’t have speci al vi deo hardware, you can di spl ay short movi e cl i ps
by repeatedl y drawi ng frames wi th glDrawPixels() i n the same regi on of the back buffer and then
swappi ng the buffers. The si ze of the frames you can di spl ay wi th reasonabl e performance usi ng
thi s method depends on your hardware’s drawi ng speed, so you mi ght be l i mi ted to 100×100 pi xel
movi es (or smal l er) i f you want smooth fake vi deo.
• Ai rbrushI n a pai nt program, your ai rbrush (or pai ntbrush) shape can be si mul ated usi ng al pha
val ues. The col or of the pai nt i s represented as the col or val ues. To pai nt wi th a ci rcul ar brush i n
bl ue, repeatedl y draw a bl ue square wi th glDrawPixels() where the al pha val ues are l argest i n the
center and taper to zero at the edges of a ci rcl e centered i n the square. Draw usi ng a bl endi ng
functi on that uses al pha of the i ncomi ng col or and (1−al pha) of the col or al ready at the pi xel . I f the
al pha val ues i n the brush are al l much l ess than 1, you have to pai nt over an area repeatedl y to get
a sol i d col or. I f the al pha val ues are near 1, each brush stroke pretty much obl i terates the col ors
underneath.
• Fi l tered ZoomsI f you zoom a pi xel i mage by a noni ntegral amount, OpenGL effecti vel y uses a box
fi l ter, whi ch can l ead to rather severe al i asi ng effects. To i mprove the fi l teri ng, ji tter the resul ti ng
i mage by amounts l ess than a pi xel and redraw i t mul ti pl e ti mes, usi ng al pha bl endi ng to average
the resul ti ng pi xel s. The resul t i s a fi l tered zoom.
• Transposi ng I magesYou can swap same−si ze i mages i n pl ace wi th glCopyPixels() usi ng the XOR
operati on. Wi th thi s method, you can avoi d havi ng to read the i mages back i nto processor memory.
I f A and B represent the two i mages, the operati on l ooks l i ke thi s:
1. A = A XOR B
2. B = A XOR B
3. A = A XOR B
279
Appendi x A
Order of Operations
Thi s gui de descri bes al l the operati ons performed between the ti me verti ces are speci fi ed and when
fragments are fi nal l y wri tten i nto the framebuffer. The chapters of thi s gui de are arranged i n an order
that faci l i tates l earni ng rather than i n the exact order i n whi ch these operati ons are actual l y
performed. Someti mes the exact order of operati ons doesn’t matterfor exampl e, surfaces can be
converted to pol ygons and then transformed, or transformed fi rst and then converted to pol ygons, wi th
i denti cal resul tsand di fferent i mpl ementati ons of OpenGL mi ght do thi ngs di fferentl y. Thi s appendi x
descri bes a possi bl e order; any i mpl ementati on i s requi red to gi ve equi val ent resul ts. I f you want more
detai l s than are presented here, see the OpenGL ReferenceManual.
Thi s appendi x has the fol l owi ng major secti ons:
• "Overview"
• "Geometric Operations"
• "Pixel Operations"
• "Fragment Operations"
• "Odds and Ends"
Overview
Thi s secti on gi ves an overvi ew of the order of operati ons, as shown i n Figure A−1 . Geometri c data
(verti ces, l i nes, and pol ygons) fol l ows the path through the row of boxes that i ncl udes eval uators and
per−vertex operati ons, whi l e pi xel data (pi xel s, i mages, and bi tmaps) i s treated di fferentl y for part of
the process. Both types of data undergo the rasteri zati on and per−fragment operati ons before the fi nal
pi xel data i s wri tten i nto the framebuffer.
Figure A−1 Order of Operati ons
Al l data, whether i t descri bes geometry or pi xel s, can be saved i n a di spl ay l i st or processed
i mmedi atel y. When a di spl ay l i st i s executed, the data i s sent from the di spl ay l i st just as i f i t were sent
by the appl i cati on.
Al l geometri c pri mi ti ves are eventual l y descri bed by verti ces. I f eval uators are used, that data i s
converted to verti ces and treated as verti ces from then on. Per−vertex cal cul ati ons are performed on
each vertex, fol l owed by rasteri zati on to fragments. For pi xel data, pi xel operati ons are performed, and
the resul ts are ei ther stored i n the texture memory, used for pol ygon sti ppl i ng, or rasteri zed to
fragments.
Fi nal l y, the fragments are subjected to a seri es of per−fragment operati ons, after whi ch the fi nal pi xel
val ues are drawn i nto the framebuffer.
280
Geometric Operations
Geometri c data, whether i t comes from a di spl ay l i st, an eval uator, the verti ces of a rectangl e, or as raw
data, consi sts of a set of verti ces and the type of pri mi ti ve i t descri bes (a vertex, l i ne, or pol ygon).
Vertex data i ncl udes not onl y the (x, y, z, w) coordi nates, but al so a normal vector, texture coordi nates,
a col or or i ndex, and edge−fl ag data. Al l these el ements except the vertex’s coordi nates can be speci fi ed
i n any order, and defaul t val ues exi st as wel l . As soon as the vertex command glVertex*() i s i ssued, the
components are padded, i f necessary, to four di mensi ons (usi ng z = 0 and w = 1), and the current val ues
of al l the el ements are associ ated wi th the vertex. The compl ete set of vertex data i s then processed.
Per−Vertex Operations
I n the per−vertex operati ons stage of processi ng, each vertex’s spati al coordi nates are transformed by
the model vi ew matri x, whi l e the normal vector i s transformed by that matri x’s i nverse and
renormal i zed i f speci fi ed. I f automati c texture generati on i s enabl ed, new texture coordi nates are
generated from the transformed vertex coordi nates, and they repl ace the vertex’s ol d texture
coordi nates. The texture coordi nates are then transformed by the current texture matri x and passed on
to the pri mi ti ve assembl y step.
Meanwhi l e, the l i ghti ng cal cul ati ons, i f enabl ed, are performed usi ng the transformed vertex and
normal vector coordi nates, and the current materi al , l i ghts, and l i ghti ng model . These cal cul ati ons
generate new col ors or i ndi ces that are cl amped or masked to the appropri ate range and passed on to
the pri mi ti ve assembl y step.
Primitive Assembly
Pri mi ti ve assembl y di ffers, dependi ng on whether the pri mi ti ve i s a poi nt, a l i ne, or a pol ygon. I f fl at
shadi ng i s enabl ed, the col ors or i ndi ces of al l the verti ces i n a l i ne or pol ygon are set to the same val ue.
I f speci al cl i ppi ng pl anes are defi ned and enabl ed, they’re used to cl i p pri mi ti ves of al l three types. (The
cl i ppi ng−pl ane equati ons are transformed by the i nverse of the model vi ew matri x when they’re
speci fi ed.) Poi nt cl i ppi ng si mpl y passes or rejects verti ces; l i ne or pol ygon cl i ppi ng can add addi ti onal
verti ces dependi ng on how the l i ne or pol ygon i s cl i pped. After thi s cl i ppi ng, the spati al coordi nates of
each vertex are transformed by the projecti on matri x, and the resul ts are cl i pped agai nst the standard
vi ewi ng pl anes x = ±w, y = ±w, and z = ±w.
I f sel ecti on i s enabl ed, any pri mi ti ve not el i mi nated by cl i ppi ng generates a sel ecti on−hi t report, and no
further processi ng i s performed. Wi thout sel ecti on, perspecti ve di vi si on by w occurs and the vi ewport
and depth−range operati ons are appl i ed. Al so, i f the pri mi ti ve i s a pol ygon, i t’s then subjected to a
cul l i ng test (i f cul l i ng i s enabl ed). A pol ygon mi ght convert to verti ces or l i nes, dependi ng on the
pol ygon mode.
Fi nal l y, poi nts, l i nes, and pol ygons are rasteri zed to fragments, taki ng i nto account pol ygon or l i ne
sti ppl es, l i ne wi dth, and poi nt si ze. Rasteri zati on i nvol ves determi ni ng whi ch squares of an i nteger gri d
i n wi ndow coordi nates are occupi ed by the pri mi ti ve. Col or and depth val ues are al so assi gned to each
such square.
Pixel Operations
Pi xel s from host memory are fi rst unpacked i nto the proper number of components. The OpenGL
unpacki ng faci l i ty handl es a number of di fferent formats. Next, the data i s scal ed, bi ased, and
processed usi ng a pi xel map. The resul ts are cl amped to an appropri ate range dependi ng on the data
type, and then ei ther wri tten i n the texture memory for use i n texture mappi ng or rasteri zed to
fragments.
281
I f pi xel data i s read from the framebuffer, pi xel −transfer operati ons (scal e, bi as, mappi ng, and
cl ampi ng) are performed. The resul ts are packed i nto an appropri ate format and then returned to
processor memory.
The pi xel copy operati on i s si mi l ar to a combi nati on of the unpacki ng and transfer operati ons, except
that packi ng and unpacki ng i s unnecessary, and onl y a si ngl e pass i s made through the transfer
operati ons before the data i s wri tten back i nto the framebuffer.
Fragment Operations
I f texturi ng i s enabl ed, a texel i s generated from texture memory for each fragment and appl i ed to the
fragment. Then fog cal cul ati ons are performed, i f they’re enabl ed, fol l owed by coverage (anti al i asi ng)
cal cul ati ons i f anti al i asi ng i s enabl ed.
Next comes sci ssori ng, fol l owed by the al pha test (i n RGBA mode onl y), the stenci l test, the
depth−buffer test, and di theri ng. Al l of these operati ons can be di sabl ed. Next, i f i n i ndex mode, a
l ogi cal operati on i s appl i ed i f one has been speci fi ed. I f i n RGBA mode, bl endi ng i s performed.
The fragment i s then masked by a col or mask or an i ndex mask, dependi ng on the mode, and drawn
i nto the appropri ate buffer. I f fragments are bei ng wri tten i nto the stenci l or depth buffer, maski ng
occurs after the stenci l and depth tests, and the resul ts are drawn i nto the framebuffer wi thout
performi ng the bl endi ng, di theri ng, or l ogi cal operati on.
Odds and Ends
Matri x operati ons deal wi th the current matri x stack, whi ch can be the model vi ew, the projecti on, or
the texture matri x stack. The commands glMultMatrix*(), glLoadMatrix*(), and glLoadI dentity() are
appl i ed to the top matri x on the stack, whi l e glTranslate*(), glRotate*(), glScale*(), glOrtho(), and
glFrustum() are used to create a matri x that’s mul ti pl i ed by the top matri x. When the model vi ew
matri x i s modi fi ed, i ts i nverse i s al so generated for normal vector transformati on.
The commands that set the current raster posi ti on are treated exactl y l i ke a vertex command up unti l
when rasteri zati on woul d occur. At thi s poi nt, the val ue i s saved and i s used i n the rasteri zati on of
pi xel data.
The vari ous glClear() commands bypass al l operati ons except sci ssori ng, di theri ng, and wri temaski ng.
Appendi x B
OpenGL State Variables
Thi s appendi x l i sts the queryabl e OpenGL state vari abl es, thei r defaul t val ues, and the commands for
obtai ni ng the val ues of these vari abl es. I t al so descri bes OpenGL’s error handl i ng faci l i ty, and how to
save and restore sets of state vari abl es. The OpenGL ReferenceManual contai ns detai l ed i nformati on
on al l the commands and constants di scussed i n thi s appendi x. Thi s appendi x has these major secti ons:
• "The Query Commands"
• "Error Handling"
• "Saving and Restoring Sets of State Variables"
• "OpenGL State Variables"
The Query Commands
There are four commands for obtai ni ng si mpl e state vari abl es, and one for determi ni ng whether a
parti cul ar state i s enabl ed or di sabl ed.
282
voi d glGetBooleanv(GLenum pname, GLbool ean *params);
voi d glGetI ntegerv(GLenum pname, GLi nt *params);
voi d glGetFloatv(GLenum pname, GLfl oat *params);
voi d glGetDoublev(GLenum pname, GLdoubl e *params);
Obtai ns Bool ean, i nteger, fl oati ng−poi nt, or doubl e−preci si on state vari abl es. The pnameargument i s a
symbol i c constant i ndi cati ng the state vari abl e to return, and paramsi s a poi nter to an array of the
i ndi cated type i n whi ch to pl ace the returned data. The possi bl e val ues for pnameare l i sted i n the
tabl es i n "OpenGL State Variables." A type conversi on i s performed i f necessary to return the
desi red vari abl e as the requested data type.
GLbool ean glI sEnabled(GLenum cap)
Returns GL_TRUE i f the mode speci fi ed by cap i s enabl ed; otherwi se, returns GL_FALSE. The possi bl e
val ues for cap are l i sted i n the tabl es i n "OpenGL State Variables"
Other speci al i zed commands return speci fi c state vari abl es. The prototypes for these commands are
l i sted here; to fi nd out when you need to use these commands, use the tabl es i n "OpenGL State
Variables" Al so see the OpenGL ReferenceManual. OpenGL’s error handl i ng faci l i ty and the
glGetError() command are descri bed i n more detai l i n the next secti on.
voi d glGetClipPlane(GLenum plane, GLdoubl e *equation);
GLenum glGetError(voi d);
voi d glGetLight{i f}v(GLenum light, GLenum pname, TYPE *params);
voi d glGetMap{i fd}v(GLenum target, GLenum query, TYPE *v);
voi d glGetMaterial{i f}v(GLenum face, GLenum pname, TYPE *params);
voi d glGetPixelMap{f ui us}v(GLenum map, TYPE *values);
voi d glGetPolygonStipple(GLubyte *mask);
const GLubyte * glGetString(GLenum name);
voi d glGetTexEnv{i f}v(GLenum target, GLenum pname, TYPE *params);
voi d glGetTexGen{i fd}v(GLenum coord, GLenum pname, TYPE *params);
voi d glGetTexI mage(GLenum target, GLi nt level, GLenum format, GLenum type, GLvoi d *pixels);
voi d glGetTexLevelParameter{i f}v(GLenum target, GLi nt level, GLenum pname, TYPE *params);
voi d glGetTexParameter{i f}v(GLenum target, GLenum pname, TYPE *params);
Error Handling
When OpenGL detects an error, i t records a current error code. The command that caused the error i s
i gnored, so i t has no effect on OpenGL state or on the framebuffer contents. (I f the error recorded was
GL_OUT_OF_MEMORY, however, the resul ts of the command are undefi ned.) Once recorded, the
current error code i sn’t cl earedthat i s, addi ti onal errors aren’t recordedunti l you cal l the query
command glGetError(), whi ch returns the current error code. I n di stri buted i mpl ementati ons of
OpenGL, there mi ght be mul ti pl e current error codes, each of whi ch remai ns set unti l queri ed. Once
you’ve queri ed al l the current error codes, or i f there’s no error, glGetError() returns GL_NO_ERROR.
Thus, i f you obtai n an error code, i t’s good practi ce to conti nue to cal l glGetError() unti l
GL_NO_ERROR i s returned to be sure you’ve di scovered al l the errors. Table B−1 l i sts the defi ned
OpenGL error codes.
You can use the GLU routi ne gluErrorString() to obtai n a descri pti ve stri ng correspondi ng to the error
code passed i n. Thi s routi ne i s descri bed i n more detai l i n "Describing Errors." Note that GLU
routi nes often return error val ues i f an error i s detected. Al so, the GLU defi nes the error codes
GLU_I NVALI D_ENUM, GLU_I NVALI D_VALUE, and GLU_OUT_OF_MEMORY, whi ch have the
same meani ng as the rel ated OpenGL codes.
Error Code Description
283
GL_INVALID_ENUM GLenum argument out of range
GL_INVALID_VALUE Numeric argument out of range
GL_INVALID_OPERATION Operation illegal in current state
GL_STACK_OVERFLOW Command would cause a stack overflow
GL_STACK_UNDERFLOW Command would cause a stack underflow
GL_OUT_OF_MEMORY Not enough memory left to execute command
Table B−1 OpenGL Error Codes
Saving and Restoring Sets of State Variables
You can save and restore the val ues of a col l ecti on of state vari abl es on an attri bute stack wi th the
commands glPushAttrib() and glPopAttrib(). The attri bute stack has a depth of at l east 16, and the
actual depth can be obtai ned usi ng GL_MAX_ATTRI B_STACK_DEPTH wi th glGetI ntegerv(). Pushi ng
a ful l stack or poppi ng an empty one generates an error.
I n general , i t’s faster to use glPushAttrib() and glPopAttrib() than to get and restore the val ues yoursel f.
Some val ues mi ght be pushed and popped i n the hardware, and savi ng and restori ng them mi ght be
expensi ve. Al so, i f you’re operati ng on a remote cl i ent, al l the attri bute data has to be transferred
across the network connecti on and back as i t’s saved and restored. However, your OpenGL
i mpl ementati on keeps the attri bute stack on the server, avoi di ng unnecessary network del ays.
voi d glPushAttrib(GLbi tfi el d mask);
Saves al l the attri butes i ndi cated by bi ts i n mask by pushi ng them onto the attri bute stack. Table B−2
l i sts the possi bl e mask bi ts that can be l ogi cal l y ORed together to save any combi nati on of attri butes.
Each bi t corresponds to a col l ecti on of i ndi vi dual state vari abl es. For exampl e, GL_LI GHTI NG_BI T
refers to al l the state vari abl es rel ated to l i ghti ng, whi ch i ncl ude the current materi al col or, the
ambi ent, di ffuse, specul ar, and emi tted l i ght, a l i st of the l i ghts that are enabl ed, and the di recti ons of
the spotl i ghts. When glPopAttrib() i s cal l ed, al l those vari abl es are restored. To fi nd out exactl y whi ch
attri butes are saved for parti cul ar mask val ues, see the tabl es i n "OpenGL State Vari abl es."
Mask Bit Attribute Group
GL_ACCUM_BUFFER_BIT accum−buffer
GL_ALL_ATTRIB_BITS −−
GL_COLOR_BUFFER_BIT color−buffer
GL_CURRENT_BIT current
GL_DEPTH_BUFFER_BIT depth−buffer
GL_ENABLE_BIT enable
GL_EVAL_BIT eval
GL_FOG_BIT fog
GL_HINT_BIT hint
GL_LIGHTING_BIT lighting
GL_LINE_BIT line
GL_LIST_BIT list
GL_PIXEL_MODE_BIT pixel
GL_POINT_BIT point
GL_POLYGON_BIT polygon
GL_POLYGON_STIPPLE_BIT polygon−stipple
GL_SCISSOR_BIT scissor
GL_STENCIL_BUFFER_BIT stencil−buffer
GL_TEXTURE_BIT texture
GL_TRANSFORM_BIT transform
GL_VIEWPORT_BIT viewport
Table B−2 Attri bute Groups
284
voi d glPopAttrib(voi d);
Restores the val ues of those state vari abl es that were saved wi th the l ast glPushAttrib().
OpenGL State Variables
The fol l owi ng pages contai n tabl es that l i st the names of queryabl e state vari abl es. For each vari abl e,
the tabl es l i st a descri pti on of i t, i ts attri bute group, i ts i ni ti al or mi ni mum val ue, and the suggested
glGet*() command to use for obtai ni ng i t. State vari abl es that can be obtai ned usi ng glGetBooleanv(),
glGetI ntegerv(), glGetFloatv(), or glGetDoublev() are l i sted wi th just one of these commandsthe one
that’s most appropri ate gi ven the type of data to be returned. These state vari abl es can’t be obtai ned
usi ng glI sEnabled(). However, state vari abl es for whi ch glI sEnabled() i s l i sted as the query command
can al so be obtai ned usi ng glGetBooleanv(), glGetI ntegerv(), glGetFloatv(), and glGetDoublev(). State
vari abl es for whi ch any other command i s l i sted as the query command can be obtai ned onl y by usi ng
that command. I f no attri bute group i s l i sted, the vari abl e doesn’t bel ong to any group. Al l queryabl e
state vari abl es except the i mpl ementati on−dependent ones have i ni ti al val ues. I f no i ni ti al val ue i s
l i sted, you need to consul t the secti on where that vari abl e i s di scussed (or the OpenGL Reference
Manual) to determi ne i ts i ni ti al val ue.
Current Values and Associated Data
State Variable Description Attribute
Group
I
GL_CURRENT_COLOR Current color current
GL_CURRENT_INDEX Current color index current
GL_CURRENT_TEXTURE_COORDS Current texture coordinates current
GL_CURRENT_NORMAL Current normal current
GL_CURRENT_RASTER_POSITION Current raster position current
GL_CURRENT_RASTER_DISTANCE Current raster distance current
GL_CURRENT_RASTER_COLOR Color associated with raster
position
current
GL_CURRENT_RASTER_INDEX Color index associated with
raster position
current
GL_CURRENT_RASTER_TEXTURE_
COORDS
Texture coordinates
associated with raster
position
current
GL_CURRENT_RASTER_POSITION_ VALID Raster position valid bit current
GL_EDGE_FLAG Edge flag current
Table B−3 State Vari abl es for Current Val ues and Associ ated Data
Transformation
State Variable Description Attribute
Group
GL_MODELVIEW_MATRIX Modelview matrix stack −−
GL_PROJECTION_MATRIX Projection matrix stack −−
GL_TEXTURE_MATRIX Texture matrix stack −−
GL_VIEWPORT Viewport origin and extent viewport
GL_DEPTH_RANGE Depth range near and far viewport
GL_MODELVIEW_STACK_DEPTH Modelview matrix stack
pointer
−−
GL_PROJECTION_STACK_DEPTH Projection matrix stack pointer −−
GL_TEXTURE_STACK_DEPTH Texture matrix stack pointer −−
285
GL_MATRIX_MODE Current matrix mode transform
GL_NORMALIZE Current normal normalization
on/off
transform/
enable
GL_CLIP_PLANEi User clipping plane
coefficients
transform
GL_CLIP_PLANEi ith user clipping plane
enabled
transform/
enable
Table B−4 Transformati on State Vari abl es
Coloring
State Variable Description Attribute
Group
Initial
Value
GL_FOG_COLOR Fog color fog 0, 0, 0, 0
GL_FOG_INDEX Fog index fog 0
GL_FOG_DENSITY Exponential fog density fog 1.0
GL_FOG_START Linear fog start fog 0.0
GL_FOG_END Linear fog end fog 1.0
GL_FOG_MODE Fog mode fog GL_EXP
GL_FOG True if fog enabled fog/enable GL_FAL
SE
GL_SHADE_MODEL glShadeModel() setting lighting GL_SMO
OTH
Table B−5 Col ori ng State Vari abl es
Lighting
See al so Table 6−1 and Table 6−2 for i ni ti al val ues.
State Variable Description Attribute
Group
GL_LIGHTING True if lighting is enabled lighting
/enable
GL_COLOR_MATERIAL True if color tracking is enabled lighting
GL_COLOR_MATERIAL_PARAME TER Material properties tracking
current color
lighting
GL_COLOR_MATERIAL_FACE Face(s) affected by color tracking lighting
GL_AMBIENT Ambient material color lighting
GL_DIFFUSE Diffuse material color lighting
GL_SPECULAR Specular material color lighting
GL_EMISSION Emissive material color lighting
GL_SHININESS Specular exponent of material lighting
GL_LIGHT_MODEL_AMBIENT Ambient scene color lighting
GL_LIGHT_MODEL_LOCAL_VIE WER Viewer is local lighting
GL_LIGHT_MODEL_TWO_SIDE Use two−sided lighting lighting
GL_AMBIENT Ambient intensity of light i lighting
GL_DIFFUSE Diffuse intensity of light i lighting
GL_SPECULAR Specular intensity of light i lighting
GL_POSITION Position of light i lighting
GL_CONSTANT_ATTENUATION Constant attenuation factor lighting
GL_LINEAR_ATTENUATION Linear attenuation factor lighting
GL_QUADRATIC_ATTENUATION Quadratic attenuation factor lighting
GL_SPOT_DIRECTION Spotlight direction of light i lighting
GL_SPOT_EXPONENT Spotlight exponent of light i lighting
286
GL_SPOT_CUTOFF Spotlight angle of light i lighting
GL_LIGHTi True if light i enabled lighting
/enable
GL_COLOR_INDEXES ca, cd, and cs for color−index
lighting
lighting
/enable
Table B−6 Li ghti ng State Vari abl es
Rasterization
State Variable Description Attribute Group
GL_POINT_SIZE Point size point
GL_POINT_SMOOTH Point antialiasing on point/enable
GL_LINE_WIDTH Line width line
GL_LINE_SMOOTH Line antialiasing on line/enable
GL_LINE_STIPPLE_PATTERN Line stipple line
GL_LINE_STIPPLE_REPEAT Line stipple repeat line
GL_LINE_STIPPLE Line stipple enable line/enable
GL_CULL_FACE Polygon culling enabled polygon/enable
GL_CULL_FACE_MODE Cull front−/back−facing polygons polygon
GL_FRONT_FACE Polygon front−face CW/CCW
indicator
polygon
GL_POLYGON_SMOOTH Polygon antialiasing on polygon/enable
GL_POLYGON_MODE Polygon rasterization mode (front
and back)
polygon
GL_POLYGON_STIPPLE Polygon stipple enable polygon/enable
−− Polygon stipple pattern polygon−stipple
Table B−7 Rasteri zati on State Vari abl es
Texturing
State Variable Description Attribute
Group
Initial
Value
GL_TEXTURE_x True if x−D texturing enabled (x is
1D or 2D)
texture/
enable
GL_F
ALSE
GL_TEXTURE x−D texture image at level of
detail i
−− −−
GL_TEXTURE_WIDTH x−D texture image i’s width −− 0
GL_TEXTURE_HEIGHT x−D texture image i’s height −− 0
GL_TEXTURE_BORDER x−D texture image i’s border
width
−− 0
GL_TEXTURE_COMPONENTS Texture image components −− 1
GL_TEXTURE_BORDER_COL OR Texture border color texture 0, 0,
0, 0
GL_TEXTURE_MIN_FILTER Texture minification function texture GL_N
EARE
ST_
MIPM
AP_LI
NEA
R
GL_TEXTURE_MAG_FILTER Texture magnification function texture GL_LI
NEAR
GL_TEXTURE_WRAP_x Texture wrap mode (x is S or T) texture GL_R
287
EPEA
T
GL_TEXTURE_ENV_MODE Texture application function texture GL_M
ODUL
ATE
GL_TEXTURE_ENV_COLOR Texture environment color texture 0, 0,
0, 0
GL_TEXTURE_GEN_x Texgen enabled (x is S, T, R, or
Q)
texture/
enable
GL_F
ALSE
GL_EYE_LINEAR Texgen plane equation
coefficients
texture −−
GL_OBJECT_LINEAR Texgen object linear coefficients texture −−
GL_TEXTURE_GEN_MODE Function used for texgen texture GL_E
YE_LI
NEA
R
Table B−8 Texturi ng State Vari abl es
Pixel Operations
State Variable Description Attribute Group
GL_SCISSOR_TEST Scissoring enabled scissor/enable
GL_SCISSOR_BOX Scissor box scissor
GL_STENCIL_TEST Stenciling enabled stencil−buffer/
enable
GL_STENCIL_FUNC Stencil function stencil−buffer
GL_STENCIL_VALUE_MASK Stencil mask stencil−buffer
GL_STENCIL_REF Stencil reference value stencil−buffer
GL_STENCIL_FAIL Stencil fail action stencil−buffer
GL_STENCIL_PASS_DEPTH_FAI L Stencil depth buffer fail action stencil−buffer
GL_STENCIL_PASS_DEPTH_PAS S Stencil depth buffer pass
action
stencil−buffer
GL_ALPHA_TEST Alpha test enabled color−buffer/e
nable
GL_ALPHA_TEST_FUNC Alpha test function color−buffer
GL_ALPHA_TEST_REF Alpha test reference value color−buffer
GL_DEPTH_TEST Depth buffer enabled depth−buffer/
enable
GL_DEPTH_FUNC Depth buffer test function depth−buffer
GL_BLEND Blending enabled color−buffer/e
nable
GL_BLEND_SRC Blending source function color−buffer
GL_BLEND_DST Blending destination function color−buffer
GL_LOGIC_OP Logical operation enabled color−buffer/e
nable
GL_LOGIC_OP_MODE Logical operation function color−buffer
GL_DITHER Dithering enabled color−buffer/e
nable
Table B−9 Pi xel Operati ons
Framebuffer Control
State Variable Description Attribute
Group
288
GL_DRAW_BUFFER Buffers selected for drawing color−buffer
GL_INDEX_WRITEMASK Color−index writemask color−buffer
GL_COLOR_WRITEMASK Color write enables; R, G, B, or A color−buffer
GL_DEPTH_WRITEMASK Depth buffer enabled for writing depth−buffer
GL_STENCIL_WRITEMASK Stencil−buffer writemask stencil−buffer
GL_COLOR_CLEAR_VALUE Color−buffer clear value (RGBA
mode)
color−buffer
GL_INDEX_CLEAR_VALUE Color−buffer clear value (color−index
mode)
color−buffer
GL_DEPTH_CLEAR_VALUE Depth−buffer clear value depth−buffer
GL_STENCIL_CLEAR_VALUE Stencil−buffer clear value stencil−buffer
GL_ACCUM_CLEAR_VALUE Accumulation−buffer clear value accum−buffer
Table B−10 Framebuffer Control State Vari abl es
Pixels
State Variable Description Attribute
Group
I
GL_UNPACK_SWAP_BYTES Value of
GL_UNPACK_SWAP_BYTES
−−
GL_UNPACK_LSB_FIRST Value of GL_UNPACK_LSB_FIRST −−
GL_UNPACK_ROW_LENGTH Value of
GL_UNPACK_ROW_LENGT H
−−
GL_UNPACK_SKIP_ROWS Value of
GL_UNPACK_SKIP_ROWS
−−
GL_UNPACK_SKIP_PIXELS Value of
GL_UNPACK_SKIP_PIXELS
−−
GL_UNPACK_ALIGNMENT Value of
GL_UNPACK_ALIGNMENT
−−
GL_PACK_SWAP_BYTES Value of GL_PACK_SWAP_BYTES −−
GL_PACK_LSB_FIRST Value of GL_PACK_LSB_FIRST −−
GL_PACK_ROW_LENGTH Value of
GL_PACK_ROW_LENGTH
−−
GL_PACK_SKIP_ROWS Value of GL_PACK_SKIP_ROWS −−
GL_PACK_SKIP_PIXELS Value of GL_PACK_SKIP_PIXELS −−
GL_PACK_ALIGNMENT Value of GL_PACK_ALIGNMENT −−
GL_MAP_COLOR True if colors are mapped pixel
GL_MAP_STENCIL True if stencil values are mapped pixel
GL_INDEX_SHIFT Value of GL_INDEX_SHIFT pixel
GL_INDEX_OFFSET Value of GL_INDEX_OFFSET pixel
GL_x_SCALE Value of GL_x_SCALE; x is
GL_RED, GL_GREEN, GL_BLUE,
GL_ALPHA, or GL_DEPTH
pixel
GL_x_BIAS Value of GL_x_BIAS; x is one of
GL_RED, GL_GREEN, GL_BLUE,
GL_ALPHA, or GL_DEPTH
pixel
GL_ZOOM_X x zoom factor pixel
GL_ZOOM_Y y zoom factor pixel
GL_x glPixelMap() translation tables; x is
a map name from Table 8−5
pixel
GL_x_SIZE Size of table x pixel
GL_READ_BUFFER Read source buffer pixel
Table B−11 Pi xel State Vari abl es
289
Evaluators
State Variable Description Attribute Group Initi
al
Val
ue
GL_ORDER 1D map order −− 1
GL_ORDER 2D map orders −− 1, 1
GL_COEFF 1D control points −− −−
GL_COEFF 2D control points −− −−
GL_DOMAIN 1D domain endpoints −− −−
GL_DOMAIN 2D domain endpoints −− −−
GL_MAP1_x 1D map enables: x is map
type
eval/enable GL_
FAL
SE
GL_MAP2_x 2D map enables: x is map
type
eval/enable GL_
FAL
SE
GL_MAP1_GRID_DOMAIN 1D grid endpoints eval 0, 1
GL_MAP2_GRID_DOMAIN 2D grid endpoints eval 0, 1;
0, 1
GL_MAP1_GRID_SEGMENTS 1D grid divisions eval 1
GL_MAP2_GRID_SEGMENTS 2D grid divisions eval 1,1
GL_AUTO_NORMAL True if automatic normal
generation enabled
eval GL_
FAL
SE
Table B−12 Eval uator State Vari abl es
Hints
State Variable Description Attribute
Group
Initi
al
Val
ue
GL_PERSPECTIVE_CORRECTION_ HINT Perspective correction hint hint GL_
DO
NT_
CA
RE
GL_POINT_SMOOTH_HINT Point smooth hint hint GL_
DO
NT_
CA
RE
GL_LINE_SMOOTH_HINT Line smooth hint hint GL_
DO
NT_
CA
RE
GL_POLYGON_SMOOTH_HINT Polygon smooth hint hint GL_
DO
NT_
CA
290
RE
GL_FOG_HINT Fog hint hint GL_
DO
NT_
CA
RE
Table B−13 Hi nt State Vari abl es
Implementation−Dependent Values
State Variable Description Attrib
ute
Grou
p
GL_MAX_LIGHTS Maximum number of lights −−
GL_MAX_CLIP_PLANES Maximum number of user clipping planes −−
GL_MAX_MODELVIEW_STACK_
DEPTH
Maximum modelview−matrix stack depth −−
GL_MAX_PROJECTION_STACK_
DEPTH
Maximum projection−matrix stack depth −−
GL_MAX_TEXTURE_STACK_DE PTH Maximum depth of texture matrix stack −−
GL_SUBPIXEL_BITS Number of bits of subpixel precision in x and
y
−−
GL_MAX_TEXTURE_SIZE Maximum height or width of a texture image
(w/o borders)
−−
GL_MAX_PIXEL_MAP_TABLE Maximum size of a glPixelMap() translation
table
−−
GL_MAX_NAME_STACK_DEPT H Maximum selection−name stack depth −−
GL_MAX_LIST_NESTING Maximum display−list call nesting −−
GL_MAX_EVAL_ORDER Maximum evaluator polynomial order −−
GL_MAX_VIEWPORT_DIMS Maximum viewport dimensions −−
GL_MAX_ATTRIB_STACK_DEPT H Maximum depth of the attribute stack −−
GL_AUX_BUFFERS Number of auxiliary buffers −−
GL_RGBA_MODE True if color buffers store RGBA −−
GL_INDEX_MODE True if color buffers store indices −−
GL_DOUBLEBUFFER True if front & back buffers exist −−
GL_STEREO True if left & right buffers exist −−
GL_POINT_SIZE_RANGE Range (low to high) of antialiased point
sizes
−−
GL_POINT_SIZE_GRANULARIT Y Antialiased point−size granularity −−
GL_LINE_WIDTH_RANGE Range (low to high) of antialiased line
widths
−−
GL_LINE_WIDTH_GRANULARI TY Antialiased line−width granularity −−
Table B−14 I mpl ementati on−Dependent State Vari abl es
Implementation−Dependent Pixel Depths
State Variable Description Attrib
ute
Grou
p
GL_RED_BITS Number of bits per red component in color
buffers
−−
GL_GREEN_BITS Number of bits per green component in −−
291
color buffers
GL_BLUE_BITS Number of bits per blue component in color
buffers
−−
GL_ALPHA_BITS Number of bits per alpha component in
color buffers
−−
GL_INDEX_BITS Number of bits per index in color buffers −−
GL_DEPTH_BITS Number of depth−buffer bitplanes −−
GL_STENCIL_BITS Number of stencil bitplanes −−
GL_ACCUM_RED_BITS Number of bits per red component in the
accumulation buffer
−−
GL_ACCUM_GREEN_BITS Number of bits per green component in the
accumulation buffer
−−
GL_ACCUM_BLUE_BITS Number of bits per blue component in the
accumulation buffer
−−
GL_ACCUM_ALPHA_BITS Number of bits per alpha component in the
accumulation buffer
−−
Table B−15 I mpl ementati on−Dependent Pi xel −Depth State Vari abl es
Miscellaneous
State Variable Description
GL_LIST_BASE Setting of glListBase()
GL_LIST_INDEX Number of display list under construction;
0 if none
GL_LIST_MODE Mode of display list under construction; undefined if none
GL_ATTRIB_STACK_DEPTH Attribute stack pointer
GL_NAME_STACK_DEPTH Name stack depth
GL_RENDER_MODE glRenderMode() setting
−− Current error code(s)
Table B−16 Mi scel l aneous State Vari abl es
Appendi x C
The OpenGL Utility Library
OpenGL provi des a powerful but smal l set of drawi ng operati ons, and al l hi gher−l evel drawi ng must be
done i n terms of these. To hel p si mpl i fy some of your programmi ng tasks, the OpenGL Uti l i ty Li brary
(GLU) i ncl udes several routi nes that encapsul ate OpenGL commands. Many of these routi nes are
descri bed i n earl i er chapters as thei r topi cs ari se; these routi nes are bri efl y l i sted here for
compl eteness. GLU routi nes that aren’t di scussed earl i er are descri bed i n more depth here.
Neverthel ess, you mi ght want to consul t the OpenGL ReferenceManual for more detai l ed descri pti ons
of al l these routi nes. Thi s appendi x groups the GLU routi nes functi onal l y as fol l ows:
• "Manipulating Images for Use in Texturing"
• "Transforming Coordinates"
• "Polygon Tessellation"
• "Rendering Spheres, Cylinders, and Disks"
• "NURBS Curves and Surfaces"
• "Describing Errors"
Manipulating Images for Use in Texturing
As you set up texture mappi ng i n your appl i cati on, you’l l probabl y want to take advantage of
292
mi pmappi ng, whi ch requi res a seri es of reduced i mages (or texture maps). To support mi pmappi ng, the
GLU i ncl udes a general routi ne that scal es i mages (gluScaleI mage()) and routi nes that generate a
compl ete set of mi pmaps gi ven an ori gi nal i mage i n one or two di mensi ons (gluBuild1DMipmaps() and
gluBuild2DMipmaps()). These routi nes are al l di scussed i n some detai l i n Chapter 9 , so here onl y
thei r prototypes are l i sted:
GLi nt gluScaleI mage(GLenum format, GLi nt widthin, GLi nt heightin, GLenum typein, const voi d *
datain, GLi nt widthout, GLi nt heightout, GLenum typeout, voi d *dataout);
GLi nt gluBuild1DMipmaps(GLenum target, GLi nt components, GLi nt width, GLenum format, GLenum
type, voi d *data);
GLi nt gluBuild2DMipmaps(GLenum target, GLi nt components, GLi nt width, GLi nt height, GLenum
format, GLenum type, voi d *data);
Transforming Coordinates
The GLU i ncl udes routi nes that create matri ces for standard perspecti ve and orthographi c vi ewi ng (
gluPerspective() and gluOrtho2D()). I n addi ti on, a vi ewi ng routi ne al l ows you to pl ace your eye at any
poi nt i n space and l ook at any other poi nt (gluLookAt()). These routi nes are di scussed i n Chapter 3 . I n
addi ti on, the GLU i ncl udes a routi ne to hel p you create a pi cki ng matri x (gluPickMatrix()); thi s routi ne
i s di scussed i n Chapter 12. For your conveni ence, the prototypes for these four routi nes are l i sted
here.
voi d gluPerspective(GLdoubl e fovy, GLdoubl e aspect, GLdoubl e zNear, GLdoubl e zFar);
voi d gluOrtho2D(GLdoubl e left, GLdoubl e right, GLdoubl e bottom, GLdoubl e top);
voi d gluLookAt(GLdoubl e eyex, GLdoubl e eyey, GLdoubl e eyez, GLdoubl e centerx, GLdoubl e centery,
GLdoubl e centerz, GLdoubl e upx, GLdoubl e upy, GLdoubl e upz);
voi d gluPickMatrix(GLdoubl e x, GLdoubl e y, GLdoubl e width, GLdoubl e height, GLi nt viewport[4]);
I n addi ti on, GLU provi des two routi nes that convert between object coordi nates and screen coordi nates,
gluProject() and gluUnProject().
GLi nt gluProject(GLdoubl e objx, GLdoubl e objy, GLdoubl e objz, const GLdoubl e modelMatrix[16],const
GLdoubl e projMatrix[16], const GLi nt viewport[4], GLdoubl e *winx, GLdoubl e *winy, GLdoubl e *winz);
Transforms the speci fi ed object coordi nates objx, objy, and objz i nto wi ndow coordi nates usi ng
modelMatrix, projMatrix, and viewport. The resul t i s stored i n winx, winy, and winz. A return val ue of
GL_TRUE i ndi cates success, and GL_FALSE i ndi cates fai l ure.
GLi nt gluUnProject(GLdoubl e winx, GLdoubl e winy, GLdoubl e winz, const GLdoubl e modelMatrix[16],
const GLdoubl e projMatrix[16], const GLi nt viewport[4], GLdoubl e *objx, GLdoubl e *objy, GLdoubl e *
objz);
Transforms the speci fi ed wi ndow coordi nates winx, winy, and winz i nto object coordi nates usi ng
modelMatrix, projMatrix, and viewport. The resul t i s stored i n objx, objy, and objz. A return val ue of
GL_TRUE i ndi cates success, and GL_FALSE i ndi cates fai l ure.
Polygon Tessellation
As di scussed i n "Describing Points, Lines, and Polygons," OpenGL can di rectl y di spl ay onl y
si mpl e convex pol ygons. A pol ygon i s si mpl e i f the edges i ntersect onl y at verti ces, there are no
dupl i cate verti ces, and exactl y two edges meet at any vertex. I f your appl i cati on requi res the di spl ay of
si mpl e nonconvex pol ygons or of si mpl e pol ygons contai ni ng hol es, those pol ygons must fi rst be
subdi vi ded i nto convex pol ygons before they can be di spl ayed. Such subdi vi si on i s cal l ed tessel l ati on.
GLU provi des a col l ecti on of routi nes that perform tessel l ati on. Note that the GLU tessel l ati on routi nes
can’t handl e nonsi mpl e pol ygons; there’s no standard OpenGL method to handl e such pol ygons.
293
Si nce tessel l ati on i s often requi red and can be rather tri cky, thi s secti on descri bes the GLU tessel l ati on
routi nes i n detai l . These routi nes take as i nput arbi trary si mpl e pol ygons that mi ght i ncl ude hol es, and
they return some combi nati on of tri angl es, tri angl e meshes, and tri angl e fans. You can i nsi st on onl y
tri angl es i f you don’t want to have to deal wi th meshes or fans. I f you care about performance, however,
you shoul d probabl y take advantage of any avai l abl e mesh or fan i nformati on.
The Callback Mechanism
To tessel l ate a pol ygon usi ng the GLU, fi rst you need to create a tessel l ati on object, and then provi de a
seri es of cal l back routi nes to be cal l ed at appropri ate ti mes duri ng the tessel l ati on. After you speci fy
the cal l backs, you descri be the pol ygon and any hol es usi ng GLU routi nes, whi ch are si mi l ar to the
OpenGL pol ygon routi nes. When the pol ygon descri pti on i s compl ete, the tessel l ati on faci l i ty i nvokes
your cal l back routi nes as necessary.
The cal l back routi nes typi cal l y save the data for the tri angl es, tri angl e meshes, and tri angl e fans i n
user−defi ned data structures, or i n OpenGL di spl ay l i sts (see Chapter 4 ). To render the pol ygons,
other code traverses the data structures or cal l s the di spl ay l i sts. Al though the cal l back routi nes coul d
cal l OpenGL commands to di spl ay them di rectl y, thi s i s usual l y not done, as tessel l ati on can be
computati onal l y expensi ve. I t’s a good i dea to save the data i f there i s any chance that you want to
di spl ay i t agai n. The GLU tessel l ati on routi nes are guaranteed never to return any new verti ces, so
i nterpol ati on of verti ces, texture coordi nates, or col ors i s never requi red.
The Tessellation Object
As a compl ex pol ygon i s bei ng descri bed and tessel l ated, i t has associ ated data, such as the verti ces,
edges, and cal l back functi ons. Al l thi s data i s ti ed to a si ngl e tessel l ati on object. To do tessel l ati on, your
program fi rst has to create a tessel l ati on object usi ng the routi ne gluNewTess().
GLUtri angul atorObj* gluNewTess(voi d);
Creates a new tessel l ati on object and returns a poi nter to i t. A nul l poi nter i s returned i f the creati on
fai l s.
I f you no l onger need a tessel l ati on object, you can del ete i t and free al l associ ated memory wi th
gluDeleteTess().
voi d gluDeleteTess(GLUtri angul atorObj *tessobj);
Del etes the speci fi ed tessel l ati on object, tessobj, and frees al l associ ated memory.
A si ngl e tessel l ati on object can be reused for al l your tessel l ati ons. Thi s object i s requi red onl y because
l i brary routi nes mi ght need to do thei r own tessel l ati ons, and they shoul d be abl e to do so wi thout
i nterferi ng wi th any tessel l ati on that your program i s doi ng. I t mi ght al so be useful to have mul ti pl e
tessel l ati on objects i f you want to use di fferent sets of cal l backs for di fferent tessel l ati ons. A typi cal
program, however, al l ocates a si ngl e tessel l ati on object and uses i t for al l i ts tessel l ati ons. There’s no
real need to free i t because i t uses a smal l amount of memory. On the other hand, i f you’re wri ti ng a
l i brary routi ne that uses the GLU tessel l ati on, you’l l want to be careful to free any tessel l ati on objects
you create.
Specifying Callbacks
You can speci fy up to fi ve cal l back functi ons for a tessel l ati on. Any functi ons that are omi tted are
si mpl y not cal l ed duri ng the tessel l ati on, and any i nformati on they mi ght have returned to your
program i s l ost. Al l are speci fi ed by the si ngl e routi ne gluTessCallback().
voi d gluTessCallback(GLUtri angul atorObj *tessobj, GLenum type, voi d (*fn)());
Associ ates the cal l back functi on fn wi th the tessel l ati on object tessobj. The type of the cal l back i s
294
determi ned by the parameter type, whi ch can be GLU_BEGI N, GLU_EDGE_FLAG, GLU_VERTEX,
GLU_END, or GLU_ERROR. The fi ve possi bl e cal l back functi ons have the fol l owi ng prototypes:
GLU_BEGI N voi d begin(GLenum type);
GLU_EDGE_FLAG
voi d edgeFlag(GLbool ean flag);
GLU_VERTEX voi d vertex(voi d *data);
GLU_END voi d end(voi d);
GLU_ERROR voi d error(GLenum errno);
To change a cal l back routi ne, si mpl y cal l gluTessCallback() wi th the new routi ne. To el i mi nate a
cal l back routi ne wi thout repl aci ng i t wi th a new one, pass gluTessCallback() a nul l poi nter for the
appropri ate functi on.
As tessel l ati on proceeds, these routi nes are cal l ed i n a manner si mi l ar to the way you woul d use the
OpenGL commands glBegin(), glEdgeFlag*(), glVertex*(), and glEnd(). (See "Marking Polygon
Boundary Edges" in Chapter 2 for more i nformati on about glEdgeFlag*().) The error cal l back i s
i nvoked duri ng the tessel l ati on onl y i f somethi ng goes wrong.
The GLU_BEGI N cal l back i s i nvoked wi th one of three possi bl e parameters: GL_TRI ANGLE_FAN,
GL_TRI ANGLE_STRI P, or GL_TRI ANGLES. After thi s routi ne i s cal l ed, and before the cal l back
associ ated wi th GLU_END i s cal l ed, some combi nati on of the GLU_EDGE_FLAG and GLU_VERTEX
cal l backs i s i nvoked. The associ ated verti ces and edge fl ags are i nterpreted exactl y as they are i n
OpenGL between glBegin(GL_TRI ANGLE_FAN), glBegin(GL_TRI ANGLE_STRI P), or glBegin
(GL_TRI ANGLES) and the matchi ng glEnd(). Si nce edge fl ags make no sense i n a tri angl e fan or
tri angl e stri p, i f there i s a cal l back associ ated wi th GLU_EDGE_FLAG, the GLU_BEGI N cal l back i s
cal l ed onl y wi th GL_TRI ANGLES. The GLU_EDGE_FLAG cal l back works exactl y anal ogousl y to the
OpenGL glEdgeFlag*() cal l .
The error cal l back i s passed a GLU error number. A character stri ng descri bi ng the error can be
obtai ned usi ng the routi ne gluErrorString(). See "Describing Errors" for more i nformati on about thi s
routi ne.
Describing the Polygon to Be Tessellated
The pol ygon to be tessel l ated, possi bl y contai ni ng hol es, i s speci fi ed usi ng the fol l owi ng four routi nes:
gluBeginPolygon(), gluTessVertex(), gluNextContour(), and gluEndPolygon(). For pol ygons wi thout hol es,
the speci fi cati on i s exactl y as i n OpenGL: start wi th gluBeginPolygon(), cal l gluTessVertex() for each
vertex i n the boundary, and end the pol ygon wi th a cal l to gluEndPolygon(). I f a pol ygon consi sts of
mul ti pl e contours, i ncl udi ng hol es and hol es wi thi n hol es, the contours are speci fi ed one after the other,
each preceded by gluNextContour(). When gluEndPolygon() i s cal l ed, i t si gnal s the end of the fi nal
contour and starts the tessel l ati on. You can omi t the cal l to gluNextContour() before the fi rst contour.
The detai l ed descri pti ons of these functi ons fol l ow.
voi d gluBeginPolygon(GLUtri angul atorObj *tessobj);
Begi ns the speci fi cati on of a pol ygon to be tessel l ated and associ ates a tessel l ati on object, tessobj, wi th
i t. The cal l back functi ons to be used are those that were bound to the tessel l ati on object usi ng the
routi ne gluTessCallback().
voi d gluTessVertex(GLUtri angul atorObj *tessobj,GLdoubl e v[3], voi d *data);
Speci fi es a vertex i n the pol ygon to be tessel l ated. Cal l thi s routi ne for each vertex i n the pol ygon to be
tessel l ated. tessobj i s the tessel l ati on object to use, v contai ns the three−di mensi onal vertex
coordi nates, and data i s an arbi trary poi nter that’s sent to the cal l back associ ated wi th GLU_VERTEX.
Typi cal l y, i t contai ns vertex data, texture coordi nates, col or i nformati on, or whatever el se the
appl i cati on may fi nd useful .
295
voi d gluNextContour(GLUtri angul atorObj *tessobj, GLenum type);
Marks the begi nni ng of the next contour when mul ti pl e contours make up the boundary of the pol ygon
to be tessel l ated. typecan be GLU_EXTERI OR, GLU_I NTERI OR, GLU_CCW, GLU_CW, or
GLU_UNKNOWN. These serve onl y as hi nts to the tessel l ati on. I f you get them ri ght, the tessel l ati on
mi ght go faster. I f you get them wrong, they’re i gnored, and the tessel ati on sti l l works. For a pol ygon
wi th hol es, one contour i s the exteri or contour and the others i nteri or. gluNextContour() can be cal l ed
i mmedi atel y after gluBeginPolygon(), but i f i t i sn’t, the fi rst contour i s assumed to be of type
GLU_EXTERI OR. GLU_CW and GLU_CCW i ndi cate cl ockwi se− and countercl ockwi se− ori ented
pol ygons. Choosi ng whi ch are cl ockwi se and whi ch are countercl ockwi se i s arbi trary i n three
di mensi ons, but i n any pl ane, there are two di fferent ori entati ons, and the GLU_CW and GLU_CCW
types shoul d be used consi stentl y. Use GLU_UNKNOWN i f you don’t have a cl ue.
voi d gluEndPolygon(GLUtri angul atorObj *tessobj);
I ndi cates the end of the pol ygon speci fi cati on and that the tessel l ati on can begi n usi ng the tessel l ati on
object tessobj.
Rendering Spheres, Cylinders, and Disks
The GLU i ncl udes a set of routi nes to draw vari ous si mpl e surfaces (spheres, cyl i nders, di sks, and
parts of di sks) i n a vari ety of styl es and ori entati ons. These routi nes are descri bed i n detai l i n the
OpenGL ReferenceManual; thei r use i s di scussed bri efl y i n the fol l owi ng paragraphs, and thei r
prototypes are al so l i sted.
To create a quadri c object, use gluNewQuadric(). (To destroy thi s object when you’re fi ni shed wi th i t,
use gluDeleteQuadric().) Then speci fy the desi red renderi ng styl e, as fol l ows, wi th the appropri ate
routi ne (unl ess you’re sati sfi ed wi th the defaul t val ues):
• Whether surface normal s shoul d be generated, and i f so, whether there shoul d be one normal per
vertex or one normal per face: gluQuadricNormals()
• Whether texture coodi nates shoul d be generated: gluQuadricTexture()
• Whi ch si de of the quadri c shoul d be consi dered the outsi de and whi ch the i nsi de:
gluQuadricOrientation()
• Whether the quadri c shoul d be drawn as a set of pol ygons, l i nes, or poi nts: gluQuadricDrawStyle()
After you’ve speci fi ed the renderi ng styl e, si mpl y i nvoke the renderi ng routi ne for the desi red type of
quadri c object: gluSphere(), gluCylinder(), gluDisk(), or gluPartialDisk(). I f an error occurs duri ng
renderi ng, the error−handl i ng routi ne you’ve speci fi ed wi th gluQuadricCallBack() i s i nvoked.
I t’s better to use the *Radius, height, and si mi l ar arguments to scal e the quadri cs rather than the
glScale*() command, so that uni t−l ength normal s that are generated don’t have to be renormal i zed. Set
the loops and stacks arguments to val ues other than 1 to force l i ghti ng cal cul ati ons at a fi ner
granul ari ty, especi al l y i f the materi al specul ari ty i s hi gh.
The prototypes are l i sted i n three categori es.
Manage quadri c objects:
GLUquadri cObj* gluNewQuadric (voi d);
voi d gluDeleteQuadric(GLUquadri cObj *state);
voi d gluQuadricCallback (GLUquadri cObj *qobj, GLenum which, voi d (*fn)());
Control the renderi ng:
voi d gluQuadricNormals (GLUquadri cObj *quadObject, GLenum normals);
voi d gluQuadricTexture(GLUquadri cObj *quadObject, GLbool ean textureCoords);
voi d gluQuadricOrientation (GLUquadri cObj *quadObject, GLenum orientation);
voi d gluQuadricDrawStyle(GLUquadri cObj *quadObject, GLenum drawStyle);
Speci fy a quadri c pri mi ti ve:
296
voi d gluCylinder (GLUquadri cObj *qobj, GLdoubl e baseRadius, GLdoubl e topRadius, GLdoubl e height,
GLi nt slices, GLi nt stacks);
voi d gluDisk (GLUquadri cObj *qobj, GLdoubl e innerRadius, GLdoubl e outerRadius, GLi nt slices, GLi nt
loops);
voi d gluPartialDisk (GLUquadri cObj *qobj, GLdoubl e innerRadius, GLdoubl e outerRadius, GLi nt slices,
GLi nt loops, GLdoubl e startAngle, GLdoubl e sweepAngle);
voi d gluSphere(GLUquadri cObj *qobj, GLdoubl e radius, GLi nt slices,GLi nt stacks);
NURBS Curves and Surfaces
NURBS routi nes provi de general and powerful descri pti ons of curves and surfaces i n two and three
di mensi ons. They’re used to represent geometry i n many computer−ai ded mechani cal desi gn systems.
The GLU NURBS routi nes can render such curves and surfaces i n a vari ety of styl es, and they can
automati cal l y handl e adapti ve subdi vi si on that tessel l ates the domai n i nto smal l er tri angl es i n regi ons
of hi gh curvature and near si l houette edges. Al l the GLU NURBS routi nes are descri bed i n Chapter 9
; thei r prototypes are l i sted here.
Manage a NURBS object:
GLUnurbsObj* gluNewNurbsRenderer (voi d);
voi d gluDeleteNurbsRenderer (GLUnurbsObj *nobj);
voi d gluNurbsCallback (GLUnurbsObj *nobj, GLenum which, voi d (*fn)());
Create a NURBS curve:
voi d gluBeginCurve(GLUnurbsObj *nobj);
voi d gluEndCurve(GLUnurbsObj *nobj);
voi d gluNurbsCurve(GLUnurbsObj *nobj, GLi nt nknots, GLfl oat *knot, GLi nt stride, GLfl oat *ctlarray,
GLi nt order, GLenum type);
Create a NURBS surface:
voi d gluBeginSurface(GLUnurbsObj *nobj);
voi d gluEndSurface(GLUnurbsObj *nobj);
voi d gluNurbsSurface(GLUnurbsObj *nobj, GLi nt uknot_count, GLfl oat *uknot, GLi nt vknot_count,
GLfl oat *vknot, GLi nt u_stride, GLi nt v_stride, GLfl oat *ctlarray, GLi nt uorder, GLi nt vorder, GLenum
type);
Defi ne a tri mmi ng regi on:
voi d gluBeginTrim (GLUnurbsObj *nobj);
voi d gluEndTrim (GLUnurbsObj *nobj);
voi d gluPwlCurve(GLUnurbsObj *nobj, GLi nt count, GLfl oat *array, GLi nt stride, GLenum type);
Control NURBS renderi ng:
voi d gluLoadSamplingMatrices (GLUnurbsObj *nobj, const GLfl oat modelMatrix[16], const GLfl oat
projMatrix[16], const GLi nt viewport[4]);
voi d gluNurbsProperty (GLUnurbsObj *nobj, GLenum property, GLfl oat value);
voi d gluGetNurbsProperty (GLUnurbsObj *nobj, GLenum property, GLfl oat *value);
Describing Errors
The GLU provi des a routi ne for obtai ni ng a descri pti ve stri ng for an error code. For i nformati on about
OpenGL’s error handl i ng faci l i ty, see "Error Handling."
const GLubyte* gluErrorString(GLenum errorCode);
Returns a poi nter to a descri pti ve stri ng that corresponds to the OpenGL, GLU, or GLX error number
passed i n errorCode. The defi ned error codes are descri bed i n the OpenGLReferenceManual al ong wi th
the command or routi ne that can generate them.
297
Appendi x D
The OpenGL Extension to the X Window System
Thi s appendi x bri efl y di scusses the routi nes defi ned as part of the OpenGL Extensi on to the X Wi ndow
System (GLX). These routi nes are di scussed i n more detai l i n the OpenGL ReferenceManual. You need
to have some knowl edge of X to ful l y understand the fol l owi ng and to use GLX successful l y. Thi s
appendi x has the fol l owi ng major secti ons:
• "Initialization"
• "Controlling Rendering"
• "GLX Prototypes"
I n the X Wi ndow System, OpenGL renderi ng i s made avai l abl e as an extensi on to X i n the formal X
sense: Connecti on and authenti cati on are accompl i shed wi th the normal X mechani sms. As wi th other
X extensi ons, there i s a defi ned network protocol for OpenGL’s renderi ng commands encapsul ated
wi thi n the X byte stream. Si nce performance i s cri ti cal i n three−di mensi onal renderi ng, the OpenGL
extensi on to X al l ows OpenGL to bypass the X server’s i nvol vement i n data encodi ng, copyi ng, and
i nterpretati on and i nstead render di rectl y to the graphi cs pi pel i ne.
Initialization
Use glXQueryExtension() and glXQueryVersion() to determi ne whether the GLX extensi on i s defi ned for
an X server, and i f so, whi ch versi on i s present. The glXChooseVisual() routi ne returns a poi nter to an
XVi sual I nfo structure descri bi ng the vi sual that best meets the cl i ent’s speci fi ed attri butes. You can
query a vi sual about i ts support of a parti cul ar OpenGL attri bute wi th glXGetConfig().
Controlling Rendering
Several GLX routi nes are provi ded for creati ng and managi ng an OpenGL renderi ng context. You can
use such a context to render off−screen i f you want. Routi nes are al so provi ded for such tasks as
synchroni zi ng executi on between the X and OpenGL streams, swappi ng front and back buffers, and
usi ng an X font.
Managing an OpenGL Rendering Context
An OpenGL renderi ng context i s created wi th glXCreateContext(). One of the arguments to thi s routi ne
al l ows you to request a di rect renderi ng context that bypasses the X server as descri bed previ ousl y.
(Note that to do di rect renderi ng, the X server connecti on must be l ocal , and the OpenGL
i mpl ementati on needs to support di rect renderi ng.) You can determi ne whether a GLX context i s di rect
wi th glXI sDirect().
To make a renderi ng context current, use glXMakeCurrent(); glXGetCurrentContext() returns the
current context. You can al so obtai n the current drawabl e wi th glXGetCurrentDrawable(). Remember
that onl y one context can be current for any thread at any one ti me. I f you have mul ti pl e contexts, you
can copy sel ected groups of OpenGL state vari abl es from one context to another wi th glXCopyContext().
When you’re fi ni shed wi th a parti cul ar context, destroy i t wi th glXDestroyContext().
Off−Screen Rendering
To render off−screen, fi rst create an X Pi xmap and then pass thi s as an argument to
glXCreateGLXPixmap(). Once renderi ng i s compl eted, you can destroy the associ ati on between the X
and GLX Pi xmaps wi th glXDestroyGLXPixmap(). (Off−screen renderi ng i sn’t guaranteed to be
supported for di rect renderers.)
298
Synchronizing Execution
To prevent X requests from executi ng unti l any outstandi ng OpenGL renderi ng i s compl eted, cal l
glXWaitGL(). Then, any previ ousl y i ssued OpenGL commands are guaranteed to be executed before
any X renderi ng cal l s made after glXWaitGL(). Al though the same resul t can be achi eved wi th
glFinish(), glXWaitGL() doesn’t requi re a round tri p to the server and thus i s more effi ci ent i n cases
where the cl i ent and server are on separate machi nes.
To prevent an OpenGL command sequence from executi ng unti l any outstandi ng X requests are
compl eted, use glXWaitX(). Thi s routi ne guarantees that previ ousl y i ssued X renderi ng cal l s are
executed before any OpenGL cal l s made after glXWaitX().
Swapping Buffers
For drawabl es that are doubl e−buffered, the front and back buffers can be exchanged by cal l i ng
glXSwapBuffers(). An i mpl i ci t glFlush() i s done as part of thi s routi ne.
Using an X Font
A shortcut for usi ng X fonts i n OpenGL i s provi ded wi th the command glXUseXFont().
GLX Prototypes
Initialization
Determi ne whether the GLX extensi on i s defi ned on the X server:
Bool glXQueryExtension (Di spl ay *dpy, i nt *errorBase, i nt *eventBase);
Bool glXQueryVersion (Di spl ay *dpy, i nt *major, i nt *minor);
Obtai n the desi red vi sual :
XVi sual I nfo* glXChooseVisual (Di spl ay *dpy, i nt screen, i nt *attribList);
i nt glXGetConfig(Di spl ay *dpy, XVi sual I nfo *vis, i nt attrib, i nt *value);
Controlling Rendering
Manage or query an OpenGL renderi ng context:
GLXContext glXCreateContext (Di spl ay *dpy, XVi sual I nfo *vis, GLXContext shareList, Bool direct);
voi d glXDestroyContext (Di spl ay *dpy, GLXContext ctx);
voi d glXCopyContext (Di spl ay *dpy, GLXContext src, GLXContext dst, GLui nt mask);
Bool glXI sDirect (Di spl ay *dpy, GLXContext ctx);
Bool glXMakeCurrent (Di spl ay *dpy, GLXDrawabl e draw, GLXContext ctx);
GLXContext glXGetCurrentContext (voi d);
GLXDrawabl e glXGetCurrentDrawable(voi d);
Perform off−screen renderi ng:
GLXPi xmap glXCreateGLXPixmap (Di spl ay *dpy, XVi sual I nfo *vis, Pi xmap pixmap);
voi d glXDestroyGLXPixmap (Di spl ay *dpy, GLXPi xmap pix);
Synchroni ze executi on:
voi d glXWaitGL (voi d);
voi d glXWaitX (voi d);
Exchange front and back buffers:
voi d glXSwapBuffers(Di spl ay *dpy, Wi ndow window);
299
Use an X font:
voi d glXUseXFont (Font font, i nt first, i nt count, i nt listBase);
Appendi x E
The OpenGL Programming Guide Auxiliary Library
Thi s appendi x descri bes the auxi l i ary l i brary that was wri tten usi ng OpenGL for thi s gui de. I t has the
fol l owi ng major secti ons:
• "Initializing and Exiting a Window"
• "Handling Window and Input Events"
• "Loading the Color Map"
• "Initializing and Drawing Three−Dimensional Objects"
• "Managing a Background Process"
• "Running the Program"
See "How to Obtain the Sample Code" for i nformati on about how to obtai n the source code for the
auxi l i ary l i brary.
Wi th the auxi l i ary l i brary, your appl i cati on structures i ts event handl i ng to use cal l back functi ons.
(Thi s method i s si mi l ar to usi ng the Xt Tool ki t, al so known as the X I ntri nsi cs, wi th a wi dget set.) For
exampl e, fi rst you open a wi ndow and regi ster cal l back routi nes for speci fi c events. Then you create a
mai n l oop wi thout an exi t. I n that l oop, i f an event occurs, i ts regi stered cal l back functi ons are
executed. Upon compl eti on of the cal l back functi ons, fl ow of control i s returned to the mai n l oop.
Initializing and Exiting a Window
Before you can open a wi ndow, you must speci fy i ts characteri sti cs: Shoul d i t be si ngl e−buffered or
doubl e−buffered? Shoul d i t store col ors as RGBA val ues or as col or i ndi ces? Where shoul d i t appear on
your di spl ay? To speci fy the answers to these questi ons, cal l auxI nitDisplayMode() and
auxI nitPosition() before you cal l auxI nitWindow() to open the wi ndow.
voi d auxI nitWindow(GLbyte *titleString);
Opens a wi ndow wi th the characteri sti cs speci fi ed by auxI nitDisplayMode() and auxI nitPosition(). The
stri ng titleString appears i n the ti tl e bar, i f your wi ndow system does that sort of thi ng. The Escape key
i s bound to an exi ti ng functi on that ki l l s the wi ndow, exi ts the program, and general l y cl eans up. Al so,
the defaul t col or for the background i s set to bl ack for an RGBA wi ndow and to col or i ndex 0 for a
col or−i ndex wi ndow.
voi d auxI nitDisplayMode(GLbi tfi el d mask);
Tel l s auxI nitWindow() whether to create an RGBA or col or−i ndex wi ndow, or a si ngl e− or
doubl e−buffered wi ndow. You can al so speci fy that the wi ndow have an associ ated depth, stenci l ,
and/or accumul ati on buffer. The mask argument i s a bi twi se ORed combi nati on of AUX_RGBA or
AUX_I NDEX, AUX_SI NGLE or AUX_DOUBLE, and any of the buffer−enabl i ng fl ags: AUX_DEPTH,
AUX_STENCI L, or AUX_ACCUM. For exampl e, for a doubl e−buffered, RGBA−mode wi ndow wi th a
depth and stenci l buffer, use AUX_DOUBLE | AUX_RGBA | AUX_DEPTH | AUX_STENCI L. The
defaul t val ue i s AUX_I NDEX | AUX_SI NGLE, or a col or−i ndex, si ngl e−buffered wi ndow.
voi d auxI nitPosition(GLi nt x, GLi nt y, GLsi zei width, GLsi zei height);
Tel l s auxI nitWindow() where to posi ti on a wi ndow on the screen. The arguments (x, y) i ndi cate the
l ocati on of the l ower l eft corner of the wi ndow, and width and height i ndi cate the wi ndow’s si ze (i n
pi xel s). The defaul t val ues are (0, 0) for (x, y) and (100, 100) for (width, height).
300
Handling Window and Input Events
After the wi ndow i s created, but before you enter the mai n l oop, you shoul d regi ster cal l back functi ons
usi ng the fol l owi ng three routi nes.
voi d auxReshapeFunc(voi d (*function)(GLsi zei , GLsi zei ));
Speci fi es the functi on that’s cal l ed whenever the wi ndow i s resi zed, moved, or exposed. The argument
function i s a poi nter to a functi on that expects two arguments, the new wi dth and hei ght of the wi ndow.
Typi cal l y, function cal l s glViewport(), so that the di spl ay i s cl i pped to the new si ze, and i t redefi nes the
projecti on matri x so that the aspect rati o of the projected i mage matches the vi ewport, avoi di ng aspect
rati o di storti on. I f you don’t cal l auxReshapeFunc(), a defaul t reshape functi on i s cal l ed, whi ch assumes
a two−di mensi onal orthographi c projecti on. Wi th thi s auxi l i ary l i brary, the wi ndow i s automati cal l y
redrawn after every reshapi ng event.
voi d auxKeyFunc(GLi nt key, voi d (*function)(voi d)) ;
Speci fi es the functi on, function, that’s cal l ed when the keyboard key i ndi cated by key i s pressed. Use
one of the defi ned auxi l i ary l i brary constants for key: AUX_A through AUX_Z, AUX_a through AUX_z,
AUX_0 through AUX_9, AUX_LEFT, AUX_RI GHT, AUX_UP, AUX_DOWN (the arrow keys),
AUX_ESCAPE, AUX_SPACE, or AUX_RETURN. Wi th thi s auxi l i ary l i brary, the wi ndow i s
automati cal l y redrawn after every processed key event, al though i n a real appl i cati on, you mi ght wai t
for several events to be compl eted before drawi ng.
voi d auxMouseFunc(GLi nt button, GLi nt mode,
voi d (*function)(AUX_EVENTREC *));
Speci fi es the functi on, function, that’s cal l ed when the mouse button i ndi cated by button enters the
mode defi ned by mode. The button argument can be AUX_LEFTBUTTON, AUX_MI DDLEBUTTON, or
AUX_RI GHTBUTTON (assumi ng a ri ght−handed setup). The modeargument i ndi cates whether the
button i s cl i cked, AUX_MOUSEDOWN, or rel eased, AUX_MOUSEUP. The function argument must
take one argument, whi ch i s a poi nter to a structure of type AUX_EVENTREC. The auxMouseFunc()
routi ne al l ocates memory for the structure. For exampl e, to determi ne the poi nter coordi nates at the
ti me of the event, you mi ght defi ne function l i ke thi s:
void function(AUX_EVENTREC *event)
{ GLint x, y;
x = event−>data[AUX_MOUSEX];
y = event−>data[AUX_MOUSEY];
...
}
Loading the Color Map
I f you’re usi ng col or−i ndex mode, you mi ght be surpri sed to di scover there’s no OpenGL routi ne to l oad
a col or i nto a col or l ookup tabl e. Thi s i s because the process of l oadi ng a col or map depends enti rel y on
the wi ndow system. The auxi l i ary l i brary provi des a general i zed routi ne to l oad a si ngl e col or i ndex
wi th an RGB val ue, auxSetOneColor(). You need to i mpl ement thi s routi ne for your parti cul ar system.
voi d auxSetOneColor(GLi nt index, GLfl oat red, GLfl oat green, GLfl oat blue);
Loads the i ndex i n the col or map, index, wi th the gi ven red, green, and blueval ues. These val ues are
normal i zed to l i e i n the range [0.0,1.0].
301
Initializing and Drawing Three−Dimensional Objects
Many sampl e programs i n thi s gui de use three−di mensi onal model s to i l l ustrate vari ous renderi ng
properti es. The fol l owi ng drawi ng routi nes are i ncl uded i n the auxi l i ary l i brary to avoi d havi ng to
reproduce the code to draw these model s i n each program. Each three−di mensi onal model comes i n two
fl avors: wi reframe wi thout surface normal s, and sol i d wi th shadi ng and surface normal s. Use the sol i d
versi on when you’re appl yi ng l i ghti ng. The argument for these routi nes al l ows you to scal e the object
that’s drawn.
voi d auxWireSphere(GLdoubl e radius);
voi d auxSolidSphere(GLdoubl e radius);
voi d auxWireCube(GLdoubl e size);
voi d auxSolidCube(GLdoubl e size);
voi d auxWireBox(GLdoubl e width, GLdoubl e height, GLdoubl e depth);
voi d auxSolidBox(GLdoubl e width, GLdoubl e height, GLdoubl e depth);
voi d auxWireTorus(GLdoubl e innerRadius, GLdoubl e outerRadius);
voi d auxSolidTorus(GLdoubl e innerRadius, GLdoubl e outerRadius);
voi d auxWireCylinder(GLdoubl e radius, GLdoubl e height);
voi d auxSolidCylinder(GLdoubl e radius, GLdoubl e height);
voi d auxWireI cosahedron(GLdoubl e radius);
voi d auxSolidI cosahedron(GLdoubl e radius);
voi d auxWireOctahedron(GLdoubl e radius);
voi d auxSolidOctahedron(GLdoubl e radius);
voi d auxWireTetrahedron(GLdoubl e radius);
voi d auxSolidTetrahedron(GLdoubl e radius);
voi d auxWireDodecahedron(GLdoubl e radius);
voi d auxSolidDodecahedron(GLdoubl e radius);
voi d auxWireCone(GLdoubl e radius, GLdoubl e height);
voi d auxSolidCone(GLdoubl e radius, GLdoubl e height);
voi d auxWireTeapot(GLdoubl e size);
voi d auxSolidTeapot(GLdoubl e size);
Draws the speci fi ed wi reframe or sol i d object. These routi nes are sel f−i ni ti al i zi ng; that i s, the fi rst ti me
a renderi ng request i s made, a di spl ay l i st i s created for the object. Every subsequent ti me the routi ne
i s cal l ed, the same di spl ay l i st i s executed. Al l these model s are drawn centered at the ori gi n. When
drawn wi th uni t scal e factors, these model s fi t i nto a box wi th al l coordi nates from −1 to 1. Use the
arguments for these routi nes to scal e the objects.
302
Managing a Background Process
You can speci fy a functi on that’s to be executed i f no other events are pendi ngfor exampl e, when the
event l oop woul d otherwi se be i dl ewi th auxI dleFunc(). Thi s routi ne takes a poi nter to the functi on as
i ts onl y argument. Pass i n zero to di sabl e the executi on of the functi on.
voi d auxI dleFunc(voi d *func);
Speci fi es the functi on, func, to be executed i f no other events are pendi ng. I f zero i s passed i n, executi on
of funci s di sabl ed.
Running the Program
The exampl es i n the book typi cal l y draw the scene each ti me the wi ndow i s created, moved, or
reshaped, or i f some i nput event occurs. Use auxMainLoop() to speci fy the routi ne that draws the scene.
voi d auxMainLoop(voi d(*displayFunc)(voi d));
Speci fi es the functi on, displayFunc, that’s cal l ed when the wi ndow needs to be updated. displayFunc
shoul d redraw the objects i n your scene.
Appendi x F
Calculating Normal Vectors
Thi s appendi x descri bes how to cal cul ate normal vectors for surfaces. You need to defi ne normal s to use
OpenGL’s l i ghti ng faci l i ty, whi ch i s descri bed i n Chapter 6, "Lighting.""Normal Vectors" i ntroduces
normal s and the OpenGL command for speci fyi ng them. Thi s appendi x goes through the detai l s of
cal cul ati ng them. I t has the fol l owi ng major secti ons:
• "Finding Normals for Analytic Surfaces"
• "Finding Normals from Polygonal Data"
Si nce normal s are perpendi cul ar to a surface, you can fi nd the normal at a parti cul ar poi nt on a surface
by fi rst fi ndi ng the fl at pl ane that just touches the surface at that poi nt. The normal i s the vector that’s
perpendi cul ar to that pl ane. On a perfect sphere, for exampl e, the normal at a poi nt on the surface i s i n
the same di recti on as the vector from the center of the sphere to that poi nt. For other types of surfaces,
there are other, better means for determi ni ng the normal s, dependi ng on how the surface i s speci fi ed.
Recal l that smooth curved surfaces are approxi mated by a l arge number of smal l fl at pol ygons. I f the
vectors perpendi cul ar to these pol ygons are used as the surface normal s i n such an approxi mati on, the
surface appears faceted, si nce the normal di recti on i s di sconti nuous across the pol ygonal boundari es. I n
many cases, however, an exact mathemati cal descri pti on exi sts for the surface, and true surface
normal s can be cal cul ated at every poi nt. Usi ng the true normal s i mproves the renderi ng consi derabl y,
as shown i n Figure F−1. Even i f you don’t have a mathemati cal descri pti on, you can do better than
the faceted l ook shown i n the fi gure. The two major secti ons i n thi s appendi x descri be how to cal cul ate
normal vectors for these two cases:
• "Finding Normals for Analytic Surfaces"expl ai ns what to do when you have a mathemati cal
descri pti on of a surface.
• "Finding Normals from Polygonal Data"covers the case when you have onl y the pol ygonal data
to descri be a surface.
303
Figure F−1 Renderi ng wi th Pol ygonal Normal s vs. True Normal s
Finding Normals for Analytic Surfaces
Anal yti c surfaces are smooth, di fferenti abl e surfaces that are descri bed by a mathemati cal equati on (or
set of equati ons). I n many cases, the easi est surfaces to fi nd normal s for are anal yti c surfaces for whi ch
you have an expl i ci t defi ni ti on i n the fol l owi ng form:
V(s,t) = [ X(s,t) Y(s,t) Z(s,t) ]
where s and t are constrai ned to be i n some domai n, and X, Y, and Z are di fferenti abl e functi ons of two
vari abl es. To cal cul ate the normal , fi nd
whi ch are vectors tangent to the surface i n the s and t di recti ons. The cross product
i s perpendi cul ar to both, and hence to the surface. The fol l owi ng shows how to cal cul ate the cross
product of two vectors. (Watch out for the degenerate cases where the cross product has zero l ength!)
304
You shoul d probabl y normal i ze the resul ti ng vector. To normal i ze a vector [x,y,z], cal cul ate i ts l ength
and di vi de each component of the vector by the l ength.
As an exampl e of these cal cul ati ons, consi der the anal yti c surface
V(s,t) = [ s2 t3 3−st ]
From thi s we have
So, for exampl e, when s=1 and t=2, the correspondi ng poi nt on the surface i s (1, 8, 1), and the vector
(−24, 2, 24) i s perpendi cul ar to the surface at that poi nt. The l ength of thi s vector i s 34, so the uni t
normal vector i s (−24/34, 2/34, 24/34) = (−0.70588, 0.058823, 0.70588).
For anal yti c surfaces that are descri bed i mpl i ci tl y, as F(x, y, z) = 0, the probl em i s harder. I n some
cases, you can sol ve for one of the vari abl es, say z = G(x, y), and put i t i n the expl i ci t form gi ven
previ ousl y:
Then conti nue as descri bed earl i er.
I f you can’t get the surface equati on i n an expl i ci t form, you mi ght be abl e to make use of the fact that
the normal vector i s gi ven by the gradi ent
eval uated at a parti cul ar poi nt (x, y, z). Cal cul ati ng the gradi ent mi ght be easy, but fi ndi ng a poi nt that
305
l i es on the surface can be di ffi cul t. As an exampl e of an i mpl i ci tl y defi ned anal yti c functi on, consi der
the equati on of a sphere of radi us 1 centered at the ori gi n:
x
2
+ y
2
+ z
2
− 1 = 0
Thi s means that
F(x, y, z) = x
2
+ y
2
+ z
2
− 1
whi ch can be sol ved for z to yi el d
Thus, normal s can be cal cul ated from the expl i ci t form
as descri bed previ ousl y.
I f you coul d not sol ve for z, you coul d have used the gradi ent
as l ong as you coul d fi nd a poi nt on the surface. I n thi s case, i t’s not so hard to fi nd a poi ntfor
exampl e, (2/3, 1/3, 2/3) l i es on the surface. Usi ng the gradi ent, the normal at thi s poi nt i s (4/3, 2/3, 4/3).
The uni t−l ength normal i s (2/3, 1/3, 2/3), whi ch i s the same as the poi nt on the surface, as expected.
Finding Normals from Polygonal Data
As menti oned previ ousl y, you often want to fi nd normal s for surfaces that are descri bed wi th pol ygonal
data such that the surfaces appear smooth rather than faceted. I n most cases, the easi est way for you to
do thi s (though i t mi ght not be the most effi ci ent way) i s to cal cul ate the normal vectors for each of the
pol ygonal facets and then to average the normal s for nei ghbori ng facets. Use the averaged normal for
the vertex that the nei ghbori ng facets have i n common. Figure F−2 shows a surface and i ts pol ygonal
approxi mati on. (Of course, i f the pol ygons represent the exact surface and aren’t merel y an
approxi mati oni f you’re drawi ng a cube or a cut di amond, for exampl edon’t do the averagi ng.
Cal cul ate the normal for each facet as descri bed i n the fol l owi ng paragraphs, and use that same normal
for each vertex of the facet.)
306
Figure F−2 Averagi ng Normal Vectors
To fi nd the normal for a fl at pol ygon, take any three verti ces v1, v2, and v3 of the pol ygon that do not
l i e i n a strai ght l i ne. The cross product
[v
1
− v
2
] × [v
2
− v
3
]
i s perpendi cul ar to the pol ygon. (Typi cal l y, you want to normal i ze the resul ti ng vector.) Then you need
to average the normal s for adjoi ni ng facets, to avoi d gi vi ng too much wei ght to one of them. For
i nstance, i n the exampl e shown i n Figure F−2, i f n
1
, n
2
, n
3
, and n
4
are the normal s for the four
pol ygons meeti ng at poi nt P, cal cul ate n
1
+n
2
+n
3
+n
4
and then normal i ze i t. The resul ti ng vector can be
used as the normal for poi nt P.
Someti mes, you need to vary thi s method for parti cul ar si tuati ons. For i nstance, at the boundary of a
307
surface (for exampl e, poi nt Q i n Figure F−2), you mi ght be abl e to choose a better normal based on
your knowl edge of what the surface shoul d l ook l i ke. Someti mes the best you can do i s to average the
pol ygon normal s on the boundary as wel l . Si mi l arl y, some model s have some smooth parts and some
sharp corners (poi nt R i s on such an edge i n Figure F−2). I n thi s case, the normal s on ei ther si de of
the crease shoul dn’t be averaged. I nstead, pol ygons on one si de of the crease shoul d be drawn wi th one
normal , and pol ygons on the other si de wi th another.
Appendi x G
Homogeneous Coordinates and Transformation Matrices
Thi s appendi x presents a bri ef di scussi on of homogeneous coordi nates. I t al so l i sts the form of the
transformati on matri ces used for rotati on, scal i ng, transl ati on, perspecti ve projecti on, and
orthographi c projecti on. These topi cs are i ntroduced and di scussed i n Chapter 3 . For a more detai l ed
di scussi on of these subjects, see al most any book on three−di mensi onal computer graphi csfor
exampl e, Computer Graphics: Principles and Practice, by Fol ey, Van Dam, Fei ner, and Hughes
(Readi ng, Mass.: Addi son−Wesl ey)or a text on projecti ve geometryfor exampl e, TheReal Projective
Plane, by H. S. M. Coxeter, 2nd ed. (Cambri dge: Cambri dge Uni versi ty Press, 1961). I n the di scussi on
that fol l ows, the term homogeneous coordi nates al ways means three−di mensi onal homogeneous
coordi nates, al though projecti ve geometri es exi st for al l di mensi ons.
Thi s appendi x has the fol l owi ng major secti ons:
• "Homogeneous Coordinates"
• "Transformation Matrices"
Homogeneous Coordinates
OpenGL commands usual l y deal wi th two− and three−di mensi onal verti ces, but i n fact al l are treated
i nternal l y as three−di mensi onal homogeneous verti ces compri si ng four coordi nates. Every col umn
vector (x, y, z, w)
T
represents a homogeneous vertex i f at l east one of i ts el ements i s nonzero. I f the real
number a i s nonzero, then (x, y, z, w)
T
and (ax, ay, az, aw)
T
represent the same homogeneous vertex.
(Thi s i s just l i ke fracti ons: x/y = (ax)/(ay).) A three−di mensi onal eucl i dean space poi nt (x, y, z)
T
becomes
the homogeneous vertex wi th coordi nates (x, y, z, 1.0)
T
, and the two−di mensi onal eucl i dean poi nt (x, y)
T
becomes (x, y, 0.0, 1.0)
T
.
As l ong as w i s nonzero, the homogeneous vertex (x, y, z, w)
T
corresponds to the three−di mensi onal
poi nt (x/ w, y/ w, z/ w)
T
. I f w = 0.0, i t corresponds to no eucl i dean poi nt, but rather to some i deal i zed
"poi nt at i nfi ni ty." To understand thi s poi nt at i nfi ni ty, consi der the poi nt (1, 2, 0, 0), and note that the
sequence of poi nts (1, 2, 0, 1), (1, 2, 0, 0.01), and (1, 2.0, 0.0, 0.0001), corresponds to the eucl i dean poi nts
(1, 2), (100, 200), and (10000, 20000). Thi s sequence represents poi nts rapi dl y movi ng toward i nfi ni ty
al ong the l i ne 2x = y. Thus, you can thi nk of (1, 2, 0, 0) as the poi nt at i nfi ni ty i n the di recti on of that
l i ne.
Note: OpenGL mi ght not handl e homogeneous cl i p coordi nates wi th w < 0 correctl y. To be sure that
your code i s portabl e to al l OpenGL systems, use onl y nonnegati ve w val ues.
Transforming Vertices
Vertex transformati ons (such as rotati ons, transl ati ons, scal i ng, and sheari ng) and projecti ons (such as
perspecti ve and orthographi c) can al l be represented by appl yi ng an appropri ate 4×4 matri x to the
coordi nates representi ng the vertex. I f v represents a homogeneous vertex, and M i s a 4×4
transformati on matri x, then Mv i s the i mage of v under the transformati on by M. (I n
computer−graphi cs appl i cati ons, the transformati ons used are usual l y nonsi ngul ari n other words,
308
the matri x M can be i nverted. Thi s i sn’t requi red, but some probl ems ari se wi th nonsi ngul ar
transformati ons.)
After transformati on, al l transformed verti ces are cl i pped so that x, y, and z are i n the range [−w, w]
(assumi ng w > 0). Note that thi s range corresponds i n eucl i dean space to [−1.0, 1.0].
Transforming Normals
Normal vectors don’t transform i n the same way as verti ces, or posi ti on vectors. Mathemati cal l y, i t’s
better to thi nk of normal vectors not as vectors, but as pl anes perpendi cul ar to those vectors. Then, the
transformati on rul es for normal vectors are descri bed by the transformati on rul es for perpendi cul ar
pl anes.
A homogeneous pl ane i s denoted by the row vector (a , b, c, d), where at l east one of a, b, c, or d i s
nonzero. I f q i s a nonzero real number, then (a, b, c, d) and (qa, qb, qc, qd) represent the same pl ane. A
poi nt (x, y, z, w)
T
i s on the pl ane (a, b, c, d) i f ax+by+cz+dw = 0. (I f w = 1, thi s i s the standard descri pti on
of a eucl i dean pl ane.) I n order for (a, b, c, d) to represent a eucl i dean pl ane, at l east one of a, b, or c must
be nonzero. I f they’re al l zero, then (0, 0, 0, d) represents the "pl ane at i nfi ni ty," whi ch contai ns al l the
"poi nts at i nfi ni ty."
I f p i s a homogeneous pl ane and v i s a homogeneous vertex, then the statement "v l i es on pl ane p" i s
wri tten mathemati cal l y as pv = 0, where pv i s normal matri x mul ti pl i cati on. I f M i s a nonsi ngul ar
vertex transformati on (that i s, a 4×4 matri x that has an i nverse M
−1
), then pv = 0 i s equi val ent to pM
−1
Mv = 0, so Mv l i es on the pl ane pM
−1
. Thus, pM
−1
i s the i mage of the pl ane under the vertex
transformati on M.
I f you l i ke to thi nk of normal vectors as vectors i nstead of as the pl anes perpendi cul ar to them, l et v and
n be vectors such that v i s perpendi cul ar to n. Then, n
T
v = 0. Thus, for an arbi trary nonsi ngul ar
transformati on M, n
T
M
−1
Mv = 0, whi ch means that nTM−1 i s the transpose of the transformed normal
vector. Thus, the transformed normal vector i s (M
−1
)
T
n. I n other words, normal vectors are
transformed by the i nverse transpose of the transformati on that transforms poi nts. Whew!
Transformation Matrices
Al though any nonsi ngul ar matri x M represents a val i d projecti ve transformati on, a few speci al
matri ces are parti cul arl y useful . These matri ces are l i sted i n the fol l owi ng paragraphs.
Translation
The cal l glTranslate*(x, y, z) generates T, where:
309
Scaling
The cal l glScale*(x, y, z) generates S, where:
Noti ce that S
−1
i s defi ned onl y i f x, y, and z are al l nonzero.
Rotation
The cal l glRotate*(a, x, y, z) generates R as fol l ows.
Let v = (x, y, z)
T
, and u = v/| | v| | = (x’, y’, z’).
Al so l et
Then
310
The R matri x i s al ways defi ned. I f x=y=z=0, then R i s the i denti ty matri x. You can obtai n the i nverse of
R, R
−1
, by substi tuti ng −a for a, or by transposi ti on.
The glRotate*() command generates a matri x for rotati on about an arbi trary axi s. Often, you’re rotati ng
about one of the coordi nate axes; the correspondi ng matri ces are as fol l ows.
As before, the i nverses are obtai ned by transposi ti on.
Perspective Projection
The cal l glFrustum(l, r, b, t, n, f ) generates R, where:
311
R i s defi ned as l ong as l not equal to r, t not equal to b, and n not equal to f.
Orthographic Projection
The cal l glOrtho*(l, r, b, t, u, f ) generates R, where:
R i s defi ned as l ong as l not equal to r, t not equal to b, and n not equal to f.
Appendi x H
Programming Tips
Thi s appendi x l i sts some ti ps and gui del i nes that you mi ght fi nd useful . Keep i n mi nd that these ti ps
are based on the i ntenti ons of the desi gners of the OpenGL, not on any experi ence wi th actual
appl i cati ons and i mpl ementati ons! Thi s appendi x has the fol l owi ng major secti ons:
• "OpenGL Correctness Tips"
• "OpenGL Performance Tips"
• "GLX Tips"
OpenGL Correctness Tips
• Do not count on the error behavi or of an OpenGL i mpl ementati oni t mi ght change i n a future
rel ease of OpenGL. For exampl e, OpenGL 1.0 i gnores matri x operati ons i nvoked between glBegin()
and glEnd() commands, but OpenGL 1.1 mi ght not. Put another way, OpenGL error semanti cs may
change between upward−compati bl e revi si ons.
• Use the projecti on matri x to col l apse al l geometry to a si ngl e pl ane. I f the model vi ew matri x i s
used, OpenGL features that operate i n eye coordi nates (such as l i ghti ng and appl i cati on−defi ned
cl i ppi ng pl anes) mi ght fai l .
• Do not make extensi ve changes to a si ngl e matri x. For exampl e, do not ani mate a rotati on by
conti nual l y cal l i ng glRotate() wi th an i ncremental angl e. Rather, use glLoadI dentity() to i ni ti al i ze
312
the gi ven matri x for each frame, then cal l glRotate() wi th the desi red compl ete angl e for that frame.
• Count on mul ti pl e passes through a renderi ng database to generate the same pi xel fragments onl y
i f thi s behavi or i s guaranteed by the i nvari ance rul es establ i shed for a compl i ant OpenGL
i mpl ementati on. (See Appendix I, "OpenGL Invariance" for detai l s on the i nvari ance rul es.)
Otherwi se, a di fferent set of fragments mi ght be generated.
• Do not expect errors to be reported whi l e a di spl ay l i st i s bei ng defi ned. The commands wi thi n a
di spl ay l i st generate errors onl y when the l i st i s executed.
• Pl ace the near frustum pl ane as far from the vi ewpoi nt as possi bl e to opti mi ze the operati on of the
depth buffer.
• Cal l glFlush() to force al l previ ous OpenGL commands to be executed. Do not count on glGet*() or
glI s*() to fl ush the renderi ng stream. Query commands fl ush as much of the stream as i s requi red to
return val i d data but don’t guarantee to compl ete al l pendi ng renderi ng commands.
• Turn di theri ng off when renderi ng predi thered i mages (for exampl e, when glCopyPixels() i s cal l ed).
• Make use of the ful l range of the accumul ati on buffer. For exampl e, i f accumul ati ng four i mages,
scal e each by one−quarter as i t’s accumul ated.
• I f exact two−di mensi onal rasteri zati on i s desi red, you must careful l y speci fy both the orthographi c
projecti on and the verti ces of pri mi ti ves that are to be rasteri zed. The orthographi c projecti on
shoul d be speci fi ed wi th i nteger coordi nates, as shown i n the fol l owi ng exampl e:
gluOrtho2D(0, width, 0, height);
where width and height are the di mensi ons of the vi ewport. Gi ven thi s projecti on matri x, pol ygon
verti ces and pi xel i mage posi ti ons shoul d be pl aced at i nteger coordi nates to rasteri ze predi ctabl y.
For exampl e, glRecti(0, 0, 1, 1) rel i abl y fi l l s the l ower l eft pi xel of the vi ewport, and glRasterPos2i(0,
0) rel i abl y posi ti ons an unzoomed i mage at the l ower l eft of the vi ewport. Poi nt verti ces, l i ne
verti ces, and bi tmap posi ti ons shoul d be pl aced at hal f−i nteger l ocati ons, however. For exampl e, a
l i ne drawn from (x1, 0.5) to (x2, 0.5) wi l l be rel i abl y rendered al ong the bottom row of pi xel s i nt the
vi ewport, and a poi nt drawn at (0.5, 0.5) wi l l rel i abl y fi l l the same pi xel as glRecti(0, 0, 1, 1).
An opti mum compromi se that al l ows al l pri mi ti ves to be speci fi ed at i nteger posi ti ons, whi l e sti l l
ensuri ng predi ctabl e rasteri zati on, i s to transl ate x and y by 0.375, as shown i n the fol l owi ng code
fragment. Such a transl ati on keeps pol ygon and pi xel i mage edges safel y away from the centers of
pi xel s, whi l e movi ng l i ne verti ces cl ose enough to the pi xel centers.
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, width, 0, height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.375, 0.375, 0.0);
/* render all primitives at integer positions */
• Avoi d usi ng negati ve w vertex coordi nates and negati ve q texture coordi nates. OpenGL mi ght not
cl i p such coordi nates correctl y and mi ght make i nterpol ati on errors when shadi ng pri mi ti ves
defi ned by such coordi nates.
OpenGL Performance Tips
• Use glColorMaterial() when onl y a si ngl e materi al property i s bei ng vari ed rapi dl y (at each vertex,
for exampl e). Use glMaterial() for i nfrequent changes, or when more than a si ngl e materi al
property i s bei ng vari ed rapi dl y.
• Use glLoadI dentity() to i ni ti al i ze a matri x, rather than l oadi ng your own copy of the i denti ty
matri x.
• Use speci fi c matri x cal l s such as glRotate*(), glTranslate*(), and glScale*(), rather than composi ng
your own rotati on, transl ati on, and scal e matri ces and cal l i ng glMultMatrix().
313
• Use glPushAttrib() and glPopAttrib() to save and restore state val ues. Use query functi ons onl y
when your appl i cati on requi res the state val ues for i ts own computati ons.
• Use di spl ay l i sts to encapsul ate potenti al l y expensi ve state changes. For exampl e, pl ace al l the
glTexI mage*() cal l s requi red to compl etel y speci fy a texture, and perhaps the associ ated
glTexParameter*(), glPixelStore*(), and glPixelTransfer*() cal l s as wel l , i nto a si ngl e di spl ay l i st.
Cal l thi s di spl ay l i st to sel ect the texture.
• Use di spl ay l i sts to encapsul ate the renderi ng cal l s of ri gi d objects that wi l l be drawn repeatedl y.
• Use eval uators even for si mpl e surface tessel l ati ons to mi ni mi ze network bandwi dth i n
cl i ent−server envi ronments.
• Provi de uni t−l ength normal s i f i t’s possi bl e to do so, and avoi d the overhead of GL_NORMALI ZE.
Avoi d usi ng glScale*() when doi ng l i ghti ng because i t al most al ways requi es that GL_NORMALI ZE
be enabl ed.
• Set glShadeModel() to GL_FLAT i f smooth shadi ng i sn’t requi red.
• Use a si ngl e glClear() cal l per frame i f possi bl e. Do not use glClear() to cl ear smal l subregi ons of the
buffers; use i t onl y for compl ete or near−compl ete cl ears.
• Use a si ngl e cal l to glBegin(GL_TRI ANGLES) to draw mul ti pl e i ndependent tri angl es, rather than
cal l i ng glBegin(GL_TRI ANGLES) mul ti pl e ti mes, or cal l i ng glBegin(GL_POLYGON). Even i f onl y a
si ngl e tri angl e i s to be drawn, use GL_TRI ANGLES rather than GL_POLYGON. Use a si ngl e cal l
to glBegin(GL_QUADS) i n the same manner, rather than cal l i ng glBegin(GL_POLYGON)
repeatedl y. Li kewi se, use a si ngl e cal l to glBegin(GL_LI NES) to draw mul ti pl e i ndependent l i ne
segments, rather than cal l i ng glBegin(GL_LI NES) mul ti pl e ti mes.
• I n general , use the vector forms of commands to pass precomputed data, and use the scal ar forms of
commands to pass val ues that are computed near cal l ti me.
• Avoi d maki ng redundant mode changes, such as setti ng the col or to the same val ue between each
vertex of a fl at−shaded pol ygon.
• Be sure to di sabl e expensi ve rasteri zati on and per−fragment operati ons when drawi ng or copyi ng
i mages. OpenGL wi l l appl y textures to pi xel i mages i f asked to!
GLX Tips
• Use glXWaitGL() rather than glFinish() to force X renderi ng commands to fol l ow GL renderi ng
commands.
• Li kewi se, use glXWaitX() rather than glXSync() to force GL renderi ng commands to fol l ow X
renderi ng commands.
• Be careful when usi ng glXChooseVisual() because bool ean sel ecti ons are matched exactl y. Si nce
some i mpl ementati ons won’t export vi sual s wi th al l combi nati ons of bool ean capabi l i ti es, you
shoul d cal l glXChooseVisual() several ti mes wi th di fferent bool ean val ues before you gi ve up. For
exampl e, i f no si ngl e−buffered vi sual wi th the requi red characteri sti cs i s avai l abl e, check for a
doubl e−buffered vi sual wi th the same capabi l i ti es. I t mi ght be avai l abl e, and i t’s easy to use.
Appendi x I
OpenGL Invariance
OpenGL i s not a pi xel −exact speci fi cati on. I t therefore doesn’t guarantee an exact match between
i mages produced by di fferent OpenGL i mpl ementati ons. However, OpenGL does speci fy exact matches,
i n some cases, for i mages produced by the same i mpl ementati on. Thi s appendi x descri bes the
i nvari ance rul es that defi ne these cases.
The obvi ous and most fundamental case i s repeatabi l i ty. A conformi ng OpenGL i mpl ementati on
generates the same resul ts each ti me a speci fi c sequence of commands i s i ssued from the same i ni ti al
condi ti ons. Al though such repeatabi l i ty i s useful for testi ng and veri fi cati on, i t’s often not useful to
appl i cati on programmers, because i t’s di ffi cul t to arrange for equi val ent i ni ti al condi ti ons. For exampl e,
renderi ng a scene twi ce, the second ti me after swappi ng the front and back buffers, doesn’t meet thi s
314
requi rement. So repeatabi l i ty can’t be used to guarantee a stabl e, doubl e−buffered i mage.
A si mpl e and useful al gori thm that counts on i nvari ant executi on i s erasi ng a l i ne by redrawi ng i t i n
the background col or. Thi s al gori thm works onl y i f rasteri zi ng the l i ne resul ts i n the same fragment x,y
pai rs bei ng generated i n both the foreground and background col or cases. OpenGL requi res that the
coordi nates of the fragments generated by rasteri zati on be i nvari ant wi th respect to framebuffer
contents, whi ch col or buffers are enabl ed for drawi ng, the val ues of matri ces other than those on the top
of the matri x stacks, the sci ssor parameters, al l wri temasks, al l cl ear val ues, the current col or, i ndex,
normal , texture coordi nates, and edge−fl ag val ues, the current raster col or, raster i ndex, and raster
texture coordi nates, and the materi al properti es. I t i s further requi red that exactl y the same fragments
be generated, i ncl udi ng the fragment col or val ues, when framebuffer contents, col or buffer enabl es,
matri ces other than those on the top of the matri x stacks, the sci ssor parameters, wri temasks, or cl ear
val ues di ffer.
OpenGL further suggests, but doesn’t requi re, that fragment generati on be i nvari ant wi th respect to
the matri x mode, the depths of the matri x stacks, the al pha test parameters (other than al pha test
enabl e), the stenci l parameters (other than stenci l enabl e), the depth test parameters (other than depth
test enabl e), the bl endi ng parameters (other than enabl e), the l ogi cal operati on (but not l ogi cal
operati on enabl e), and the pi xel −storage and pi xel −transfer parameters. Because i nvari ance wi th
respect to several enabl es i sn’t recommended, you shoul d use other parameters to di sabl e functi ons
when i nvari ant renderi ng i s requi red. For exampl e, to render i nvari antl y wi th bl endi ng enabl ed and
di sabl ed, set the bl endi ng parameters to GL_ONE and GL_ZERO to di sabl e bl endi ng, rather than
cal l i ng gl Di sabl e(GL_BLEND). Al pha testi ng, stenci l testi ng, depth testi ng, and the l ogi cal operati on
can al l be di sabl ed i n thi s manner.
Fi nal l y, OpenGL requi res that per−fragment ari thmeti c, such as bl endi ng and the depth test, be
i nvari ant to al l OpenGL state except the state that di rectl y defi nes i t. For exampl e, the onl y OpenGL
parameters that affect how the ari thmeti c of bl endi ng i s performed are the source and desti nati on
bl end parameters and the bl end enabl e parameter. Bl endi ng i s i nvari ant to al l other state changes.
Thi s i nvari ance hol ds for the sci ssor test, the al pha test, the stenci l test, the depth test, bl endi ng,
di theri ng, l ogi cal operati ons, and buffer wri temaski ng.
As a resul t of al l these i nvari ance requi rements, OpenGL can guarantee that i mages rendered i nto
di fferent col or buffers, ei ther si mul taneousl y or separatel y usi ng the same command sequence, are
pi xel i denti cal . Thi s hol ds for al l the col or buffers i n the framebuffer, or al l the col or buffers i n an
off−screen buffer, but i t i sn’t guaranteed between the framebuffer and off−screen buffers.
Appendi x J
Color Plates
Thi s appendi x contai ns the col or pl ates that appear i n the pri nted versi on of thi s gui de.
315
Figure J−1 Pl ate 1
Plate 1. The scene from the cover of thi s book, wi th the objects rendered as wi reframe model s. See
Chapter 2 .
316
Figure J−2 Pl ate 2
Plate 2. The same scene usi ng fog for depth−cuei ng (l i nes further from the eye are di mmer). See
Chapter 7 .
317
Figure J−3 Pl ate 3
Plate 3. The same scene wi th anti al i ased l i nes that smooth the jagged edges. See Chapter 7 .
318
Figure J−4 Pl ate 4
Plate 4. The scene drawn wi th fl at−shaded pol ygons (a si ngl e col or for each fi l l ed pol ygon). See
Chapter 5 .
319
Figure J−5 Pl ate 5
Plate 5. The scene rendered wi th l i ghti ng and smooth−shaded pol ygons. See Chapter 5 and Chapter
6.
320
Figure J−6 Pl ate 6
Plate 6. The scene wi th texture maps and shadows added. See Chapter 9 and Chapter 13.
321
Figure J−7 Pl ate 7
Plate 7. The scene drawn wi th one of the objects moti on−bl urred. The accumul ati on buffer i s used to
compose the sequence of i mages needed to bl ur the movi ng object. See Chapter 10.
322
Figure J−8 Pl ate 8
Plate 8. A cl ose−up shotthe scene i s rendered from a new vi ewpoi nt. See Chapter 3 .
323
Figure J−9 Pl ate 9
Plate 9. The scene drawn usi ng atmospheri c effects (fog) to si mul ate a smoke−fi l l ed room. See
Chapter 7 .
324
Figure J−10 Pl ate 10
Plate 10. Teapots drawn wi th ji ttered vi ewi ng vol umes i nto the accumul ati on buffer for a
depth−of−fi el d effect. The gol d teapot i s i n sharpest focus. See Chapter 10.
Figure J−11 Pl ate 11
Plate 11. A smooth−shaded tri angl e. The three verti ces at the corners are drawn i n red, green, and
bl ue; the rest of the tri angl e i s smoothl y shaded between these three col ors. See Chapter 5 .
325
Figure J−12 Pl ate 12a
Figure J−13 Pl ate 12b
Plate 12. The col or cube. (a) The red, green, and bl ue axes are shown; (b) The axes denote yel l ow, cyan,
and magenta. See Chapter 5 .
326
Figure J−14 Pl ate 13a
Figure J−15 Pl ate 13b
327
Figure J−16 Pl ate 13c
Figure J−17 Pl ate 13d
Plate 13. Objects drawn wi th gray materi al parameters and col ored l i ght sources. (a) Thi s scene has
pal e bl ue ambi ent l i ght and a whi te di ffuse l i ght source. (b) Thi s scene has a pal e bl ue di ffuse l i ght
source and al most no ambi ent l i ght. (c) An i nfi ni te l i ght source i s used; (d) A l ocal l i ght source i s used.
Wi th the i nfi ni te l i ght source, the hi ghl i ght (specul ar refl ecti on) i s centered on both the cone and the
328
sphere because the angl e between the object and the l i ne of si ght i s i gnored. Wi th a l ocal l i ght source,
the angl e i s taken i nto account, so the hi ghl i ghts are l ocated appropri atel y on both objects. See
Chapter 6 .
Figure J−18 Pl ate 14a
329
Figure J−19 Pl ate 14b
Plate 14. Gray teapots drawn wi th di fferent l i ghti ng condi ti ons. (a) Each of the three teapots i s drawn
wi th i ncreasi ng ambi ent l i ght. (b) The teapots are cl i pped to expose thei r i nteri ors. The top teapot uses
one−si ded l i ghti ng, the mi ddl e one uses two−si ded l i ghti ng wi th the same materi al for both front and
back faces, and the bottom teapot uses two−si ded l i ghti ng and di fferent materi al s for the front and back
faces. See Chapter 6 .
330
Figure J−20 Pl ate 15
Plate 15. A l i ghted sphere drawn usi ng col or i ndex mode. See Chapter 6 .
331
Figure J−21 Pl ate 16
Plate 16. Twel ve spheres, each wi th di fferent materi al parameters. The row properti es are as fol l ows:
row 1  No ambi ent refl ecti on; row 2  Grey ambi ent refl ecti on; row 3  Bl ue ambi ent refl ecti on. The
fi rst col umn uses a bl ue di ffuse materi al col or wi th no specul ar properti es. The second col umn adds
whi te specul ar refl ecti on wi th a l ow shi ni ness exponent. The thi rd col umn uses a hi gh shi ni ness
exponent and thus has a more concentrated hi ghl i ght. The fourth col umn uses the bl ue di ffuse col or
and, i nstead of specul ar refl ecti on, adds an emi ssi ve component. See Chapter 6 .
332
Figure J−22 Pl ate 17
Plate 17. Li ghted, smooth−shaded teapots drawn wi th di fferent materi al properti es that approxi mate
real materi al s. The fi rst col umn has materi al s that resembl e (from top to bottom) emeral d, jade,
obsi di an, pearl , ruby, and turquoi se. The second col umn resembl es brass, bronze, chrome, copper, gol d,
and si l ver. The thi rd col umn represents vari ous col ors of pl asti c: bl ack, cyan, green, red, whi te, and
yel l ow. The fourth col umn i s drawn wi th si mi l ar col ors of rubber. See Chapter 6 .
Figure J−23 Pl ate 18a
Figure J−24 Pl ate 18b
333
Figure J−25 Pl ate 18c
Plate 18. Li ghted, green teapots drawn usi ng automati c texture−coordi nate generati on and a red
contour texture map. (a) The texture contour stri pes are paral l el to the pl ane x = 0, rel ati ve to the
transformed object (that i s, usi ng GL_OBJECT_LI NEAR). As the object moves, the texture appears to
be attached to i t. (b) A di fferent pl anar equati on (x + y + z = 0) i s used, so the stri pes have a di fferent
ori entati on. (c) The texture coordi nates are cal cul ated rel ati ve to eye coordi nates and hence aren’t fi xed
to the object (GL_EYE_LI NEAR). As the object moves, i t appears to "swi m" through the texture. See
Chapter 9 .
334
Figure J−26 Pl ate 19
Plate 19. A texture−mapped Bezi er surface mesh created usi ng eval uators. See Chapter 9 and
Chapter 11.
Figure J−27 Pl ate 20
Plate 20. A si ngl e pol ygon drawn usi ng a set of mi pmapped textures. I n thi s case, each texture i s
si mpl y a di fferent col or. The pol ygon i s actual l y a rectangl e ori ented so that i t recedes i nto the di stance,
appeari ng to become progressi vel y smal l er. As the vi si bl e area of the pol ygon becomes smal l er,
correspondi ngl y smal l er mi pmaps are used. See Chapter 9 .
335
Figure J−28 Pl ate 21a
336
Figure J−29 Pl ate 21b
Plate 21. An envi ronment−mapped object. I n (a) i s the ori gi nal texture, a processed photograph of a
coffee shop i n Pal o Al to, taken wi th a very wi de−angl e l ens. (b) I s a gobl et wi th the envi ronment map
appl i ed; because of the mappi ng, the gobl et appears to refl ect the coffee shop off i ts surface. See
Chapter 9 .
337
Figure J−30 Pl ate 22a
Figure J−31 Pl ate 22b
Plate 22. A scene wi th several fl at−shaded objects. I n (a), the scene i s al i ased. I n (b), the accumul ati on
buffer i s used for scene anti al i asi ng: the scene i s rendered several ti mes, each ti me ji ttered l ess than
one pi xel , and the i mages are accumul ated and then averaged.See Chapter 10.
338
Figure J−32 Pl ate 23a
Figure J−33 Pl ate 23b
Plate 23. A magni fi cati on of the previ ous scenes. (a) The i mage shows the al i ased, jagged edges. (b)
The edges are bl urred, or anti al i ased, and hence l ess jagged. See Chapter 10.
339
Figure J−34 Pl ate 24
Plate 24. A scene drawn wi th texture mappi ng, l i ghti ng, and shadows. The pai nti ngs, fl oor, cei l i ng,
and benches are texture−mapped. Note the use of spotl i ghts and shadows. See Chapter 6 , Chapter 9
, and Chapter 13.
340
Figure J−35 Pl ate 25
Plate 25. A l i ghted, smooth−shaded model on a texture−mapped surface. See Chapter 5 , Chapter 6 ,
and Chapter 9 .
341
Figure J−36 Pl ate 26
Plate 26. A dramati cal l y l i t and shadowed scene, wi th most of the surfaces textured. The i ri s i s a
pol ygonal model . See Chapter 2 , Chapter 6 , Chapter 9 , and Chapter 13.
342
Figure J−37 Pl ate 27
Plate 27. Sophi sti cated use of texturi ng. Al l surfaces are texture−mapped. I n addi ti on, the attenuated
spotl i ght effect i s created usi ng a projected texture. See Chapter 9 and Chapter 13.
Figure J−38 Pl ate 28
Plate 28. Li t, smooth−shaded three−di mensi onal font. The font i s created by extrudi ng a
two−di mensi onal shape al ong a speci fi ed axi s. See Chapter 2 , Chapter 5 , and Chapter 6 .
Figure J−39 Pl ate 29
343
Figure J−40 Pl ate 30
Pl ates 29 and 30. Two scenes snapped from a vi sual si mul ati on program. The hi l l s are composed of just
a few pol ygons, but al l the pol ygons are texture−mapped. Si mi l arl y, the bui l di ngs are composed of onl y
a few textured rectangul ar wal l s. See Chapter 2 , Chapter 3 , and Chapter 9 .
344
Figure J−41 Pl ate 31
Plate 31. Another scene from a di fferent vi sual si mul ati on program. The hi l l s are textured, and the
scene i s rendered wi th fog. The ai rpl anes, obvi ousl y, are pol ygonal . See Chapter 2 , Chapter 3 ,
Chapter 7 , and Chapter 9 .
Glossary
aliasing
A renderi ng techni que that assi gns to pi xel s the col or of the pri mi ti ve bei ng rendered, regardl ess of
whether that pri mi ti ve covers al l of the pi xel ’s area or onl y a porti on of the pi xel ’s area. Thi s
resul ts i n jagged edges, or jaggies.
alpha
A fourth col or component. The al pha component i s never di spl ayed di rectl y. I t’s typi cal l y used to
control col or bl endi ng. By conventi on, OpenGL al pha corresponds to the noti on of opaci ty rather
than transparency, meani ng that an al pha val ue of 1.0 i mpl i es compl ete opaci ty, and an al pha
val ue of 0.0 compl ete transparency.
345
animation
Generati ng repeated renderi ngs of a scene, wi th smoothl y changi ng vi ewpoi nt and/or object
posi ti ons, qui ckl y enough that the i l l usi on of moti on i s achi eved. OpenGL ani mati on al most al ways
i s done usi ng doubl e−bufferi ng.
antialiasing
A renderi ng techni que that assi gns pi xel col ors based on the fracti on of the pi xel ’s area that’s
covered by the pri mi ti ve bei ng rendered. Anti al i ased renderi ng reduces or el i mi nates the jaggi es
that resul t from al i ased renderi ng.
application−specific clipping
Cl i ppi ng of pri mi ti ves agai nst pl anes i n eye coordi nates; the pl anes are speci fi ed by the appl i cati on
usi ng glClipPlane().
back faces
See faces.
bit
Bi nary di gi t. A state vari abl e havi ng onl y two possi bl e val ues: 0 or 1. Bi nary numbers are
constructi ons of one or more bi ts.
bitmap
A rectangul ar array of bi ts. Al so, the pri mi ti ve rendered by the glBitmap() command, whi ch uses
i ts bitmap parameter as a mask.
bitplane
A rectangul ar array of bi ts mapped one−to−one wi th pi xel s. The framebuffer i s a stack of
bi tpl anes.
blending
Reducti on of two col or components to one component, usual l y as a l i near i nterpol ati on between the
two components.
buffer
A group of bi tpl anes that store a si ngl e component (such as depth or green) or a si ngl e i ndex (such
as the col or i ndex or the stenci l i ndex). Someti mes the red, green, bl ue, and al pha buffers together
are referred to as the col or buffer, rather than the col or buffers.
C
God’s programmi ng l anguage.
client
The computer from whi ch OpenGL commands are i ssued. The computer that i ssues OpenGL
commands can be connected vi a a network to a di fferent computer that executes the commands, or
commands can be i ssued and executed on the same computer. See al so server.
client memory
The mai n memory (where program vari abl es are stored) of the cl i ent computer.
clip coordinates
The coordi nate system that fol l ows transformati on by the projecti on matri x and that precedes
perspecti ve di vi si on. Vi ew−vol ume cl i ppi ng i s done i n cl i p coordi nates, but appl i cati on−speci fi c
cl i ppi ng i s not.
clipping
El i mi nati on of the porti on of a geometri c pri mi ti ve that’s outsi de the hal f−space defi ned by a
346
cl i ppi ng pl ane. Poi nts are si mpl y rejected i f outsi de. The porti on of a l i ne or of a pol ygon that’s
outsi de the hal f−space i s el i mi nated, and addi ti onal verti ces are generated as necessary to compl ete
the pri mi ti ve wi thi n the cl i ppi ng hal f−space. Geometri c pri mi ti ves and the current raster posi ti on
(when speci fi ed) are al ways cl i pped agai nst the si x hal f−spaces defi ned by the l eft, ri ght, bottom,
top, near, and far pl anes of the vi ew vol ume. Appl i cati ons can speci fy opti onal appl i cati on−speci fi c
cl i ppi ng pl anes to be appl i ed i n eye coordi nates.
color index
A si ngl e val ue that represents a col or by name, rather than by val ue. OpenGL col or i ndi ces are
treated as conti nuous val ues (for exampl e, fl oati ng−poi nt numbers) whi l e operati ons such as
i nterpol ati on and di theri ng are performed on them. Col or i ndi ces stored i n the framebuffer are
al ways i nteger val ues, however. Fl oati ng−poi nt i ndi ces are converted to i ntegers by roundi ng to the
nearest i nteger val ue.
color−index mode
An OpenGL context i s i n col or i ndex mode i f i ts col or buffers store col or i ndi ces, rather than red,
green, bl ue, and al pha col or components.
color map
A tabl e of i ndex−to−RGB mappi ngs that’s accessed by the di spl ay hardware. Each col or i ndex i s
read from the col or buffer, converted to an RGB tri pl e by l ookup i n the col or map, and sent to the
moni tor.
components
Si ngl e, conti nuous (for exampl e, fl oati ng−poi nt) val ues that represent i ntensi ti es or quanti ti es.
Usual l y, a component val ue of zero represents the mi ni mum val ue or i ntensi ty, and a component
val ue of one represents the maxi mum val ue or i ntensi ty, though other normal i zati ons are
someti mes used. Because component val ues are i nterpreted i n a normal i zed range, they are
speci fi ed i ndependent of actual resol uti on. For exampl e, the RGB tri pl e (1, 1, 1) i s whi te, regardl ess
of whether the col or buffers store 4, 8, or 12 bi ts each.
Out−of−range components are typi cal l y cl amped to the normal i zed range, not truncated or
otherwi se i nterpreted. For exampl e, the RGB tri pl e (1.4, 1.5, 0.9) i s cl amped to (1.0, 1.0, 0.9) before
i t’s used to update the col or buffer. Red, green, bl ue, al pha, and depth are al ways treated as
components, never as i ndi ces.
concave
Nonconvex.
context
A compl ete set of OpenGL state vari abl es. Note that framebuffer contents are not part of OpenGL
state, but that the confi gurati on of the framebuffer i s.
convex
A pol ygon i s convex i f no strai ght l i ne i n the pl ane of the pol ygon i ntersects the pol ygon more than
twi ce.
convex hull
The smal l est convex regi on encl osi ng a speci fi ed group of poi nts. I n two di mensi ons, the convex
hul l i s found conceptual l y by stretchi ng a rubber band around the poi nts so that al l of the poi nts l i e
wi thi n the band.
coordinate system
I n n−di mensi onal space, a set of n l i nearl y i ndependent vectors anchored to a poi nt (cal l ed the
ori gi n). A group of coordi nates speci fi es a poi nt i n space (or a vector from the ori gi n) by i ndi cati ng
how far to travel al ong each vector to reach the poi nt (or ti p of the vector).
347
culling
The process of el i mi nati ng a front face or back face of a pol ygon so that i t i sn’t drawn.
current matrix
A matri x that transforms coordi nates i n one coordi nate system to coordi nates of another system.
There are three current matri ces i n OpenGL: the model vi ew matri x transforms object coordi nates
(coordi nates speci fi ed by the programmer) to eye coordi nates; the perspecti ve matri x transforms
eye coordi nates to cl i p coordi nates; the texture matri x transforms speci fi ed or generated texture
coordi nates as descri bed by the matri x. Each current matri x i s the top el ement on a stack of
matri ces. Each of the three stacks can be mani pul ated wi th OpenGL matri x−mani pul ati on
commands.
current raster position
A wi ndow coordi nate posi ti on that speci fi es the pl acement of an i mage pri mi ti ve when i t’s
rasteri zed. The current raster posi ti on, and other current raster parameters, are updated when
glRasterPos() i s cal l ed.
depth
General l y refers to the z wi ndow coordi nate.
depth−cuing
A renderi ng techni que that assi gns col or based on di stance from the vi ewpoi nt.
display list
A named l i st of OpenGL commands. Di spl ay l i sts are al ways stored on the server, so di spl ay l i sts
can be used to reduce network traffi c i n cl i ent−server envi ronments. The contents of a di spl ay l i st
may be preprocessed, and mi ght therefore execute more effi ci entl y than the same set of OpenGL
commands executed i n i mmedi ate mode. Such preprocessi ng i s especi al l y i mportant for computi ng
i ntensi ve commands such as glTexI mage().
dithering
A techni que for i ncreasi ng the percei ved range of col ors i n an i mage at the cost of spati al
resol uti on. Adjacent pi xel s are assi gned di fferi ng col or val ues; when vi ewed from a di stance, these
col ors seem to bl end i nto a si ngl e i ntermedi ate col or. The techni que i s si mi l ar to the hal ftoni ng
used i n bl ack−and−whi te publ i cati ons to achi eve shades of gray.
double−buffering
OpenGL contexts wi th both front and back col or buffers are doubl e−buffered. Smooth ani mati on i s
accompl i shed by renderi ng i nto onl y the back buffer (whi ch i sn’t di spl ayed), then causi ng the front
and back buffers to be swapped. See auxSwapBuffers() i n Appendix E .
element
A si ngl e component or i ndex.
evaluated
The OpenGL process of generati ng object−coordi nate verti ces and parameters from previ ousl y
speci fi ed Bézi er equati ons.
execute
An OpenGL command i s executed when i t’s cal l ed i n i mmedi ate mode or when the di spl ay l i st that
i t’s a part of i s cal l ed.
eye coordinates
The coordi nate system that fol l ows transformati on by the model vi ew matri x and that precedes
transformati on by the projecti on matri x. Li ghti ng and appl i cati on−speci fi c cl i ppi ng are done i n eye
348
coordi nates.
faces
The si des of a pol ygon. Each pol ygon has two faces: a front face and a back face. Onl y one face or
the other i s ever vi si bl e i n the wi ndow. Whether the back or front face i s vi si bl e i s effecti vel y
determi ned after the pol ygon i s projected onto the wi ndow. After thi s projecti on, i f the pol ygon’s
edges are di rected cl ockwi se, one of the faces i s vi si bl e; i f di rected countercl ockwi se, the other face
i s vi si bl e. Whether cl ockwi se corresponds to front or back (and countercl ockwi se corresponds to
back or front) i s determi ned by the OpenGL programmer.
flat−shaded
Refers to a pri mi ti ve col ored wi th a si ngl e, constant col or across i ts extent, rather than smoothl y
i nterpol ated col ors across the pri mi ti ve. See Gouraud shading.
fog
A renderi ng techni que that can be used to si mul ate atmospheri c effects such as haze, fog, and smog
by fadi ng object col ors to a background col or based on di stance from the vi ewer. Fog al so ai ds i n the
percepti on of di stance from the vi ewer, gi vi ng a depth cue.
fonts
Groups of graphi cal character representati ons usual l y used to di spl ay stri ngs of text. The
characters may be roman l etters, mathemati cal symbol s, Asi an i deograms, Egypti an hi erogl yphs,
and so on.
fragment
Fragments are generated by the rasteri zati on of pri mi ti ves. Each fragment corresponds to a si ngl e
pi xel and i ncl udes col or, depth, and someti mes texture−coordi nate val ues.
framebuffer
Al l the buffers of a gi ven wi ndow or context. Someti mes i ncl udes al l the pi xel memory of the
graphi cs hardware accel erator.
front faces
See faces.
frustum
The vi ew vol ume warped by perspecti ve di vi si on.
gamma correction
A functi on appl i ed to col ors stored i n the framebuffer to correct for the nonl i near response of the
eye (and someti mes of the moni tor) to l i near changes i n col or−i ntensi ty val ues.
geometric model
The object−coordi nate verti ces and parameters that descri be an object. Note that OpenGL doesn’t
defi ne a syntax for geometri c model s, but rather a syntax and semanti cs for the renderi ng of
geometri c model s.
geometric object
Geometri c model .
geometric primitive
A poi nt, a l i ne, or a pol ygon.
Gouraud shading
Smooth i nterpol ati on of col ors across a pol ygon or l i ne segment. Col ors are assi gned at verti ces and
l i nearl y i nterpol ated across the pri mi ti ve to produce a rel ati vel y smooth vari ati on i n col or. Al so
349
cal l ed smooth shading.
group
Each pi xel of an i mage i n cl i ent memory i s represented by a group of one, two, three, or four
el ements. Thus, i n the context of a cl i ent memory i mage, a group and a pi xel are the same thi ng.
half−spaces
A pl ane di vi des space i nto two hal f−spaces.
homogeneous coordinates
A set of n+1 coordi nates used to represent poi nts i n n−di mensi onal projecti ve space. Poi nts i n
projecti ve space can be thought of as poi nts i n eucl i dean space together wi th some poi nts at
i nfi ni ty. The coordi nates are homogeneous because a scal i ng of each of the coordi nates by the same
nonzero constant doesn’t al ter the poi nt to whi ch the coordi nates refer. Homogeneous coordi nates
are useful i n the cal cul ati ons of projecti ve geometry, and thus i n computer graphi cs, where scenes
must be projected onto a wi ndow.
image
A rectangul ar array of pi xel s, ei ther i n cl i ent memory or i n the framebuffer.
image primitive
A bi tmap or an i mage.
immediate−mode
Executi on of OpenGL commands when they’re cal l ed, rather than from a di spl ay l i st. No
i mmedi ate−mode bi t exi sts; the modei n i mmedi ate mode refers to usage of OpenGL, rather than to
a speci fi c bi t of OpenGL state.
index
A si ngl e val ue that’s i nterpreted as an absol ute val ue, rather than as a normal i zed val ue i n a
speci fi ed range (as i s a component). Col or i ndi ces are the names of col ors, whi ch are dereferenced
by the di spl ay hardware usi ng the col or map. I ndi ces are typi cal l y masked, rather than cl amped,
when out of range. For exampl e, the i ndex 0xf7 i s masked to 0x7 when wri tten to a 4−bi t buffer
(col or or stenci l ). Col or i ndi ces and stenci l i ndi ces are al ways treated as i ndi ces, never as
components.
indices
Preferred pl ural of i ndex. (The choi ce between the pl ural forms i ndi ces or i ndexesas wel l as
matri ces or matri xes and verti ces or vertexeshas engendered much debate between the authors
and pri nci pal revi ewers of thi s gui de. The authors’ compromi se sol uti on i s to use the −i ces form but
to state cl earl y for the record that the use of i ndi ce [sic], matri ce [sic], and verti ce [sic] for the
si ngul ar forms i s an abomi nati on.)
IRIS GL
Si l i con Graphi cs’ propri etary graphi cs l i brary, devel oped from 1982 through 1992. OpenGL was
desi gned wi th I RI S GL as a starti ng poi nt.
jaggies
Arti facts of al i ased renderi ng. The edges of pri mi ti ves that are rendered wi th al i asi ng are jagged
rather than smooth. A near−hori zontal al i ased l i ne, for exampl e, i s rendered as a set of hori zontal
l i nes on adjacent pi xel rows, rather than as a smooth, conti nuous l i ne.
lighting
The process of computi ng the col or of a vertex based on current l i ghts, materi al properti es, and
l i ghti ng−model modes.
350
line
A strai ght regi on of fi ni te wi dth between two verti ces. (Unl i ke mathemati cal l i nes, OpenGL l i nes
have fi ni te wi dth and l ength.) Each segment of a stri p of l i nes i s i tsel f a l i ne.
luminance
The percei ved bri ghtness of a surface. Often refers to a wei ghted average of red, green, and bl ue
col or val ues that gi ves the percei ved bri ghtness of the combi nati on.
matrices
Preferred pl ural of matri x. (See indices.)
matrix
A two−di mensi onal array of val ues. OpenGL matri ces are al l 4×4, though when they are stored i n
cl i ent memory they’re treated as 1×16 si ngl e−di mensi on arrays.
modelview matrix
The 4×4 matri x that transforms poi nts, l i nes, pol ygons, and raster posi ti ons from object coordi nates
to eye coordi nates.
monitor
The devi ce that di spl ays the i mage i n the framebuffer.
motion blurring
A techni que that si mul ates what you get on a pi ece of fi l m when you take a pi cture of a movi ng
object, or when you move the camera when you take a pi cture of a stati onary object. I n ani mati ons
wi thout moti on bl ur, movi ng objects can appear jerky.
network
A connecti on between two or more computers that al l ows each to transfer data to and from the
others.
nonconvex
A pol ygon i s nonconvex i f there exi sts a l i ne i n the pl ane of the pol ygon that i ntersects the pol ygon
more than twi ce.
normal
A three−component pl ane equati on that defi nes the angul ar ori entati on, but not posi ti on, of a
pl ane or surface.
normalized
Di vi de each of the components of a normal by the square root of the sum of thei r squares. Then, i f
the normal i s thought of as a vector from the ori gi n to the poi nt (nx’, ny’, nz’), thi s vector has uni t
l ength.
factor = sqrt(nx
2
+ ny
2
+ nz
2
)
nx’ = nx /factor
ny’ = ny /factor
nz’ = nz /factor
normal vectors
Same as normal.
NURBS
351
Non−Uni form Rati onal B−Spl i ne. A common way to speci fy parametri c curves and surfaces. See
GLU NURBS routi nes i n Appendix C .
object
An object−coordi nate model that’s rendered as a col l ecti on of pri mi ti ves.
object coordinates
Coordi nate system pri or to any OpenGL transformati on.
orthographic
Nonperspecti ve projecti on, as i n some engi neeri ng drawi ngs, wi th no foreshorteni ng.
parameters
Val ues passed as arguments to OpenGL commands. Someti mes one of the val ues passes by
reference to an OpenGL command.
perspective division
The di vi si on of x, y, and z by w, carri ed out i n cl i p coordi nates.
pixel
Pi cture el ement. The bi ts at l ocati on (x, y) of al l the bi tpl anes i n the framebuffer consti tute the
si ngl e pi xel (x, y). I n an i mage i n cl i ent memory, a pi xel i s one group of el ements. I n OpenGL
wi ndow coordi nates, each pi xel corresponds to a 1.0×1.0 screen area. The coordi nates of the l ower
l eft corner of the pi xel named x,y are (x, y), and of the upper ri ght corner are (x+1, y+1).
point
An exact l ocati on i n space, whi ch i s rendered as a fi ni te−di ameter dot.
polygon
A near−pl anar surface bounded by edges speci fi ed by verti ces. Each tri angl e of a tri angl e mesh i s a
pol ygon, as i s each quadri l ateral of a quadri l ateral mesh. The rectangl e speci fi ed by glRect*() i s
al so a pol ygon.
primitive
A poi nt, a l i ne, a pol ygon, a bi tmap, or an i mage. (Note: Not just a poi nt, a l i ne, or a pol ygon!)
projection matrix
The 4×4 matri x that transforms poi nts, l i nes, pol ygons, and raster posi ti ons from eye coordi nates to
cl i p coordi nates.
quadrilateral
A pol ygon wi th four edges.
rasterized
Converted a projected poi nt, l i ne, or pol ygon, or the pi xel s of a bi tmap or i mage, to fragments, each
correspondi ng to a pi xel i n the framebuffer. Note that al l pri mi ti ves are rasteri zed, not just poi nts,
l i nes, and pol ygons.
rectangle
A quadri l ateral whose al ternate edges are paral l el to each other i n object coordi nates. Pol ygons
speci fi ed wi th glRect*() are al ways rectangl es; other quadri l ateral s mi ght be rectangl es.
rendering
Conversi on of pri mi ti ves speci fi ed i n object coordi nates to an i mage i n the framebuffer. Renderi ng
i s the pri mary operati on of OpenGLi t’s what OpenGL does.
RGBA
352
Red, Green, Bl ue, Al pha.
RGBA mode
An OpenGL context i s i n RGBA mode i f i ts col or buffers store red, green, bl ue, and al pha col or
components, rather than col or i ndi ces.
server
The computer on whi ch OpenGL commands are executed. Thi s mi ght di ffer from the computer
from whi ch commands are i ssued. See client.
shading
The process of i nterpol ati ng col or wi thi n the i nteri or of a pol ygon, or between the verti ces of a l i ne,
duri ng rasteri zati on.
single−buffering
OpenGL contexts that don’t have back col or buffers are si ngl e−buffered. You can use these contexts
for ani mati on, but take care to avoi d vi sual l y di sturbi ng fl ashes when renderi ng.
singular matrix
A matri x that has no i nverse. Geometri cal l y, such a matri x represents a transformati on that
col l apses poi nts al ong at l east one l i ne to a si ngl e poi nt.
stipple
A one− or two−di mensi onal bi nary pattern that defeats the generati on of fragments where i ts
val ue i s zero. Li ne sti ppl es are one−di mensi onal and are appl i ed rel ati ve to the start of a l i ne.
Pol ygon sti ppl es are two−di mensi onal and are appl i ed wi th a fi xed ori entati on to the wi ndow.
tessellation
Reducti on of a porti on of an anal yti c surface to a mesh of pol ygons, or of a porti on of an anal yti c
curve to a sequence of l i nes.
texel
A texture el ement. A texel i s obtai ned from texture memory and represents the col or of the texture
to be appl i ed to a correspondi ng fragment.
textures
One− or two−di mensi onal i mages that are used to modi fy the col or of fragments produced by
rasteri zati on.
texture mapping
The process of appl yi ng an i mage (the texture) to a pri mi ti ve. Texture mappi ng i s often used to add
real i sm to a scene. As an exampl e, you coul d appl y a pi cture of a bui l di ng facade to a pol ygon
representi ng a wal l .
texture matrix
The 4×4 matri x that transforms texture coordi nates from the coordi nates that they’re speci fi ed i n to
the coordi nates that are used for i nterpol ati on and texture l ookup.
transformations
The warpi ng of spaces. I n OpenGL, transformati ons are l i mi ted to projecti ve transformati ons that
i ncl ude anythi ng that can be represented by a 4×4 matri x. Such transformati ons i ncl ude rotati ons,
transl ati ons, (nonuni form) scal i ngs al ong the coordi nate axes, perspecti ve transformati ons, and
combi nati ons of these.
triangle
A pol ygon wi th three edges. Tri angl es are al ways convex.
353
vertex
A poi nt i n three−di mensi onal space.
vertices
Preferred pl ural of vertex. See indices.
viewpoint
The ori gi n of ei ther the eye− or the cl i p−coordi nate system, dependi ng on context. (For exampl e,
when di scussi ng l i ghti ng, the vi ewpoi nt i s the ori gi n of the eye−coordi nate system. When
di scussi ng projecti on, the vi ewpoi nt i s the ori gi n of the cl i p−coordi nate system.) Wi th a typi cal
projecti on matri x, the eye−coordi nate and cl i p−coordi nate ori gi ns are at the same l ocati on.
view volume
The vol ume i n cl i p coordi nates whose coordi nates sati sfy the three condi ti ons
−w ≤ x ≤ w
−w ≤ y ≤ w
−w ≤ z ≤ w
Geometri c pri mi ti ves that extend outsi de thi s vol ume are cl i pped.
window
A subregi on of the framebuffer, usual l y rectangul ar, whose pi xel s al l have the same buffer
confi gurati on. An OpenGL context renders to a si ngl e wi ndow at a ti me.
window−aligned
When referri ng to l i ne segments or pol ygon edges, i mpl i es that these are paral l el to the wi ndow
boundari es. (I n OpenGL, the wi ndow i s rectangul ar, wi th hori zontal and verti cal edges). When
referri ng to a pol ygon pattern, i mpl i es that the pattern i s fi xed rel ati ve to the wi ndow ori gi n.
window coordinates
The coordi nate system of a wi ndow. I t’s i mportant to di sti ngui sh between the names of pi xel s,
whi ch are di screte, and the wi ndow−coordi nate system, whi ch i s conti nuous. For exampl e, the pi xel
at the l ower l eft corner of a wi ndow i s pi xel (0, 0); the wi ndow coordi nates of the center of thi s pi xel
are (0.5, 0.5, z). Note that wi ndow coordi nates i ncl ude a depth, or z, component, and that thi s
component i s conti nuous as wel l .
wireframe
A representati on of an object that contai ns l i ne segments onl y. Typi cal l y, the l i ne segments
i ndi cate pol ygon edges.
X Window System
A wi ndow system used by many of the machi nes on whi ch OpenGL i s i mpl emented. GLX i s the
name of the OpenGL extensi on to the X Wi ndow System (see Appendix D ).
354