Documente Academic
Documente Profesional
Documente Cultură
Reproduction or translation of this work beyond that permitted by Section 107 or 108 of the 1976 United States
Copyright Act without the express written permission of the copyright holder is unlawful.
admin@helios32.com
http://www.helios32.com
1
Radiosity: A Programmer’s Perspective was originally published in 1994 by John Wiley & Sons, New York, NY.
Contents
.................................
Foreword ................................................................................................................................................ i
Preface .................................................................................................................................................... iii
Introduction ..................................................................................................................................... 1
quickly become a part of our experience. Today, it is routine to find realistic, computer-generated images
on television and in the movies. Synthetic images are also routinely used in scientific and engineering
applications, such as medicine, astronomy, and mechanical engineering. Of particular interest these days is
the creation, manipulation, and display of virtual environments such as cities, campuses, buildings, and
rooms. These environments have obvious applications in architecture, but they may also be used to
Underlying all these applications is the computer technology, both software and hardware, to create
realistic pictures. In the strongest use of the term, realism may be interpreted to mean indistinguishable
form the real world. Many of us are routinely fooled into thinking a digital artifact is, in fact, a photo of a
real event or place. The goals of realistic rendering, however, go beyond mere duplication. Our perceptual
system responds to many complex visual cues, such as perspective, shading, texturing, and shadows, and
these are used to perceive attributes and relationships of objects and the environment in which they are
embedded. To the designer, these visual cues may be used to communicate space and form. This ability to
use visual metaphors to connect to our perceptual system is why there are so many applications of three-
dimensional graphics.
The majority of the computer graphics technology revolving around imagery manipulates images
directly. Images or drawing primitives are input, and images are output. Three-dimensional graphics are
quite different in that the process involves creating a computer model of the scene and running an
algorithm to produce an image from that model. To produce an interesting image, the computer model must
describe a complex environment with diverse objects. The objects must have interesting shapes and be
made from interesting materials. Also input are the position and properties of a digital camera and a set of
digital lights. The objects that comprise the computer model are not that different, in principle, from the
action of a digital camera: Virtual light is focused onto virtual film to create virtual image. Virtual light is
emitted from sources, interacts with material objects, and eventually arrives at the camera’s film plane. The
Two major techniques have been developed for modeling light on a computer, ray tracing and radiosity.
Ray tracing was the first of the two, and is well known to anyone interested in computer graphics. Ray-
tracing systems model light rays traveling from the eye to the light sources. As the rays propagate they may
be blocked by intervening occluders, or they may be reflected or refracted according to the classic laws of
optics. Radiosity is a more recent innovation. Radiosity systems model the interreflections of light from
matte or diffuse surfaces. A matte surface reflects light equally in all directions. The key advantage of a
radiosity algorithm is that multiple bounces of light can be modeled. Thus it is possible to capture very
subtle, but dramatic, illumination effects such as soft shadows and indirect light. These lighting effects are
This book is the first attempt to bring radiosity algorithms to a wide audience. It provide a lively and
accessible description of the basic ideas and techniques. But more important, the book is not merely a
collection of formulas and references, but contains C++ source code that implements a complete radiosity
system on readily available PCs. If the reader is interested in three-dimensional graphics, and likes to learn
Miscellaneous Poems
B. Cornwell, 1822
What is Radiosity?
There are two approaches to generating photorealistic images–digital pictures that are difficult to
distinguish from real photographs–in computer graphics. The first approach involves ray tracing
The use of photorealistic images in television and print advertising has left us somewhat inured to the
capabilities of ray tracing techniques. We see images that look almost, but not quite, like reality every day.
Look carefully, however, at the cover and color plates of this book. Notice the accurate rendition of diffuse
reflections and color bleeding between surfaces, realistic penumbrae along shadow boundaries and detailed
shading within shadows. These subtle but important visual effects, so difficult to achieve with conventional
Radiosity offers more than mere realism, however. Imagine creating a virtual reality stroll through the
lobby, halls and rooms of an international-class hotel. The building exists only as a set of architectural
CAD drawings. What you want is an animated sequence of images, a video where every frame is as richly
detailed as the images shown in this book. If you use ray tracing techniques, each frame has to be traced
pixel by pixel. Ray tracing techniques are view-dependent; the number of ray-surface intersection
calculations can increase geometrically with the complexity of the scene. In contrast, the radiosity approach
is view-independent. Most of the lighting calculations are performed only once for a given environment.
Once they have been completed, it is a relatively simple task to render a view of the environment as seen
from any camera position. The effort required to generate a sequence of images can be considerably less
This is not a theoretical example that requires some future supercomputer. The cover of this book is
courtesy of the architectural firm of Hellmuth, Obata and Kassabaum, Inc. They are using radiosity-based
iv Preface
_____________________________________________________________________
rendering software that runs on desktop graphics workstations to create promotional stills and videos for
Few of us are rich or fortunate enough to have a thirty-thousand dollar graphics workstation sitting on
our desk. For now at least, we will have to let the professionals create their photorealistic and richly
detailed videos. We can, however, create high resolution color images using nothing more expensive than
What sort of images? The color plates in this book imply that the radiosity approach is useful primarily
as an architectural design and illustration tool. This emphasis reflects the original development of radiosity
as a computer graphics tool. Architectural interiors provided convenient and impressive demonstrations of
radiosity’s strengths. Since then, the radiosity approach has been applied to entertainment productions,
virtual reality systems, diagnostic medicine, scientific research and engineering studies. Research into the
Radiosity is in a sense the complement of ray tracing. Ray tracing techniques excel in the rendition of
point light sources, specular reflections and refraction effects. Radiosity methods accurately model area
light sources, diffuse reflections, color bleeding effects and realistic shadows. It follows that the best use of
radiosity may lie in a combination of radiosity methods and ray tracing techniques. Fortunately, most
scenes of everyday interest include few specular surfaces and transparent objects. We can potentially use
radiosity methods to visualize a scene, followed where necessary by a ray tracing pass to more accurately
render the specular highlights and refraction effects. The number of rays that must be traced is far fewer
than if the scene was visualized using ray tracing techniques alone.
Looking to the future, virtual reality systems will be expected to offer photorealistic images at real-time
display rates. The radiosity approach allows us to create such images using “progressive refinement”
techniques, where each image initially appears as an approximate rendering of the scene. The radiosity
algorithm is then iterated to progressively “refine” the image. The longer we focus our attention on a scene,
the closer it will approach reality. We will be able to combine this ability with motion compensation and
Preface v
_____________________________________________________________________
other video data compression techniques to create seemingly smooth zoom and pan sequences through our
virtual worlds.
Critics have argued that radiosity methods require inordinate amounts of memory and processing
power. Their complaints were justified when the first of these methods was proposed a decade ago. Times
have changed, however, and will continue to do so. We have affordable personal computers with memory,
processing power and video display capabilities undreamt of a decade ago sitting on our desktops. We also
have practical radiosity methods that can be easily implemented on these computers. Radiosity is no longer
the domain of academic researchers with their multiprocessor workstations and dedicated hardware
graphics accelerators. We can experiment and work with radiosity today using off-the-shelf personal
computers.
A Few Limitations
The radiosity approach has several limitations when compared to ray tracing techniques. To begin with,
radiosity theory is based on the assumption that all surfaces are ideal diffuse reflectors. Accurately
modeling specular surfaces and transparent materials requires a combination of radiosity methods and ray
tracing techniques. These combinations–extended radiosity methods–offer the best features of radiosity and
Another limitation involves the representation of surfaces. Whereas ray tracing techniques can use
implicit equations to define curved surfaces, most radiosity methods require all surfaces–curved and flat–to
be modeled as typically nonuniform polygon meshes. This is not a fundamental limitation, since any flat or
curved surface can be approximated by a polygon mesh. Nevertheless, a complex curved surface defined as
a mesh usually requires a fair amount of memory. The same surface represented by an implicit equation
(e.g., a Bézier or quadric surface) requires memory for only a few parameters.
A more serious limitation is that these polygon meshes must be carefully chosen to avoid aliasing
artifacts in the rendered images. Choosing an appropriate mesh for each surface is a non-trivial problem
that depends on the geometrical relationship between surfaces, the placement of light sources and surface
reflectance properties. Fortunately, the meshing process can be automated to some extent using “adaptive
subdivision” techniques.
vi Preface
_____________________________________________________________________
On the positive side, there is a popular misconception that radiosity approach requires a closed
environment, where every ray of light must eventually intersect at least one surface. In fact, it is just that–a
misconception. Radiosity can model any environment that ray tracing can.
Given these limitations, the radiosity approach is clearly not a panacea for generating photorealistic
images of arbitrary scenes. As a rule of thumb, it is best suited for those applications where the majority of
objects have surfaces that are flat, opaque and diffusely reflective. Many architectural scenes fall nicely
into this category, which explains why most artistic examples of radiosity feature office interiors and the
like. Scenes featuring mostly curved objects with specular or semi-specular surfaces and transparent
materials such as glass are more appropriately rendered using ray tracing techniques.
This is not to say that radiosity approach should be considered only for architectural design and
illustration. More esoteric applications include thermal engineering analysis, solar atmospheric studies,
computer-aided tomography and virtual reality simulations. After ten years of research, we are just
beginning to see radiosity methods applied to real-world problems. It will be interesting to see where future
Radiosity is very much a computer graphics tool. Consequently, this book examines the gamut of
radiosity methods in depth, beginning with the basics of radiosity theory and ending somewhere in the
frontiers of current research. The algorithms are rigorously and clearly explained, implementation details
are examined at length, and C++ source code is presented for a complete radiosity-based renderer–
HELIOS–that runs under Microsoft Windows 3.1 and Windows NT. Moreover, most of the code is
platform-independent and designed for 32-bit environments, which means that it can be ported to other
development and target platforms with minimal effort. In short, this book is itself a programmer’s tool for
exploring radiosity.
Many advanced computer graphics techniques rely heavily on sophisticated mathematics; this is not
true for radiosity. Understanding radiosity requires no more than a basic knowledge of vectors and
matrices, plus an ability to visualize in three dimensions. Please do not let the brief excursions into higher
mathematics deter you. If you remember your high-school algebra, you have all the mathematical tools you
Preface vii
_____________________________________________________________________
need. The occasional text box provides a brief explanation of possibly unfamiliar mathematical notation
and concepts. At worst, the mathematics can be skipped altogether with minimal loss of continuity.
This book is aimed at computer science undergraduates and computer enthusiasts of all ages. There are
no classroom exercises to spoil the fun–we all learn best by doing. The radiosity renderer presented in this
book offers endless opportunities. Take it apart, see how it works, and rebuild it ... add features,
experiment with different algorithms and profile their performance. Learn from your experiences and
discoveries, and above all else enjoy what you are doing. Remember: radiosity is easy to understand and
In terms of today’s personal desktop computer technology, what you need to compile and run HELIOS
• an IBM PC-AT clone with a ‘386 CPU and 4 megabytes of RAM and a ‘387 floating point
• minimum 256-color display adapter and color monitor (65,536 or 16.7 million [24-bit] colors
recommended)
These are minimum requirements. An IBM PC-AT clone with a 66 MHz ‘486-DX2 CPU rendered the
photorealistic image shown in Color Plate 1 in 40 seconds. A computer with a 16 MHz ‘386-SX CPU will
HELIOS uses Microsoft’s BMP graphics file format to both display and store 24-bit color images. It
can also generate color dithered images suitable for 16-bit (65,356 color) and 15-bit (32,768 color)
displays. However, it does not directly support 256-color displays. The images it does display on
Nevertheless, a computer with a 256-color display adapter can be used. The accompanying diskette
includes a standalone utility (with fully documented C++ source code) for generating 8-bit (256 color)
BMP files from the 24-bit BMP files that HELIOS produces. (It would take very little work to add this
viii Preface
_____________________________________________________________________
capability to HELIOS itself. However, both programs require a fair amount of memory. On a machine with
4 megabytes of memory, it is probably better to run each program separately to avoid those dreaded “out of
This book is about radiosity and the implementation of radiosity methods in C++. It is not about
programming in or for any particular environment. There are some 7,000 lines of draft ANSI C++ source
code, of which only 1,700-odd lines are devoted to the graphical user interface provided by MS-Windows.
The remainder is devoted to the underlying computer graphics software needed to implement the radiosity
renderer.
The MS-Windows interface is written in ANSI C, and compiles without modification under either
Microsoft Visual C++ Version 1.5 or Borland C++ Version 4.0. No use whatsoever is made of any
compiler-specific functions or class libraries other than those required for generic MS-Windows programs.
More importantly, the interface code is completely encapsulated in its own set of classes.
Are you programming for another environment? HELIOS also compiles as a Microsoft Win32s or
Windows NT program without modification. You only need to specify a global #define to create a 32-bit
executable. As such, the platform-independent C++ radiosity code should properly compile under any C++
A radiosity algorithm can be written in about a dozen lines of pseudocode. A functional radiosity-based
rendering program, on the other hand, requires much more. In particular, it requires the support of a
complete 3-D viewing system. While the algorithms have been published before, few computer graphics
programming texts have attempted to address the complexities of writing the necessary code. The effort
needed to develop a ray tracing program pales in comparison. Neverthless, it is all here.
Regardless of the subject, a programmer’s perspective must consider more than implementing
pseudocode in C++. While the basics of radiosity can be explained in five hundred words or less–see the
introduction–we need to understand its underlying and fundamental principles. We will see that these
how do we measure it? We will examine the parallel sciences of radiometry and photometry in detail, with
a brief excursion into radiometric field theory. The concepts are simple but extremely important to what
follows.
Chapter Two, Radiosity Theory explains radiosity in terms of the geometrical nature of light, using a
minimum of mathematics. Mathematical proofs of key concepts are provided as optional reading.
Most radiosity methods expect only one type of graphic primitive: three-dimensional polygons. Chapter
Three, Building An Environment presents the basic algorithms needed to represent them. These algorithms
are not part of the radiosity approach per se. Neverthess, they are needed to describe complex 3-D scenes
and to view them afterwards. Fortunately, they are simple to understand and straightforward to implement.
We will also need many of the basic algorithms used in 3-D computer-aided drafting programs. Chapter
Four, A Viewing System reviews synthetic cameras, windowing and clipping, hidden surface elimination,
scan conversion and incremental shading techniques. From these, it builds a complete 3-D viewing system
for MS-Windows 3.1 and Windows NT. With it, we will be able to view wireframe images, shaded 3-D
Form factors are the heart and soul of radiosity theory. Imagine two polygons floating in space. If one
polygon is emitting light, how much of it will be intercepted by the other one? This is a simple question
with no easy answer. Believe it or not, it took mathematicians over 230 years to find a equation that solves
for the general case of two arbitrarily-oriented polygons! Fortunately, there are much simpler solutions for
our needs. Chapter Five, Form Factor Determination looks at a number of efficient calculation methods,
Chapter Six, Solving the Radiosity Equation details several radiosity algorithms and associated
techniques that have been developed over the past ten years. The first method, full radiosity, was an
academic curiosity derived from radiant heat transfer theory. The subsequent improvements and
modifications represent a fascinating tour de force of mathematical insight and programming ingenuity.
Aliasing is an ever-present problem for the radiosity approach. Surfaces are described as polygon
meshes. If the mesh is too coarse, the mesh outline will be visible in the rendered surface. If the mesh is too
x Preface
_____________________________________________________________________
fine, the radiosity methods must perform unnecessary calculations. Chapter Seven, Meshing Strategies
examines the issues involved and explores substructuring techniques that attempt to create optimal meshes
for surfaces.
Finally, Chapter Eight looks to the future of both HELIOS and the radiosity approach in general. It
proposes a number of enhancements that you might consider as programming projects, and concludes with
Acknowledgments
My debts of gratitude extend in several directions. First, I am indebted to the many computer graphics
researchers who found radiosity as fascinating a topic as I have. More to the point, it is their investigative
work that has provided the foundations for this book. There are too many names to acknowledge here; I
Second, I am indebted to a number of researchers in other fields. There are many interwoven threads
leading to the development of radiosity, including geometrical optics, astronomy, photometry and
radiometry, radiant heat and illumination engineering, field theory and nuclear physics. They include
forgotten and neglected names such as Fock, Yamauti, Gershun and Moon, whose pioneering work in
photometric and radiometric theory was fifty to one hundred years before its time. Their efforts are
Third, I owe personal debts to a number of people. They include Peter Murphy of Ledalite
Architectural Products for financial support and an unending interest in the impossible, Domina Eberle
Spencer for inspiration, David DiLaura at the University of Colorado for providing an unattainable goal
and sharing his love of higher mathematics, and Peter Ngai of Peerless Lighting for ten years of unwitting
incentive. I also thank Peter Franck of Ledalite Architectural Products for his careful review of the draft
manuscript and Eric Haines of 3D/Eye for his insightful comments and for sharing his radiosity
bibliography.
The radiosity research community is small and friendly. I am extremely grateful to Stuart Feldman,
Filippo Tampieri and Rod Recker of Lightscape Graphics Software and David Munson of Hellmuth, Obata
and Kassabaum, Inc. for providing their exquisite color images. Thanks are also due to Holly Rushmeier,
Preface xi
_____________________________________________________________________
Michael Cohen, Pat Hanrahan, Richard Mistrick, Greg Ward, Mark Pavicic, Nelson Max, John Wallace,
Alain Fournier, Pierre Poulin and numerous others for their collective assistance and many small but
important contributions.
Writing a program as complicated as a radiosity renderer from scratch is not for the faint of heart. Aside
from the mathematics and technical issues involved, it requires a great deal of careful thought, detailed
planning and discipline. For this, I thank my friends at Glenayre Electronics and Josef Roehrl of
Stonehenge Technologies, who collectively spent four years teaching me the difference between
programming and software engineering. One million-plus lines of C and 680x0 assembly code for
electronic voice mail and radio telecommunications–now there is a program to be proud of!
Finally, I thank the following for their encouragement and moral support: my wife Janet, my parents
Frank and Marjorie Ashdown, and last but not least, Annie Ballyk for endlessly repeating her favorite
Never underestimate the power of a grandmother’s words. Yes, Annie, I finally have!
This year marks the tenth anniversary of radiosity as recognized by the computer graphics community.
It began more or less as a mathematical curiosity that could laboriously render the interior of an empty box
(Goral et al. [1984]). Today, radiosity is entering the marketplace as a powerful computer graphics tool for
Despite this inherent power, radiosity has remained almost exclusively a university research topic. Each
passing year has seen the publication of more effective and ingenious radiosity-based algorithms.
Nevertheless, the number of radiosity-based rendering programs available to individual computer graphics
enthusiasts has remained almost insignificant. As of 1994, there are apparently only two public domain
packages for UNIX-based machines, both available on the Internet from their authors. (There are also
several implementations of Radiance, a superlative public domain ray tracing program with radiosity-
related effects.) None of these programs, however, explore the radiosity approach in depth.
Why is this? There is certainly no shortage of public domain ray tracing programs. DKBTrace (e.g.,
Lindley [1992]) and its successor, Persistence of Vision (Wells and Young [1993]) are two well-known
examples that can produce outstanding ray-traced imagery. These are complex programs with many
options and capabilities. The effort put into their development likely exceeds that needed to develop a fully
functional radiosity-based rendering program by an order of magnitude. If this is so, why are there no
Perhaps the answer can be found in this quote from Shenchang Eric Chen of Apple Computer, Inc.
(Chen [1991]):
While a naive ray tracer can be implemented fairly easily and compactly (as in the case of Paul
Heckbert, who has a ray tracer printed on his business card), implementing a radiosity program is
generally regarded as an enormous task. This is evident in that there still is no public domain radiosity
code available …
This sounds reasonable; public domain programs usually begin as small weekend programming projects
that quietly grow into major undertakings. The critical factor is that first tentative release. If it has any
2 Introduction
________________________________________________________________________
merit whatsoever, a cadre of loyal users will prompt the author to fix one more bug and add another
handful of features. The project soon becomes a group effort that continues to grow until it rivals its
commercial counterparts.
A radiosity-based renderer, on the other hand, is not something you do in a weekend. It is a major
undertaking requiring many long and tedious hours of planning, design, development and testing. Worse,
there are no intermediate stages of development. The first synthesized image appears only when the entire
This is saddening. The widespread availability of affordable ray tracing programs has brought us many
captivating images by talented artists, both amateur and professional. They have also captured the
imagination of many young students, encouraging them to pursue their interests in computer graphics and
related fields of enquiry. A capable radiosity-based rendering program could only encourage this pool of
talented individuals.
complete with over 7,000 lines of C++ source code and 500 pages of documentation (this book).
HELIOS is both a celebration and a challenge. The celebration is two-fold: radiosity’s anniversary and
HELIOS’s own marriage of radiosity with Microsoft Windows 3.1 and Windows NT. The challenge …
Shenchang Chen got it right–developing HELIOS was indeed “an enormous task.” As such, it deserves
more than a few pages of hastily prepared user documentation. It needs every page of the book you are
now holding to properly describe its underlying algorithms and design philosophy.
This book was written concurrently with the program’s development. Each paragraph bears with it the
immediate (and often frustrating) experience of having implemented the algorithms being discussed. The
The challenge in writing the program was to ensure that the code remained as generic as possible. True,
HELIOS has been implemented as an MS-Windows program. However, very little of the code is specific to
MS-Windows. This comes from the first draft specification for the program’s design:
Introduction 3
________________________________________________________________________
[The program] shall be implemented such that the display device and environment dependencies are
minimized. Wherever possible, these dependencies shall be encapsulated in clearly defined and well-
Most of the code in this book is written in draft ANSI C++. More importantly, it was expressly
designed for ease of porting to other computer environments. It compiles without any errors or warnings
for both 16-bit (Windows 3.1) and 32-bit (Windows NT and Win32s) target environments. The goal was to
develop a radiosity renderer that could be implemented on any platform that supports bitmap graphics
The real challenge is to you. This book provides an abundance of radiosity algorithms and
implementations. Some features are discussed but not implemented. Others are implemented but not
incorporated in HELIOS. They range from small but significant performance enhancements to major
software development projects. While HELIOS is a fully functional program, it lacks some of the bells and
whistles we normally associate with a commercial product. Thes are opportunities; you can enhance
Think of an empty and darkened room. It has a fluorescent light fixture mounted on the ceiling and a
table sitting on the floor underneath it. The light fixture is turned off. There are no windows, open doors or
We all know what happens next. Light flows from the light fixture, filling every corner of the room at
the speed of … well, light. It directly illuminates the walls, floor and table top. The sides of the table are in
shadow, and the ceiling is not directly illuminated. Depending on the surface reflectances, some of the light
will be reflected back into the room; the rest will be absorbed. The reflected light will “bounce” from
surface to surface until it is completely absorbed. In the process, it indirectly illuminates the entire room,
Within this simple model is the realm of our visual experience. Of this light, an almost infinitesimal
portion will find its way to our eye’s retina. Converted into electrochemical signals, it provides visual
images to our brain: we perceive the room in all its visual complexity.
Note the term “perceive”. This is an important but often neglected point. We visually see light that
impinges on our retina; electrochemical reactions generate nerve impulses that travel along the optic nerves
to the visual cortex in our brain. From this, we consciously perceive the information that it conveys.
If you think about it for a moment, we are surrounded by a three-dimensional field of light that we can
never directly perceive. A flashlight beam is invisible until it is reflected by a surface, shines through
translucent glass, or passes through smoke or airborne dust. We can only experience those material objects
that direct light towards our eye; the light itself is an invisible agent in this process.
We commonly think in terms of rays of light that are emitted by a light source. Each ray follows a
straight line through space, possibly bouncing from surface to surface, until it is either completely absorbed
or enters our eye (Fig. I.2). Those rays we see are focused by the cornea onto the retina; together, they
From this, it should be evident that we can look at a photograph and perceive the objects it portrays. If
each ray of light reflected from the photograph towards our eye exactly mimics those rays we see from the
original scene, then we should not be able to tell the difference between the photograph and the original
objects.
Of course, nature is rarely so kind. Our binocular vision immediately tells us that the photograph is a
two-dimensional surface with no perceptual depth. The relative positions of the objects in the photograph
remain unchanged as we move our heads. These and a thousand other visual cues tell us that a photograph
Nevertheless, we appreciate these images and value them for both their aesthetic and informational
content. They take us to places where we cannot go, remind us of past events and convey images of reality
we cannot see or otherwise imagine. More recently, they have shown us images of virtual realities–
photorealistic renditions of imaginary worlds that exist only as bits of information in the memory of our
computers.
We value these images most when they portray the world as we think it should be. A view of an
architectural interior should exhibit all the characteristics of the real world. Specular reflections from glass
and polished wood, diffuse reflections from matte finishes, fine details and textures in every object and
realistic shadows are but a few of these. Capturing these nuances is a considerable challenge to the
computer scientist and artist alike. While much progress has been made since the first crude line drawings
6 Introduction
________________________________________________________________________
were displayed on the cathode ray tube screen of MIT’s WhirlWind I computer in 1950 (Newmann and
Sproull [1979]), the current state of the art reveals that we still have far to go.
In the meantime, we have the knowledge and computing power to synthesize photorealistic images
using nothing more than our artistic sense and a personal desktop computer. We might say that these
images allow us to capture reality. It will take several hundred pages of higher mathematics and some
rather convoluted source code to explain how, but the results will be rewarding and extremely satisfying.
The first attempts to capture reality in the form of photorealistic images relied on the basic principles of
geometric optics. Using Figure I.1 as an example, each ray of light emitted by the light source was
faithfully followed as it traversed the room (Whitted [1980]). At each point where it intersects a surface,
the physical properties of that surface determine how much of the ray is absorbed and the direction and
color of the remainder. A black surface will obviously reflect much less light than a white one. Similarly, a
red surface will reflect mostly red light, even though the color of the light source may have been white. A
transparent object behaves in the same manner, except that the remaining light is transmitted through its
The problem with this approach is that it is shockingly inefficient. Most of the rays will be fully
absorbed before they ever reach our eye. Why follow them if they cannot be seen? This leads to the
concept of backwards ray tracing. Knowing how a ray is reflected or transmitted by each object it
encounters on its path from the light source to our eye, we can trace it backwards through space and time
from our eye (Fig. I.3). We then have to consider only those rays that we can actually see.
Introduction 7
________________________________________________________________________
Unfortunately, this leads to a second problem. Figures I.2 and I.3 show a single ray being reflected
from the surface, but this is a gross simplification. Physical surface finishes vary from microscopically
smooth to roughly textured. A smooth and polished surface acts much like a mirror–it is a specular
reflector of light. A single ray of light incident on the surface will be reflected as a single ray. This is a
trivial event for a ray tracing program, since the angle of reflection can be calculated very easily.
More often, however, physical surfaces will act as semi-specular and diffuse reflectors (Fig. I.4). Here,
an incident ray is reflected as an infinite number of rays. The intensity of each reflected ray will vary,
depending on the angle of the incident ray, the angle of the reflected ray and the surface reflectance
properties. This makes ray tracing somewhat more difficult, to say the least.
The overall effect of light being repeatedly reflected from semi-specular and diffuse surfaces is to fill
the room with rays going in every direction. This fill light, to use the artist’s term for it, provides the soft
shadows and subtle shadings we associate with realistic images. Without it, most shadows are black and
featureless.
8 Introduction
________________________________________________________________________
It becomes computationally infeasible to trace any significant number of these diffusely-reflected rays
for complex scenes (or environments) involving hundreds or thousands of non-specular surfaces. This
highlights an important limitation of ray tracing techniques: they have difficulty in accurately modeling
Most ray tracing programs do not attempt to model these reflections directly. Instead, numerous
techniques have been developed to simulate their contribution to indirect illumination. One popular
approach is to simply assume that all surfaces are evenly illuminated by a completely diffuse but hidden
light source. This ambient lighting term has no physical basis; it simply attempts to make the objects in the
Other, more sophisticated ray tracing algorithms can be used to simulate soft shadows and diffuse
reflections. Again, however, they are often ad hoc techniques without a firm physical basis. The results are
not always satisfactory–many ray traced images exhibit the characteristic signature of plastic-looking
This is not to disparage ray tracing techniques. Computer graphics practitioners have been extremely
successful in using these techniques to create an astounding assortment of images. What we need to
recognize is that they have their limitations, and to consider the possible alternatives where necessary.
These are our radiosity methods, a fundamentally different approach to photorealistic image synthesis.
Figure I.5 shows our empty room again, but with three significant refinements: 1) all surfaces are
assumed to be ideal diffuse and opaque reflectors; 2) the light source is an ideal diffuse emitter of light, and
The assumption that all surfaces are ideal diffuse (or Lambertian) reflectors is important. These
reflectors have a unique and very interesting property: they reflect light equally in all directions, regardless
of the angle of the incident ray or rays of light illuminating the surface.
Look at the paper this page is printed on–it is a reasonable approximation of an ideal diffuse reflector.
Try holding it under an incandescent desk lamp and tilting the book back and forth. If you keep it at a
constant distance from the lamp, the visual “brightness” of the paper will not change significantly. A spot
light meter will tell you the same thing; the amount of light reflected in any direction is independent of the
This will prove extremely useful to us. The total quantity of light reflected from a Lambertian surface is
equal to the quantity of the incident light times the surface reflectance. Period. A grey Lambertian surface
with a surface reflectance of 20 percent reflects precisely 20 percent of any incident light, and distributes it
An ideal diffuse emitter is identical to a Lambertian reflector, except that it emits light equally in all
directions. Some fluorescent light fixtures are reasonable approximations of ideal diffuse emitters. Most
light sources, however, are not. Neverthless, it is a useful concept that will help us understand the radiosity
approach.
So what does this give us? Well, consider that it is very easy to calculate how much light is emitted in
any given direction by a Lambertian emitter or reflector. (The details are presented in Chapter One.) If we
know the geometry of the room and the constituent elements of its surfaces, we can determine how much
light each element receives from the light source. Note that we do not have to trace individual rays, since
10 Introduction
________________________________________________________________________
all the information we need is contained in the room and element geometry. (See Chapter Five for a
detailed exposition.) Most of the elements will receive some light. A few, however, will be hidden from
view (as seen from the light source) by other elements, and so they receive no direct illumination.
So far, so good. Now, each of these elements will absorb some of the light it receives and reflect the
remainder back into the room. If we know the reflectance of each surface, we can calculate the precise
amount. Each illuminated element now become a secondary ideal diffuse emitter that “sends” its light to
This process is clearly iterative, and proceeds until all of the reflected light from all of the elements is
finally absorbed. If we keep a tally of how much light each element reflects and/or emits, we end up
knowing how “bright” it will appear when viewed from any direction. Loosely speaking, this is the
element’s radiosity.
Finally, we know the geometry of each element in the room–in computer graphics parlance, it is a
three-dimensional polygon. If we know its brightness, we can use a 3-D graphics package to directly render
a photorealistic image of the room (as a collection of 3-D polygons) from any viewpoint.
That’s all there is to it! Radiosity explained in five hundred words or less. Mark this section for future
reference.
There are both obvious and subtle differences between ray tracing and radiosity. In ray tracing, the
viewer is paramount. All rays are traced from the view position into the environment. Changing the view
position or orientation by more than a small amount usually requires repeating the entire ray tracing
process from scratch. As such, most ray tracing techniques represent a view-dependent process.
Radiosity is the exact opposite. Our light transfer calculations are based solely on the geometry of the
environment. There is no view position or viewer. Radiosity considers only the interaction of light with
This has an important consequence. Given an environment, we can calculate the visual brightness of
each of its surface elements. These calculations may take some time, but we only need to perform them
once. After that, we can position and orient ourselves anywhere in the environment and synthesize a
Introduction 11
________________________________________________________________________
photorealistic image almost as quickly as we can draw and shade 3-D polygons on our computer screen.
On the other side of the coin, efficient radiosity methods are limited to modeling Lambertian surfaces.
They can model semi-specular surfaces, but only with roughly the same amount of effort as is required by
ray tracing techniques. Also, radiosity methods fail completely to model those specular reflections that are
In short, we should consider ray tracing and radiosity as two complementary approaches to
photorealistic image synthesis. Researchers are still refining existing algorithms and developing new ones.
In the future, we will likely rely on a hybrid approach that combines the best features of both–radiosity for
diffuse reflections and ray tracing for specular highlights. Here, our interest is in radiosity–its theory and
implementation.
There is a fundamental aspect of the radiosity approach that has been so far overlooked in the computer
graphics literature. Consider that ray tracing techniques model objects. An individual ray must interact with
objects in the environment before it can convey any information. Without detailed knowledge of these
Radiosity is different. Yes, we still need to know the geometry and physical properties of the objects.
However, radiosity allows us to render an image of the environment from any viewpoint. Seen thus, it is
evident that radiosity is not modelling the objects within the environment. Instead, it is modelling the three-
dimensional field of light that permeates the environment. More to the point, we will see in Chapter One
that it can in theory model this field exactly and completely. This then becomes a central theme of this
In explaining the radiosity approach, we necessarily had to gloss over a few minor implementation
details ... well, maybe not so minor. In fact, it will take the remainder of this book to discuss them. It will
involve the occasional excursion into higher mathematics, including analytic geometry, elementary
calculus, matrix theory, four dimensional … come back here! It will not be as difficult as you might think.
12 Introduction
________________________________________________________________________
If anything, the sheer volume of C++ source code will prove to be more of challenge. Implementing a
functional radiosity-based renderer is no easy task, as the size of this book attests. Besides, all of the key
mathematical concepts and terminology are explained in strategically positioned text boxes.
The radiosity approach is firmly based on simple geometrical concepts that can be explained without
the aid of mathematics. The mathematics are there because we have to explain these simple concepts to
some very stupid acquaintances: our computers. Read the text first so that you understand the principles
References
Arvo, J., Ed. [1991]. Graphics Gems II, Academic Press, San Diego, CA.
Chen, S.E. [1991]. “Implementing Progressive Radiosity with User-Provided Polygon Display Routines”,
Goral, C. M., K.E. Torrance, D.P. Greenberg and B. Battaile [1984]. “Modeling the Interaction of Light
Between Diffuse Surfaces”, Computer Graphics 18:3 (Proc. ACM SIGGRAPH ‘84), 213 - 222.
Lindley, C.A. [1992]. Practical Ray Tracing in C, John Wiley & Sons, New York, NY.
Newmann, W.M. and R.F. Sproull [1979]. Principles of Interactive Computer Graphics, 2nd Ed.,
Wells, D. and C. Young [1993]. Ray Tracing Creations, Waite Group Press, Corte Madera, CA.
Whitted, T. [1980]. “An Improved Illumination Model for Shaded Display”, Comm. ACM 23:6, 343 - 349.
PART
I
Radiosity Models Light
............................
Here there be dragons. Beware!
Radiosity models light. To fully appreciate the significance of this contention, we first need to
understand what light is and how it is measured. Chapter One examines the concepts of radiometry and
photometry, with a brief excursion into radiometric field theory. These concepts provide a foundation for
Chapter Two, which explains radiosity in terms of the geometrical nature of light.
For some readers, there may indeed be dragons here. Differential equations, area integrals and other
topics from college-level mathematics are not everyday fare for most programmers. Fear not, however. The
accompanying text boxes tame them with high school algebra and trigonometry.
Chapter 1
Measuring Light
1.0 Introduction
light, n. 1. The natural agent that stimulates the sense of sight. 2. Medium or condition of space in
which sight is possible.
The Concise Oxford English Dictionary
Oxford University Press, 1964
There have been many theories concerning the nature of light. Aristotle [384-322 BC] believed
that it consisted of “corpuscles” that emanated from the eye to illuminate the world. Today, we favor
the theory of quantum mechanics (e.g., Hecht and Zajac [1987]), or perhaps the possibility that light
may be vibrations in the fifth dimension of ten-dimensional hyperspace (e.g., Kaku [1994]). Even so,
the true nature of light remains a mystery. It is perhaps appropriate that the pre-eminent dictionary of
the English language describes light so loosely: “the natural agent that stimulates the sense of sight.”
Whatever it may be, our interest in light is much more parochial. We simply want to model what
we see and perceive. While we may think in terms of objects, what we see is light. Ray tracing models
objects; radiosity models light. The distinction is subtle but important. If we are to understand
radiosity, we must first understand the basics. What is light and how do we measure it?
The material in this chapter is somewhat removed from the computer graphics mainstream.
Nevertheless, it is vitally important to understand what it is we are trying to model. The key concepts
in radiosity are radiant exitance (also known as radiosity) and luminance. Unfortunately, these
concepts must be carefully described in fairly rigorous terms using a variety of arcane definitions. So,
Light is electromagnetic radiation. What we see as visible light is only a tiny fraction of the
electromagnetic spectrum, extending from very low frequency radio waves through microwaves,
Measuring Light 15
____________________________________________________________________
infrared, visible and ultraviolet light to x-rays and ultra-energetic gamma rays. Our eyes respond to
visible light; detecting the rest of the spectrum requires an arsenal of scientific instruments ranging
A rigorous and exact description of electromagnetic radiation and its behavior requires a thorough
complete understanding of how we peceive the light our eyes see delves deeply into the physiology
and psychology of the human visual system. There is an enormous body of literature related to the
physical aspects of light as electromagnetic radiation (e.g., Hecht and Zajac [1987]) and an equally
enormous amount devoted to how we perceive it (e.g., Cornsweet [1977]). Fortunately, our interests
are extremely modest. We simply want to measure what we see and perceive.
1.2 Radiometry
Radiometry is the science of measuring light in any portion of the electromagnetic spectrum. In
practice, the term is usually limited to the measurement of infrared, visible and ultraviolet light using
optical instruments.
There are two aspects of radiometry: theory and practice. The practice involves the scientific
instruments and materials used in measuring light, including radiation thermocouples, bolometers,
photodiodes, photosensitive dyes and emulsions, vacuum phototubes, charge-coupled devices and a
Radiometric theory is such a simple topic that most texts on physics and optics discuss it in a few
paragraphs. Unfortunately, a certain historical bias has left us with a theory that is conceptually simple
but sometimes difficult to understand. In essence, the problem is one of separating light from objects.
To appreciate this bias, we first need to review the fundamental radiometric concepts.
Light is radiant energy. Electromagnetic radiation (which can be considered both a wave and a
particle, depending on how you measure it) transports energy through space. When light is absorbed
by a physical object, its energy is converted into some other form. A microwave oven, for example,
heats a glass of water when its microwave radiation is absorbed by the water molecules. The radiant
16 Measuring Light
_____________________________________________________________________
energy of the microwaves is converted into thermal energy (heat). Similarly, visible light causes an
electric current to flow in a photographic light meter when its radiant energy is transferred to the
Energy per unit time is power, which we measure in joules per second, or watts. A laser beam, for
example, has so many milliwatts or watts of radiant power. Light “flows” through space, and so
radiant power is more commonly referred to as the “time rate of flow of radiant energy”, or radiant
Φ = dQ dt (1.1)
If your background doesn’t include college-level calculus, think of the above differential equation
as follows. You might walk m meters in t minutes. The velocity v at which you walk may vary, but
your average velocity v avg is the distance m divided by the time t, or:
v avg = m t
In each minute, you may walk ∆m meters, where ∆m varies from minute to minute. Your average
vavg = ∆m ∆t
where ∆t is the interval of time over which ∆m is measured. We can clearly shorten the interval of
time (seconds, milliseconds, etc.) until it is infinitesimally small. The distance traveled is then
infinitesimally short. If we denote the time interval as dt (indicating a differential interval of time)
v = dm dt
Looking again at Equation 1.1, the radiant energy Q is the total “amount of work done” (the
definition of energy). The radiant flux Φ is the infinitesimal amount of work done ( dQ ) in an
In terms of a photographic light meter measuring visible light, the instantaneous magnitude of the
electric current is directly proportional to the radiant flux. The total amount of current measured over a
period of time is directly proportional to the radiant energy absorbed by the light meter during that
time. This is how a photographic flash meter works–it measures the total amount of radiant energy
The flow of light through space is often represented by geometrical rays of light such as those used
in computer graphics ray tracing. They can be thought of as infinitesimally thin lines drawn through
space that indicate the direction of flow of radiant energy (light). They are also mathematical
abstractions–even the thinnest laser beam has a finite cross-section. Nonetheless, they provide a useful
Radiant flux density is the radiant flux per unit area at a point on a surface, where the surface can
be real or imaginary (i.e., a mathematical plane). There are two possible conditions. The flux can be
arriving at the surface (Fig. 1.1a), in which case the radiant flux density is referred to as irradiance.
The flux can arrive from any direction above the surface, as indicated by the rays. Irradiance is
defined as:
E = dΦ dA (1.2)
where Φ is the radiant flux arriving at the point and dA is the differential area surrounding the point.
The flux can also be leaving the surface due to emission and/or reflection (Fig. 1.1b). The radiant
flux density is then referred to as radiant exitance. As with irradiance, the flux can leave in any
M = dΦ dA (1.3)
where Φ is the radiant flux leaving the point and dA is the differential area surrounding the point.
18 Measuring Light
_____________________________________________________________________
dA dA
Figure 1.1a - Irradiance Figure 1.1b - Radiant exitance
The importance of a “real or imaginary” surface cannot be overstated. It means that radiant flux
density can be measured anywhere in three-dimensional space. This includes on the surface of
physical objects, in the space between them (e.g., in air or a vacuum) and inside transparent media
1.2.4 Radiance
Radiance is best understood by first visualizing it. Imagine a ray of light arriving at or leaving a
point on a surface in a given direction. Radiance is simply the amount of radiant flux contained in this
ray. Period.
A more formal definition of radiance requires that we think of the ray as being an infinitesimally
narrow (“elemental”) cone with its apex at a point on a real or imaginary surface. This cone has a
A solid angle is the 3-D analog of a two-dimensional angle. Figure 1.2a shows two lines radiating
from the center of a circle of radius r. The angle θ between the lines can measured in terms of the
length of the chord c between them. If c = r, then the angle is one radian. The circumference of a
Similarly, Figure 1.2b shows a cone radiating from the center of a sphere of radius r. The solid
angle ω of the cone (which can have any cross-sectional shape) can be measured in terms of the
surface area A of the sphere it intersects as ω = A r 2 . If A = r 2 , then the solid angle is one
steradian. The area of a sphere is 4πr 2 ; therefore, there are 4π steradians in a sphere.
Measuring Light 19
____________________________________________________________________
θ
c ω
Α
r
r
We must also note that the ray is intersecting the surface at an angle. If the area of intersection
with the surface has an differential cross-sectional area dA, the cross-sectional area of the ray is
dA cos θ , where θ is the angle of between the ray and the surface normal, as shown in Figure 1.3. (The
ray cross-sectional area dA cos θ is called the projected area of the ray-surface intersection area dA.
n
Φ
θ
Projected area
dA cos θ
dA
Figure 1.3 - A ray of light intersecting a surface
With these preliminaries in mind, we can imagine an elemental cone dω containing a ray of light
that is arriving at or leaving a surface (Figs. 1.4a and 1.4b). The definition of radiance is then:
where Φ is the radiant flux, dA is the differential area surrounding the point, dω is the differential
solid angle of the elemental cone and θ is the angle between the ray and the surface normal n at the
point.
The superscript ‘2’ in Equation 1.4 doesn’t mean that anything is being squared. Rather, it
indicates that the infinitesimal amount of flux dΦ is divided by the differential area dA and the
Φ n Φ n
θ θ
dω dω
dA dA
Figure 1.4a - Radiance (arriving) Figure 1.4b - Radiance (leaving)
Unlike radiant flux density, the definition of radiance does not distinguish between flux arriving at
or leaving the surface. In fact, the formal definition of radiance (ANSI/IES [1986]) states that it can be
Another way of looking at radiance is to note that the radiant flux density at a point on a surface
due to a single ray of light arriving (or leaving) at an angle θ to the surface normal is dΦ (dA cosθ ) .
The radiance at that point for the same angle is then d 2 Φ [dω (dA cosθ )] , or radiant flux density per
We can imagine an infinitesimally small point source of light that emits radiant flux in every
direction. The amount of radiant flux emitted in a given direction can be represented by a ray of light
I = dΦ dω (1.5)
where dω is the differential solid angle of the elemental cone containing the given direction. From the
E = dΦ dA = dΦ r 2 dω = I r 2 (1.6)
where the differential surface area dA is on the surface of a sphere centered on and at a distance r from
the source and E is the irradiance at that surface. More generally, the radiant flux will intercept dA at
an angle θ (Fig. 1.5). This gives us the inverse square law for point sources:
E = I cosθ d 2 (1.7)
Measuring Light 21
____________________________________________________________________
where I is the intensity of the source in the given direction and d is the distance from the source to the
θ
d
dA
We can further imagine a real or imaginary surface as being a continuum of point sources, where
each source occupies a differential area dA (Fig. 1.6). Viewed at an angle θ from the surface normal n,
the source has a projected area of dA cos θ . Combining the definitions of radiance (Eqn. 1.4) and
where dI is the differential intensity of the point source in the given direction.
dI
θ
dA
The above definitions are those commonly used in illumination engineering, and are in accordance
with the American National Standard Institute publication “Nomenclature and Definitions for
Illuminating Engineering” (ANSI/IES [1986]). Unfortunately, these definitions differ somewhat from
those used in thermal engineering (e.g., Siegel and Howell [1981]). Radiative heat transfer theory (i.e.,
infrared light) does not use the point source concept. Thermal engineers instead use the term “radiant
intensity ” to describe radiance (watts per unit area per unit solid angle).
22 Measuring Light
_____________________________________________________________________
The different terminology was of little consequence until the computer graphics community
adapted the concepts of radiative heat transfer to create radiosity theory. In the process of doing so it
adopted thermal engineering’s terminology. This is an unfortunate situation, since computer graphics
This book defines radiant intensity as “watts per unit solid angle” and radiance as “watts per unit
area per unit solid angle” to maintain consistency between radiosity and ray tracing theory. You
should remember, however, that many papers and texts on radiosity theory and some computer
graphics texts instead define “radiant intensity” as “watts per unit area per unit solid angle”.
1.4 Photometry
Photometry is the science of measuring visible light in units that are weighted according to the
sensitivity of the human eye. It is a quantitative science based on a statistical model of the human
visual response to light–that is, our perception of light under carefully controlled conditions..
The human visual system is a marvelously complex and highly nonlinear detector of
electromagnetic radiation with wavelengths ranging from about 380 to 770 nanometers (nm). We see
light of different wavelengths as a continuum of colors ranging through the visible spectrum: 650 nm
The sensitivity of the human eye to light varies with wavelength. A light source with a radiance of
one watt/m2-steradian of green light, for example, appear much brighter than the same source with a
radiance of one watt/m2-steradian of red or blue light. In photometry, we do not measure watts of
radiant energy. Rather, we attempt to measure the subjective impression produced by stimulating the
This task is complicated immensely by the eye’s nonlinear response to light. It varies not only with
wavelength, but also with the amount of radiant flux, whether the light is constant or flickering, the
spatial complexity of the scene being perceived, the adaptation of the iris and retina, the psychological
Nevertheless, the subjective impression of seeing can be quantified for “normal” viewing
Illumination, or CIE) asked over one hundred observers to visually match the “brightness” of
monochromatic light sources with different wavelengths under controlled conditions. The statistical
result–the so-called “CIE photometric curve” shown in Figure 1.7–shows the photopic luminous
efficiency of the human visual system as a function of wavelength. It provides a weighting function
1
0.9
0.8
0.7
Photopic 0.6
luminous 0.5
efficiency 0.4
0.3
0.2
0.1
0
390 440 490 540 590 640 690 740
Wavelength (nm)
Photometric theory does not address how we perceive colors. The light being measured can be
the CIE weighting function. This underlines a crucial point: the only difference between radiometric
and photometric theory is in their units of measurement. With this thought firmly in mind, we can
The foundations of photometry were laid in 1729 by Pierre Bouguer. In his “L’Essai d’Optique”,
Bouguer discussed photometric principles in terms of the convenient light source of his time: a wax
candle. This became the basis of the point source concept in photometric theory.
Wax candles were used as national light source standards in the 18th and 19th centuries. England,
for example, used spermaceti (a wax derived from sperm whale oil). These were replaced in 1909 by
an international standard based on a group of carbon filament vacuum lamps, and again in 1948 by a
crucible containing liquid platinum at its freezing point. Today, the international standard is a
theoretical point source that has a luminous intensity of one candela (the Latin word for candle). It
emits monochromatic radiation with a frequency of 540 × 1012 Hertz (or approximately 555 nm,
24 Measuring Light
_____________________________________________________________________
corresponding with the wavelength of maximum photopic luminous efficiency) and has a radiant
Together with the CIE photometric curve, the candela provides the weighting factor needed to
convert between radiometric and photometric measurements. Consider for example a monochromatic
point source with a wavelength of 510 nm and a radiant intensity of 1/683 watts per steradian. The
photopic luminous efficiency at 510 nm is 0.503. The source therefore has a luminous intensity of
0.503 candela.
Luminous flux is photometrically weighted radiant flux (power). Its unit of measurement is the
lumen, defined as 1/683 watts of radiant power at a frequency of 540 × 1012 Hertz. As with luminous
intensity, the luminous flux of light with other wavelengths can be calculated using the CIE
photometric curve.
A point source having a uniform (isotropic) luminous intensity of one candela in all directions
(i.e., a uniform intensity distribution) emits one lumen of luminous flux per unit solid angle
(steradian).
Luminous flux density is photometrically weighted radiant flux density. Illuminance is the
photometric equivalent of irradiance, while luminous exitance is the photometric equivalent of radiant
exitance.
1.4.5 Luminance
luminance. It is an approximate measure of how “bright” a surface appears when we view it from a
given direction. Luminance used to be called “photometric brightness”. This term is no longer used in
Measuring Light 25
____________________________________________________________________
illumination engineering, since the subjective sensation of visual brightness is influenced by many
A Lambertian surface is a surface that has a constant radiance or luminance that is independent of
the viewing direction. In accordance with the definition of radiance (luminance), the radiant
A Lambertian surface is also referred to as an ideal diffuse emitter or reflector. In practice there are
no true Lambertian surfaces. Most matte surfaces approximate an ideal diffuse reflector, but typically
exhibit semispecular reflection characteristics at oblique viewing angles. Nevertheless, the Lambertian
Lambertian surfaces are unique in that they reflect incident flux in a completely diffuse manner
(Fig. 1.8). It does not matter what the angle of incidence θ of an incoming geometrical ray is–the
equivalent to a point source and so the flux leaving the surface can be modeled as geometrical rays.
The intensity I θ of each ray leaving the surface at an angle θ from the surface normal is given by
Iθ = I n cosθ (1.9)
where I n is the intensity of the ray leaving in a direction perpendicular to the surface.
26 Measuring Light
_____________________________________________________________________
dA
Figure 1.8 - Reflection from a Lambertian surface
The derivation of equation 1.9 becomes clear when we remember that we are viewing dA from an
angle θ. For a differential area dA with a constant radiance or luminance, its intensity must vary in
accordance with its projected area, which is dA cosθ . This give us:
There is a very simple relation between radiant (luminous) exitance and radiance (luminance) for
M = πL (1.11)
where the factor of π is a source of endless confusion to students of radiometry and photometry.
on the inside surface of an imaginary sphere S (Fig. 1.9). The inverse square law (Eqn. 1.6) provides
the irradiance E at any point P on the inside surface of the sphere. However, d = D cosθ , where D is
which simply says that the irradiance (radiant flux density) of any point P on the inside surface of S is
a constant.
Measuring Light 27
____________________________________________________________________
n
Sphere S
P
D
θ
θ d
dA
This is interesting. From the definition of irradiance (Eqn. 1.2), we know that Φ = EA for
constant flux density across a finite surface area A. Since the area A of the surface of a sphere with
A = 4πr 2 = πD 2 (1.14)
we have:
Φ = EA = πI n D 2 D 2 = πI n (1.15)
Given the definitions of radiant exitance (Eqn. 1.3) and radiance for a Lambertian surface (Eqn.
1.10), we have:
M = dΦ dA = πdI n dA = πL (1.16)
This explains, clearly and without resorting to integral calculus, where the factor of π comes from.
We see light only through its effects on physical objects. In looking at the world, we “see”
physical objects. More precisely, we perceive the luminance of their surfaces. Bouguer and other early
investigators made this apparent truism an integral part of photometric theory by defining illuminance,
Physicists later became interested in other aspects of light, including that emitted by plasmas.
What is the luminous exitance or luminance of an electric arc? The glowing gas has no definable
surface! The same goes for the sky overhead, where the blue light we see is due to sunlight scattered
by air and dust molecules from the ground to the outer reaches of the atmosphere. These are clearly
volume sources of light. The definitions of luminous flux density and luminance do not seem to apply.
28 Measuring Light
_____________________________________________________________________
This problem was overcome by introducing the concept of an imaginary surface, a mathematical
plane drawn in space. It can be positioned and oriented in 3-D space as required, including inside a
volume light source. The traditional photometric definitions were thus retained intact.
The question is, why? Photometric and radiometric theory does not address the properties of any
surface, real or imaginary. Is it necessary to consider surfaces at all? The answer is simple and
unequivocal: no.
Field theory is one of the most powerful mathematical methods used in physics today. At the time
of its development however, most of our present-day radiometric and photometric theory was already
firmly established. Based mainly on the work of Johann Heinrich Lambert [1760] and geometrical
Mehmke [1898] was the first to suggest that field theory might have applications in illumination
engineering. His suggestion was later developed into a formal theoretical framework for radiometric
field theory by Yamauti [1932] and Gershun [1936]. Moon and Spencer continued to develop this
theory for another forty-odd years, culminating in their publication of “The Photic Field” (Moon and
Spencer [1981]).
Radiometric field theory does not address light coming from point sources. Rather, it considers a
field of light that permeates three-dimensional space. Yamauti and Gershun referred to this field as a
“light field”, while Moon and Spencer [1981] called it a “photic” field. Photic fields are rigorously
described by Maxwell’s electromagnetic field equations for the special case of zero wavelength
(Moon and Spencer [1981]). They are also 5-D scalar fields, where scalar measurements (irradiance
and radiance) are made in five dimensions: three axes for position (x, y, and z) and two axes for
As you might have guessed, the full mathematical details of radiometric field theory are complex
and abstract. This complexity has made it more of a curiosity than a useful tool for everyday
illumination engineering. Very few illumination engineers are even aware of its existence.
Measuring Light 29
____________________________________________________________________
Nevertheless, radiometric field theory has something to offer: a different view of radiometry and
photometry. This becomes evident when we reconsider radiometry (and by extension photometry)
The validity of radiant energy and radiant flux is self-evident, since they do not refer to surfaces.
Electromagnetic radiation transports energy through space. We can therefore imagine a field of light–a
photic field–in three-dimensional space, with geometrical rays indicating its direction of flow.
We can monitor this flow with an instrument that detects the radiant flux incident on a small
surface area (its “active surface”). The flux is converted into an electric current I that we can measure
with an ammeter M (Fig. 1.10). By dividing the measured flux by the surface area, we can calculate
Our instrument can be placed anywhere in space; the amount of radiant flux it receives it measures
clearly depends on its position and orientation. If we make the active surface area infinitesimally
I
M
The radiant flux must come from physical objects, either directly from emissive sources or
indirectly through reflection, refraction, diffraction or scattering. Remember however that we are
measuring light; where it comes from is immaterial. We are only interested in measuring radiant flux
In measuring irradiance, our instrument “sees” an entire hemisphere of space. That is, it is
sensitive to rays of light arriving from any direction above the surface of the imaginary plane defined
30 Measuring Light
_____________________________________________________________________
by the position and orientation of the instrument’s active surface. However, we are measuring
irradiance as a property of a photic field. We do not need to relate this measurement to any surface,
real or imaginary.
This is a subtle but very important point. Radiometric field theory does not change the definition
of radiant flux density (irradiance and radiant exitance). Instead, it changes the way we interpret it.
Radiant flux density is an intrinsic property of a photic field. Its relation to any physical surface is
almost coincidental. We should therefore refer to irradiance or radiant exitance at a surface rather than
of a surface.
This interpretation of radiant flux density can be extended to the definition of radiance with
interesting results. Suppose we use an opaque shield (oriented perpendicular to the active surface) to
restrict our irradiance meter’s field of view to a finite solid angle ω (Fig. 1.11). It then measures the
average radiance at the active surface for the directions contained within the field of view.
M Opaque shield Φ
By using a differential solid angle dω and a differential active surface area dA, we can in theory
measure the radiance at a mathematical point for radiant flux arriving from directly above the surface.
Since the solid angle dω defines a geometrical ray of light that is perpendicular to the active surface,
the area dA coincides with the differential cross-sectional area of the ray. In other words, our
instrument measures the radiance of a ray of light at a point in space. The interpretation is clear:
radiance is an intrinsic property of a geometrical ray of light. It is not a property of any surface, real or
imaginary.
L = d 2 Φ dAdω (1.17)
where Φ is the radiant flux of the ray at the point, dA is the differential cross-sectional area of the ray
and dω is the differential solid angle of an elemental cone containing the ray.
Moon [1942] referred to this definition of radiance as helios. However, it is merely a special case
of the more general definition of radiance (Eqn. 1.4). In particular, it only considers radiant flux
arriving at a point, and it has an implicit divisor of cos θ (where the angle θ is zero).
To answer the obvious question, the name of the radiosity rendering program presented in this
book–HELIOS–is in honor of the pioneering work done by Moon and Spencer in the fields of
If nothing else, radiometric field theory clearly demonstrates the following axiom:
Radiometry and photometry measure intrinsic properties of a field of light in space. These
There is an interesting corollary to this axiom: radiometric and photometric theory does not
require a point source. This was implicitly demonstrated in the order of presentation of the
radiometric definitions, where radiant intensity was presented almost as an afterthought. Without a
The photometric definitions began with luminous intensity only because photometric theory
defines the candela as a basic unit of measurement and derives the definition of lumens from it. This is
a historical artifact from the time of Pierre Bouguer and his wax candles. (We still draw point sources
as a candle with geometrical rays radiating from the flame!) The lumen can be defined from first
principles without resorting to point sources; the candela is just another name for lumens per
steradian.
The inconsequential nature of the point source is important for two reasons. First, there are no
point sources in nature. Even the distant stars have a finite width that can be measured if the telescope
32 Measuring Light
_____________________________________________________________________
aperture is large enough. We will see in the next chapter that radiosity theory does not require a point
source. In this sense, radiometric field theory provides a clearer understanding of radiosity.
Second, point sources are objects. Ray tracing techniques rely on point sources as the ultimate
source of radiant flux within an environment. The illuminance at a surface due to a point source can
be determined using Lambert’s inverse square law, but only if we know the exact distance from the
surface to the source. This is simple enough for single point sources, but becomes difficult for
extended line and area sources and intractable for volume sources if they are modeled as an array or
The radiosity approach emphasizes light over objects. As we see in the next chapter, the
geometrical relations between objects in an environment are required only to determine their mutual
“form factors”. Radiosity then models the photic field within the environment with no further
reference to these objects. This is the proof of our contention: radiosity models light.
ANSI/IES [1986] does not define or even mention “radiosity”. This is not unusual–there are many
photometric and radiometric terms whose use is no longer encouraged. Illuminance, for example, used
to be called “illumination”. It was changed to illuminance to avoid confusion with “the act of
When Moon wrote “The Scientific Basis of Illumination Engineering” in 1936, luminous exitance
was called “luminosity”. Curiously, there was no equivalent term for radiant exitance, so he coined the
The illumination engineering community ignored Moon’s proposal. Luminosity was changed to
“luminous emittance” and later to luminous exitance, with radiant exitance following as a consequent.
Meanwhile, the thermal engineering community adopted radiosity (e.g., Siegel and Howell [1981]).
This book takes exception, perhaps unwisely, to the computer graphics community’s use of the
term “radiosity” to describe radiant exitance. While it is an accepted term within the thermal
Measuring Light 33
____________________________________________________________________
reasons. The computer graphics and illumination engineering communities have many common
interests. If we are to communicate effectively, we must use a common lexicon of definitions. That
An irradiance or radiance meter is carefully designed to respond equally to light of any wavelength
within the visible spectrum. As such, the meter measures radiant flux, regardless of whether we are
measuring sunlight, monochromatic laser radiation or any other source of visible light.
Suppose that we are using a radiance meter to measure sunlight reflected from a surface, where the
radiant flux consists of a continuum of wavelengths across the visible spectrum (e.g., Fig. 1.12). We
can filter this light such that it has a very narrow bandwidth. For example, we can use a “multilayer
interference” filter that is only transparent to light with wavelengths between 632 nm and 633 nm. If
we could make the filter bandwidth infinitesimally narrow (a physical impossibility), we could
measure spectral radiance, which is expressed in watts per square meter per steradian per nanometer
(ANSI/IES [1986). Following Equation 1.4, spectral radiance is expressed mathematically as:
where λ is the wavelength. (On second thought, it might be better to remember the concept rather than
the equation!)
The sum of spectral radiance for each infinitesimally narrow band across the visible spectrum is of
course equal to the radiance we would measure without a filter. In practice, we can divide the
spectrum into bands of finite width and achieve approximately the same result. Suppose we measure
average spectral radiance through red, green and blue filters, where each filter is almost transparent
within its bandwidth and the amount of overlap between the color bands is minimized. The sum of
In measuring the distribution of spectral radiance across the visible spectrum, we are measuring
the physical “color” of the radiant flux. The relative amounts of spectral radiance determine what we
perceive as the color of the surface. Red, for example, indicates a preponderance of spectral radiance
34 Measuring Light
_____________________________________________________________________
at wavelengths between 580 nm and 700 nm, while blue indicates a preponderance of spectral
radiance between 400 nm and 480 nm. According to Figure 1.12, our surface will appear to be
distinctly reddish.
Measuring the color of radiant flux is a relatively straightforward task. However, it is often
difficult to determine what our perception of the color will be. As with photometric quantities, our
response to spectral radiance distribution (color) depends on a host of physical and psychological
variables. The subjective impression of color perception can only be quantified (in a statistical sense)
1
Spectral Radiance
0.8
0.6
0.4
0.2
0
400 420 440 460 480 500 520 540 560 580 600 620 640 660 680
Wavelength (nm)
A full discussion of how we perceive color requires at least a book in itself (e.g., Judd and
Wyszecki [1975] or Burnham et al. [1963]). For the purposes of photorealism, however, our viewing
transparency. Foley et al. [1990], Hill [1990], Watt [1990] and other tutorial and reference texts offer
informative overviews of color theory for the computer graphics enthusiast. Perhaps the best reference
You might question the brevity of this discussion on color theory, especially since this book is
devoted to the subject of photorealistic images. If so, you are absolutely correct. Unfortunately, the
topic of radiosity and its implementation fills a book in itself. As interesting and important as the topic
of color theory is, there is simply no space to discuss it in any greater depth.
Given the definition of spectral radiance, we can compare it with the definition of radiant exitance
M λ = d 2 Φ (dAdλ ) (1.19)
This is one of the two key concepts in radiosity theory (the other is luminance). More specifically,
it is the concept of an average spectral radiant exitance that is measured through a red, green or blue
filter. The importance of these concepts will become evident in the next chapter.
We can remember this concept in a colloquial sense: the average spectral radiant exitance of a real
or imaginary surface is simply the amount of radiant flux–visible light–per square meter leaving the
surface, where the light is within a given band of colors (e.g., red, green or blue).
Having seen that radiometric and photometric quantities are intrinsic properties of a field of light
Reflectance and transmittance are intrinsic properties of physical objects. They are independent of
In the simplest case, we have opaque objects with ideal diffuse or ideal specular surfaces. Here,
reflectance is a dimensionless number that indicates the percentage of incident radiant flux reflected
The reflectance of any given surface typically varies with wavelength. Thus, we can refer to
inherent spectral reflectance as the reflectance of a surface within an infinitesimally narrow band of
wavelengths. We can further refer to the spectral reflectance distribution as the “color” of the surface.
Defined in this manner, color is an intrinsic property of physical surfaces that is independent of any
surrounding field of light. We know from experience that the perceived color of an object can vary,
depending on the spectral irradiance distribution of the light illuminating it. For example, an object
that appears blue in sunlight will be jet black when viewed under a monochromatic red light. This,
however, is a consequence of the surrounding photic field, not the object itself.
There is more to reflectance than this, of course. In general, the reflectance of an opaque object
with semispecular surfaces is a function of the angle of incidence of the illuminating flux and the
36 Measuring Light
_____________________________________________________________________
function, or BRDF.
Transparent and translucent objects complicate matters even further, especially when the objects
are inhomogeneous. We can easily measure and express the transmittance of an ideal transparent
object with specular surfaces. For ideal transparent objects with semispecular surfaces, we can express
problem becomes more intractable. Reflection, refraction, diffraction, scattering and polarization
effects all contribute to the distribution of radiant flux within and through transparent and translucent
objects. Accurately modeling these effects typically requires a physically accurate model of the object
being illuminated.
We shall find in the next chapter, however, that the radiosity approach is best suited to modeling
environments with opaque and ideally diffuse surfaces. Thus, while we should be aware of the
reflectance and transmittance of physical objects, we can consider reflectance in its simplest form: the
1.15 Conclusions
The material presented in this chapter is unquestionably tedious reading for someone interested
solely in computer programming. Clearly though, the fundamental definitions of radiometry and
The very brief introduction to radiometric field theory is recommended reading. Defining
radiometric and photometric theory in terms of a photic field is more than mere semantic juggling; it
offers a new paradigm for lighting research and radiosity studies. More importantly, it clarifies the
References
ANSI/IES [1986]. American National Standard Nomenclature and Definitions for Illuminating
Engineering, ANSI/IES RP-16-1986, Illuminating Engineering Society of North America, New York,
NY.
Burnham, R.W., R.M. Hanes and C.J. Bartleson [1963]. Color: A Guide To Basic Facts and Concepts,
Cornsweet, T.N. [1977]. Visual Perception, Academic Press, New York, NY.
Foley, J.D., A. van Dam, S.K. Feiner and J.F. Hughes [1990]. Computer Graphics: Principles and
Gershun, A. [1936]. Svetovoe Pole (The Light Field), Moscow. Translated by P. Moon and G.
Technology, 51 - 151.
Hall, R. [1989]. Illumination and Color in Computer Generated Imagery, Springer-Verlag, New
York, NY.
Hecht, E. and A. Zajac [1987]. Optics, 2nd edition, Addison-Wesley, Reading, MA.
Hill, F.S., Jr. [1990]. Computer Graphics, Macmillan, New York, NY.
Judd, D. and G. Wyszecki [1975]. Color in Business, Science and Industry, Wiley, New York, NY.
Lambert, J.H. [1760]. Photometria sive de mensura et gradibus luminus, colorum et umbrae. German
translation with annotations by E. Anding [1892], Ostwald’s Klassiker der Exakten Wissenschaften
Mehmke, R. [1898]. “Über die mathematische bestimmung der helligkeit in räumen mit
tagesbeleuchtung, insbesondere gemäldesälen mit deckenlict”, Zs. für Math. u. Phys. 43, 41 - 57.
Moon, P. [1936]. The Scientific Basis of Illumination Engineering, McGraw-Hill, New York, NY.
Moon, P. [1942]. “A System of Photometric Concepts”, J. Optical Society of America 32 (June), 348 -
362.
Moon, P. and D.E. Spencer [1981]. The Photic Field, MIT Press, Cambridge, MA.
Siegel, R. and J.R. Howell [1981]. Thermal Radiation Heat Transfer, Hemisphere Publishing,
Washington, DC.
Yamauti, Z. [1932]. “Theory of Field of Illumination” (in English), Researches of the Electrotechnical
Reading, MA.
Chapter 2
Radiosity Theory
2.0 Introduction
Radiosity models light. More specifically, the radiosity approach models the field of light–the photic
field–within an environment. We saw this on an informal basis in the introduction; it is now time to
Our understanding of how light is measured allows us to consider both ray tracing and radiosity in
greater detail. Returning to our empty room (Fig. 2.1), we can now ask how we might model both the flow
Figure 2.1 - Modeling the flow and field of light in an empty room
Light flows through space and optically homogeneous media (air, water, glass, and so forth) in a
straight line, which we model as a geometrical ray. This is the essence of the ray tracing approach.
We can model the direct illumination in an environment using conventional ray tracing techniques. We
know that the illuminance at a point on any surface due to a single point source can be calculated using the
inverse square law (Eqn. 1.7). We can model the light fixture (an area source) as a finite 2-D array of n
Si
di
θi
Area source
∑ (I i cosθ i )
n
E= d i2 (2.1)
i =1
where Ii is the luminous intensity of point source Si in its given direction. In other words, we simply add
Another quick note on mathematical terminology. The “Σ” symbol (pronounced “sigma”) indicates
summation. If, for example, we have n variables xi, where 1 ≤ i ≤ n, then the expression:
n
y= ∑ xi
i =1
means that y is equal to the sum of the variables xi, or y = x1 + x2 + x3 + ... + xn. The lower and upper
You may sometimes see the sigma symbol without these limits, but only when they are obvious and
therefore implied.
There are a few complications, of course. We need to determine whether each point source i is visible
from the surface being illuminated (that is, its visibility), and we need to know its distance d i from the
point on the surface. We also need to know the luminous intensity I i for each source in its given direction.
Modeling an area source as a 2-D array of point sources is a straightforward but computationally expensive
technique.
Radiosity Theory 41
________________________________________________________________________
Modeling the indirect illumination is more challenging. A ray of light reflected from an ideal specular
surface remains a single ray. In general however, most physical surfaces are semispecular or diffuse
reflectors. This means that a single ray of light will be reflected as an infinite number of rays (Fig. 2.3).
We saw in the introduction that this represents a nearly intractable computation problem. We can trace
as many rays as we want or have time for, but this will still represent a vanishingly small portion of the
number of rays actually in the environment. Yes, ray tracing accurately models the flow of light in an
environment. However, it provides at best an almost insignificant sampling of the field of light that
permeates it.
Backwards ray tracing (e.g., Glassner [1989) provides a partial solution by tracing a finite number of
rays from the eye to the objects being modeled. As such, it attempts to sample the photic field at a specific
point in space. Consider, however, what this means. A ray of light is traced backwards from the eye to the
object is originated from. In Figure I.2, the ray luminance at the point of intersection was due to two rays
from the point source and a specular surface. In reality, however, life is more complex. The ray luminance
at the point of intersection is due to the direct illuminance from the source (which is in general an area or
volume source) and the indirect illuminance due to multiple reflections from many semi-specular and
This is the dilemma of ray tracing techniques. Each and every reflection from a diffuse or semi-specular
surface results in an infinity of rays from a single incident ray. The ray tracing approach can only sample
these rays at each surface. Each reflection results in a geometric decrease in the overall size of the sample
(infinity, infinity square, infinity cubed, …). As such, it cannot accurately model the photic field at a
specific point in space, since in general the entire field contributes to its value at any point in space.
This explains the inability of ray tracing techniques to accurately model soft shadows and other subtle
effects of lighting (such as color bleeding). These effects can only be achieved through the use of ad hoc
techniques that are better at generating visually appealing imagery than they are at modeling the physical
reality of light.
Once again, this is not to disparage ray tracing techniques. The dual of the above argument is that
specular highlights are essential to truly photorealistic images. In a sense, however, they represent the
luminance of individual rays of light. Considering Figure 2.2 and Equation 2.1, the illuminance at a point
in space (i.e., our eye) is due to the sum of many of rays. The contribution of any single ray is minuscule.
Nevertheless, we may perceive one or more individual rays as being dazzlingly luminous against a muted
background.
This is where the ray tracing approach excels. We see–at least to within the limits of resolution of the
human eye–the luminance of individual rays of light; we do not see or perceive the illuminance of our
Radiosity Theory 43
________________________________________________________________________
retinae. The ray tracing approach is essential if we are to accurately model the luminance of specularly-
reflected rays.
In summary, ray tracing accurately models the flow of light in an environment. Unfortunately, it does
not and cannot model the field of light with the same degree of accuracy. For this, we need a fundamentally
different approach.
… and so we return again to our empty room, with each surface neatly divided into a mesh of elements
that we shall call patches (Fig. 2.5). We also assume that each surface is a Lambertian reflector, and that
The assumption that all surfaces are Lambertian is important–remember that these surfaces have a
constant luminance (or, more generally, radiance) that is independent of the viewing direction. For a
Lambertian reflector, the reflected luminous (radiant) flux is independent of the angle of the incident flux.
From the point of view of a single patch, it does not matter where the light is coming from–if we know its
illuminance (irradiance) and reflectance, we can calculate its luminous (radiant) exitance and luminance
(radiance). For the sake of convenience, we shall henceforth discuss radiosity in radiometric terms; the
We know that the distribution of flux leaving a Lambertian surface is given by Lambert’s Cosine Law
(Eqn. 1.9). We can therefore calculate the flux emitted in any given direction by the light source patch.
Simple geometry allows us to determine which patches are visible from each light source patch; this allows
44 Radiosity Theory
________________________________________________________________________
us to determine their irradiances. Each irradiated patch in turn reflects some of its incident flux back into
the room. Again using Lambert’s Cosine Law, we can determine the irradiances of all the patches visible to
it.
This process is clearly iterative, and proceeds until all of the reflected flux is finally absorbed. If we
keep a record of how much flux each patch reflects and/or emits, we end up knowing its radiant exitance
M. Since the patch is Lambertian, we can divide M by π to determine its radiance L (from Equation 1.11).
Confused? Read “Radiosity Explained” in the introduction and try again. The two explanations are
equivalent, except that the above uses the more rigorous terminology we developed in the previous chapter.
Finally, we know the geometry of each patch in the room. If we know its radiance (and consequently its
luminance), we can use a 3-D graphics package to directly render a photorealistic image of the room (as a
The restriction of Lambertian surfaces is not fundamental. As presented above, it simply allows us to
employ Lambert’s Cosine Law as a computational convenience. Suppose, for example, that we have a non-
Lambertian light source whose spatial flux distribution characteristics are known. Again using the room
geometry, we can determine the flux (i.e., the direct illumination) incident on any given patch. If the
projected width of the patch as seen from the source is small enough in comparison to the distance between
then, we can “shoot” a ray from the source to the center of the patch. The luminance of this ray will be
approximately the same as the infinite number of other source rays which directly illuminate the patch, and
so we can approximate the incident flux as the ray luminance times the patch’s projected area (with
appropriate allowances for occluding objects). By considering any non-emitting patch that reflects flux as a
“secondary light source”, we can generalize this concept to any semi-specular or specular surface.
That’s all there is to it! We have exactly paraphrased our discussion in the introduction, this time
adding the proper radiometric/photometric terminology and a few explanatory comments. True, we have
necessarily glossed over a few minor implementation details ... well, maybe not so minor. We will examine
Summarizing once again, it is evident that radiosity accurately models the field of light within an
environment. The contribution of the entire photic field is taken into account at every point in space, and so
Radiosity Theory 45
________________________________________________________________________
the subtle lighting effects of soft shadows and color bleeding are naturally accounted for. Moreover, the
radiosity approach solves for the entire photic field at all points in space. We can choose any point and
direction in the environment and generate a photorealistic view without having to repeat the radiosity
calculations.
In that ray tracing techniques model the flow of light in an environment, we might visualize ray tracing
as a dynamic process that follows photons of light as they interact with objects in the environment. In
contrast, radiosity is a static process. The incessant generation and flow of photons results in a static field
that permeates the environment. Radiosity models the intrinsic nature of this photic field.
Radiosity and ray tracing are in a sense dual processes (Smits et al. [1992]). In practical terms, radiosity
models the field of light that determines the wide brush of lighting and its subtle nuances. Ray tracing, its
indispensable complement, is needed to provide the specular highlights as finishing touches. Only together
are they are capable of providing truly photorealistic images … with a few exceptions.
To be honest, existing radiosity methods model the field of light in a purely reflective environment.
Nowhere in the above discussion is there any mention of the refraction of light through transparent objects.
There is also no mention of scattering, diffraction or other optical phenomena that are easily modeled with
If you think about it, these phenomena are most often localized to the objects and their immediate
environs. A prism casts a rainbow of light on a surface; a glass sphere projects a circle of light on a
tabletop and presents a topsy-turvy view of the environment seen through it. While we see and perceive
these phenomena as prominent visual effects, they rarely influence the surrounding photic field to any
significant extent. Their effect on the global environment is localized to those ray of light that directly
There are hybrid techniques that combine radiosity methods with ray tracing techniques to accurately
model these phenomena (e.g., Wallace et al. [1987], Rushmeier and Torrance [1990] and Chen et al.
[1991]). Once you understand both approaches, it is not difficult to create a hybrid rendering program.
46 Radiosity Theory
________________________________________________________________________
These, however, are future challenges for the motivated reader. In this book, our concern will be
The computer graphics community has traditionally divided the problem of modeling the flow of light
into two separate subproblems: local and global illumination. Local illumination is that light which travels
directly from the source to the surface being illuminated. In other words, direct illumination. Global
illumination is light that has been reflected, refracted, scattered, diffracted or whatever by one or more
To some extent, this division reflects the viewpoint and heritage of ray tracing techniques and their
emphasis on point sources and objects. If we approach the problem in terms of a photic field, the division
The radiosity approach is often characterized in the literature as a solution to the global illumination
problem. In a sense, it is. However, it is more productive to remember that ray tracing models objects,
Perhaps the greatest surprise in developing a radiosity rendering program comes from realizing that its
most difficult aspect has nothing whatsoever to do with light per se. The claim in Section 2.2 that “simple
geometry allows us to determine which patches are visible from each patch” is true, but only in an intuitive
Stated in more formal terms, the problem is this: knowing the radiant exitance of one Lambertian patch,
Figure 2.6 shows this problem in its simplest form. The relative position and orientation of the two
patches E i and E j is entirely arbitrary. Patch E i is a Lambertian emitter that is emitting some quantity of
flux Φ i , while patch E j is receiving a portion of its emitted flux, Φ ij . The dimensionless fraction
Φ ij Φ i is called the form factor from E i to E j , and is denoted as either FEi − Ej or, more compactly, Fij .
Radiosity Theory 47
________________________________________________________________________
Ej
ni
Φ ij
nj
Ei
The problem is deceptively simple. The total flux emitted by patch E i is Φ i = M i Ai , where M i is its
radiant exitance and Ai is its area. The flux received by E j is Φ ij = Fij Φ i . Unfortunately, calculating
Fij , can be an extremely difficult problem in analytic geometry. It is so difficult, in fact, that a general
solution was not found until 1993 (Schröder and Hanrahan [1993]), over 260 years after the problem was
We will devote all of Chapter Five to calculating the form factor between two patches in an
environment. In the following section, we will develop the underlying mathematics that we will later need.
A word of encouragement. While the following equations involve rudimentary calculus, you do not
need any knowledge of this subject to understand them. Look carefully: the terms of these equations are
Remember also that these equations describe physical concepts. As long as you understand these
Consider the two differential area (that is, infinitesimally small) patches dEi and dE j shown in Figure
2.7, where dE i is a Lambertian emitter. The fraction of flux emitted by dE i that is received by dE j is the
ni r
dω
θi
dEi
Recalling the discussion of solid angles and projected areas from the previous chapter, the solid angle
where dA j is the differential area of dE j . From Equation 1.4, the differential flux Φ(θ i ) leaving dE i in
where L(θ i ) is the radiance of dE i in the direction θ i . Since dE i is a Lambertian emitter, L(θ i ) = Li (a
constant) for all directions θ i . Substituting this and Equation 2.2 for dω gives:
Since dEi is a Lambertian emitter, the total emitted flux Φ i is given by Equation 1.16, or:
The form factor dFdEi − dEj for two differential area patches is thus:
Now, suppose that dE j is the Lambertian emitter and dEi is receiving its flux, namely Φ ji . We can
determine the reciprocal differential form factor dFdEj − dEi by simply reversing the patch subscripts in
Radiosity Theory 49
________________________________________________________________________
Equation 2.6. Doing so illustrates the reciprocity relation for form factors between any two differential
This is an extremely important result for radiosity theory. Why this is so will be seen in the next section and
Now the fun begins. We can compute the form factor FdEi − Ej from a differential Lambertian emitter
cosθ i cosθ j
FdEi − Ej = ∫ dFdEi−dEj = ∫ πr 2
dA j (2.8)
Aj Aj
Equation 2.8 is an area integral equation. What it says is this: divide the finite area E j into an infinite
number of differential areas, calculate their differential form factors, and add the results together to obtain
∞ cosθ in cosθ jn
FdEi− Ej = ∑ πr jn 2
dA jn
jn =1
where E j is divided into an infinite number of infinitesimal areas dE jn , each with its own angles θ in and
θ jn , and distance r jn .
This is all you need to know about integral calculus in order to understand radiosity theory!
dEjn
Ej
dEi
Figure 2.8 - Determining the form factor FdEi − Ej by area integration over E j
50 Radiosity Theory
________________________________________________________________________
Next, we need to determine the form factor FEi − dEj from a finite area Lambertian emitter E i with a
uniform radiance distribution across its surface to a differential area patch dE j . We note that the total flux
Φ i emitted by E i is:
Φ i = Mi Ai (2.9)
(Note that we are now integrating over the area of E i rather than E j .)
which yields:
dA j cosθ i cosθ j
FEi − dEj =
Ai ∫ πr 2
dAi (2.12)
Ai
Of course, our interest is in patch-to-patch form factors, or the form factor from a finite area E i to
another finite area E j . For this, we need to integrate over the areas of E i and E j . (In physical terms, we
need to consider the contribution of each differential area of E i to the illuminance of E j ). The flux
received by E j is then:
M i ∫ FdEi − Ej dAi
Ai 1
FEi − Ej =
M i Ai
=
Ai ∫ FdEi− Ej dAi (2.14)
Ai
From Equation 2.8, this yields the double area integral equation:
Radiosity Theory 51
________________________________________________________________________
1 cosθ i cosθ j
FEi − Ej =
Ai ∫∫ πr 2
dA j dAi (2.15)
Ai A j
The reciprocal form factor FEj − Ei is obtained by reversing the patch subscripts. This demonstrates that
the reciprocity relation (Equation 2.7) also holds true for finite area patches. In other words:
Ai Fij = A j F ji (2.16)
The importance of the reciprocity relation cannot be overstated. It says that if we can somehow
calculate the form factor Fij from an patch E i to another patch E j , then we can trivially calculate the
The above equations implicitly assume that the two patches E i and E j are fully visible to each other.
In a complex environment, two patches may be partially hidden by one or more occluding objects. If so,
then a suitable term must be added to account for the occlusions, such as:
1 cosθ i cosθ j
FEi − Ej =
Ai ∫∫ πr 2
HIDij dA j dAi (2.17)
Ai A j
where the term HIDij accounts for the possible occlusion of each point of patch E j as seen from each
point of patch E i .
We now know the relation between the geometry of two patches and their form factors. However,
equations involving double integration are often difficult to solve, and Equation 2.17 is no exception, with
or without occlusion. For our needs, there are no practical analytic solutions for this equation. This leaves
us with numerical integration, which will be the primary topic of Chapter Five.
As a final comment, Equation 2.17 does not consider the medium separating the two patches. In the
example of our empty room, the medium is air. Each ray of light traveling from patch to patch does so in a
straight line without absorption, refraction or scattering. In other words, the medium is considered to be
non-participating. This is not always the case; airborne dust, smoke and fog are a few examples of
participating media. These introduce complications that the radiosity approach can handle only with severe
computational difficulty (e.g., Rushmeier and Torrance [1987]). The issues involved are unfortunately well
To summarize:
1. The form factor from a differential area dEi to another differential area dE j is given by:
where θ i and θ j are the angles between a line connecting dEi and dE j and their respective surface
2. The form factor from a finite area patch E i to another finite area patch E j is given by:
1 cosθ i cosθ j
Fij =
Ai ∫∫ πr 2
dA j dAi
Ai A j
There are no practical analytic solutions for this equation. It must typically be solved using numerical
Ai Fij = A j F ji
4. The form factor concept assumes that the medium separating the patches does not absorb, refract or
A form factor is a dimensionless constant representing the fraction of flux emitted by one surface patch
that is received by another–and no more. It takes into account the shape and relative orientation of both
surfaces and the presence of any obstructions, but is otherwise independent of any surface properties.
Form factors were first developed for use in thermal and illumination engineering (see Section 2.7),
where they have been variously called shape, configuration, angle and view factors. The thermal
engineering literature is filled with discussions of form factor algebra, of which the reciprocity relation is
only one example. Most of these discussions relate to a time when form factors were calculated by hand.
Some properties, however, are still useful. For example, the summation relation states that:
Radiosity Theory 53
________________________________________________________________________
n
∑F
j =1
ij =1 (2.18)
for any patch E i in a closed environment with n patches. (A closed environment is one where all of the
flux emitted by any one patch must be received by one or more patches in the environment. In other words,
none of it can escape into space.) This summation includes the form factor Fii , which is defined as the
fraction of flux emitted by E i that is also directly received by E i . Clearly, Fii can only be nonzero if E i
is concave. Thus:
Fii ≠ 0 if E i is concave
Most radiosity methods model surfaces as two-dimensional grids of planar polygons (see Chapter
If patches Ei and E j are both Lambertian surfaces, the form factor Fij indicates the fraction of flux
emitted by E i that is received by E j . Similarly, the reciprocal form factor F ji indicates the fraction of
flux emitted by E j that is received by E i . However, form factors in themselves do not consider the flux
Remember that we are trying to determine the radiant exitance M i of each patch E i in an n-patch
environment. This exitance is clearly due to the flux initially emitted by the patch plus that reflected by it.
The reflected flux comes from all of the other patches E j visible to E i in the environment.
Consider any patch E j that is fully visible to E i . The flux leaving patch E j is Φ j = M j A j . The
fraction of this flux received by patch E i is Φ ji = M j A j F ji . Of this, the flux subsequently reflected by
where M ij is defined as the exitance of E i due to the flux received from E j . Using the reciprocity
To calculate the final exitance M i of patch E i , we must consider the flux received by E i from all
n
Mi = Moi + ρi ∑ M j Fij (2.21)
j =1
where M oi is the initial exitance of patch E i due to its emitted flux only. Rearranging terms results in:
n
M oi = M i − ρ i ∑ M j Fij (2.22)
j =1
We can express this equation for all the patches E1 through E n as a set of n simultaneous linear
equations:
M o = (I − T )M (2.25)
where I is the n × n identity matrix, M is the final n × 1 exitance vector, M o is the initial n × 1 exitance
vector, and T is an n × n matrix whose (i,j)th element is ρ i Fij . (If you find this terminology confusing, see
surface reflectances1, patch form factors and patch exitances. Solving these equations provides us with the
radiant exitance, radiance and ultimately luminance of every patch in the environment it describes.
It is evident that we first require the initial patch exitances M oi . Clearly, only those patches that emit
radiant flux will have non-zero values, which we can obtain from the description of the light sources.
Second, we must determine the form factors Fij for each pair of patches in the environment. Equation
2.22 implies that we must determine n 2 form factors for an environment with n patches. However, the
reciprocal form factors F ji can be trivially determined using the reciprocity relation, thus providing n(n-
1)/2 factors. Also, if the patches are flat or convex, the form factors Fii are zero. We are then left with:
form factors that must be determined from the patch geometries. To put this into perspective, a reasonably
complex environment with 10,000 patches requires some fifty million form factor determinations.
This is a very big number for desktop computers. Allowing four bytes per floating point number for
each form factor means we need some 190 megabytes of random access memory. Even if we had this
amount of memory, it would take a very long time to calculate 50 million numbers.
Fortunately, there are a variety of acceleration techniques for form factor determination that allow us to
circumvent these time and memory constraints. We will closely examine several of these techniques in
1
The reflectance of a surface generally varies according to the wavelength of light–this is what gives a
surface its color when viewed under “white light” illumination. Recalling the discussion of spectral
reflectance distribution from the previous chapter, we can divide the spectrum into three component
bands–red, green and blue–and determine an average spectral reflectance value for each band. (This
approach maps directly onto the familiar red-green-blue [RGB] color model of computer graphics. Other,
more sophisticated color models may use four or more spectral bands.) The radiosity equation can then be
On the other hand, there is no reason to be discouraged by these numbers. A personal desktop computer
with four megabytes of RAM is more than adequate for producing photorealistic images in a few minutes
or less. The image shown in Color Plate 1 took 40 seconds to render on a 66 MHz ‘486 IBM PC-AT clone.
Compare this to the hours of computation time often needed to render a single ray traced image!
Our problem then is to solve the radiosity equation for the final patch exitances M i . The matrix is
typically too large for direct methods such as Gaussian elimination. However, it is ideally suited for
iterative techniques such as the Jacobi and Gauss-Seidel methods (e.g., Golub and Van Loan [1983], Varga
[1962]). These methods are guaranteed to converge to a solution, since the matrix is always strictly
diagonally dominant for flat and convex patches. That is, ρ i Fij is always less than one, while Fii is
always zero. Furthermore, they converge very quickly, typically in six to eight iterations (Cohen and
Greenberg [1985]). We will examine these methods and a more powerful and useful variation called
This then is our basic radiosity algorithm: any one of several iterative techniques that solve the
radiosity equation. There are strong connections between these techniques and the physical flow of light in
an environment. Again, however, we will have to wait until Chapter Six before we can examine them in
detail.
Solving the radiosity equation for an environment is equivalent to determining its “energy balance”.
The amount of radiant flux reflected and absorbed by a patch must equal the amount of flux incident on its
surface. Flux is energy per unit time. If this balance is not maintained, the patch will steadily accumulate or
lose energy over time. The final solution to the radiosity equation therefore ensures that the flow of energy
The radiosity equation reveals why most radiosity methods are view-independent. Once we have
determined the form factors for an environment and solved for the final patch exitances, we can quickly
render a photorealistic image of the environment as a collection of 3-D polygons from any viewpoint. The
Radiosity Theory 57
________________________________________________________________________
solution to the radiosity equation thus describes the photic field permeating the environment. In doing so, it
allows us to move anywhere within this field and visualize it in any direction.
Equation 2.24 also shows that radiosity methods model light rather than objects. The radiosity equation
solves for the field of light–the photic field–within an environment. The only contribution made by the
objects comprising the environment is in defining the form factors and surface reflectances.
Recall from Section 1.9 that we can place an irradiance meter (Fig. 1.10) anywhere in physical space
and orient it in any direction. We can then measure the irradiance at that point in space. Here, we have a
virtual space defined by the description of patches in a computer file. Virtual or not, we can place a
differential patch with zero reflectance anywhere in this space and orient as we please. By determining the
form factors from the surrounding environment to this patch, we can calculate its irradiance.
We can similarly calculate the radiance at any point P in any direction in a virtual space with the
mathematical analogue of a radiance meter (Fig. 1.11). If we assume that the normal of our differential
patch intersects a point Q on some surface in the environment, the radiance at the point P in the given
direction is equal to the radiance of the ray of light emanating from the point Q and intersecting our patch.
A photic field is completely characterized by its radiance at any point and direction in the space
containing the field. In physical space, we can measure irradiance and radiance. In virtual space, we can
calculate these properties by solving the radiosity equation. Clearly then, radiosity models light.
One problem with the radiosity approach in general is that each patch must necessarily have a finite
area. An implicit assumption of the radiosity equation is that each patch then has a uniform irradiance and
radiant exitance distribution across its surface. This is not true in real life–illuminated surfaces exhibit
continuous gradations of radiance. Accurately modeling these smooth changes within the radiosity
equation requires the use of extremely small patches–and an ever larger matrix to solve. (There are a
number of elegant solutions to this problem. However, they are at the forefront of current radiosity research
and so beyond the scope of this book. The best that can be done is to provide a brief survey in Chapter
Eight.)
On a more positive note, it is evident that we need to determine the form factors for a particular
environment only once. The radiosity equation then allows us to quickly change the patch reflectances and
initial patch exitances without any further calculations other than solving the equation. In more colloquial
58 Radiosity Theory
________________________________________________________________________
terms, we can quickly dim, brighten and turn off lights, change the light source colors, change the surface
reflectance and color of any object in the environment, and even redefine which objects emit light. The
details of this magic–which can be difficult at best using ray tracing techniques–are also discussed in
Chapter Eight.
We need to discuss one more concept regarding radiosity theory, this time from computer science.
Actually, there are two closely related concepts to consider: time and space complexity.
Time complexity is a measure of how long it will take a computer to solve a problem using a specific
algorithm. It is not a measure of time per se, but rather a measure of how many elementary CPU operations
(add, multiply, divide and so forth) that must be performed to solve the problem. Similarly, space
complexity is a measure of the maximum amount of memory the algorithm requires in order to solve the
problem.
The radiosity equation solves for the final exitances of n patches. Solving this equation using (for
example) Gaussian elimination would require cn 3 operations, where c is a constant. However, constant
factors are not considered in complexity calculations. This ensures that the time and space complexity
measures are independent of the CPU or compiled program used to implement the algorithm. The time
complexity of Gaussian elimination is thus expressed as O(n 3 ) . This so-called “big-O” notation is thus a
measure of how much time is required to solve the problem relative to the number of patches n.
This also demonstrates one reason why Gaussian elimination is ill-suited to solving the radiosity
equation. If an environment with 10,000 patches requires t minutes to solve its corresponding radiosity
equation, an environment with 100,000 patches (which is a large but not unreasonable number for complex
architectural scenes) will require approximately one thousand times as long to solve. We might with clever
programming reduce this to five hundred times, but the basic issue remains–the Gaussian elimination
The Gauss-Seidel method is somewhat better in that its time complexity is O(n 2 ) for one iteration (see
Chapter Six for details). However, its space complexity is determined by the number of form factors that
must be stored in memory, which is approximately n 2 2 . Ignoring the constant factor, this is a space
Radiosity Theory 59
________________________________________________________________________
complexity of O(n 2 ) . Clearly, the Gauss-Seidel method also does not scale well to problems involving
How bad is this? Given an environment with 100,000 patches, solving the corresponding radiosity
equation using Gauss-Seidel iteration would require the solution of one billion floating point equations and
four gigabytes of memory. At least one iteration is required before an initial approximation of the final
The good news is that there are progressive refinement algorithms that solve the radiosity equation in
reasonable time. Those we will examine in Chapter Six have time and space complexities of O(n) . That is,
they need memory to store at most n form factors at any one time, and they can generate an initial image in
O(n) time. Subsequent images become progressively more refined, quickly approaching the photorealistic
While there are some disadvantages to these algorithms (see Chapter Six for details), they make
radiosity a practical approach to photorealistic image generation. More importantly, they scale well as the
The radiosity approach to photorealistic image generation was independently introduced to the
computer graphics community by Goral et al. [1984] and Nishita and Nakamae [1985], who based their
work on radiative heat transfer theory and thermal engineering techniques (e.g., Siegel and Howell [1992]).
At that time, various radiosity algorithms had been employed by the thermal engineering community for
some thirty years (e.g., Hottel [1954]). Hottel referred to his algorithm as the “zone method” (Hottel and
Sarofim [1967]), calling radiosity “an undesirable word”. However, Sparrow [1963] had earlier noted that
the algorithms proposed by Hottel [1954], Eckbert and Drake [1959] and Gebhart [1961] were essentially
equivalent, and had labeled them “radiosity methods”. By 1967, the term had become part of thermal
engineering’s lexicon.
This is not the beginning of the story, however. The fundamental equation of radiant flux transfer
between ideal diffuse surfaces (Equation 2.22) was apparently first recognized by Yamauti [1926] and
Buckley [1927]. It was Ziro Yamauti who first suggested solving this Fredholm integral of the second kind
60 Radiosity Theory
________________________________________________________________________
(e.g., Heckbert [1991]) using finite difference equations. His suggestion was formalized as a lighting
calculation technique in H.H. Higbie’s “Lighting Calculations” (Higbie [1934]). In the absence of
One exception was the work done by Parry Moon and Domina Eberle Spencer in the 1940s. They used
Yamauti’s technique (which they called the “interflection method”) to study lighting in empty rooms
(Moon and Spencer [1946]). Credit for the first photorealistic images created using radiosity methods must
go to Moon and Spencer–they exhibited synthetic photographs of empty rooms with luminous ceilings at
the 1946 National Technical Conference of the Illuminating Engineering Society of North America
(O’Brien and Howard [1959]). In the absence of computers, they calculated the luminance of each patch by
hand, cut out paper squares from Munsell color charts and pasted them together to form their images,
which were then photographed (Spencer [1993]). These photographs are reproduced in Moon and Spencer
[1948].
The introduction of digital computers in the 1950’s saw an international resurgence of interest in
Yamauti’s work. Numerous papers were presented to the illumination engineering community, including
those by Caracciolo [1952] , Centeno and Zagustin [1953], Dourgnon [1955], O’Brien [1955], Phillips
[1957] and O’Brien and Howard [1959]. Radiosity theory research has continued within this community to
The illumination and thermal engineering communities have variously referred to radiosity theory and
sum”, “zone”, “zonal cavity”, “zone analysis” and “radiative transfer”. Today, illumination engineers use
the term “radiative transfer theory”, while thermal engineers and the computer graphics community use
2.8 Conclusions
In modeling an environment, the radiosity theory we have developed makes the following assumptions:
While none of these assumptions represent fundamental constraints for radiosity theory, they make
solving the radiosity equation a computationally tractable problem for personal desktop computers.
There is of course much more that can be said about radiosity theory. For instance, reducing the patches
from finite to differential areas leads to the Neumann series and a generalization of the Jacobi iteration
method. It also leads to Fredholm integrals of the second kind, Galerkin and point collocation methods (an
adaptation of finite element techniques) and other mathematical esoterica. There are also much more
sophisticated methods for representing the radiosity equation. (See Chapter Eight for brief survey of the
relevant literature.)
Those readers interested in pursuing this topic further are strongly advised to read Cohen and Wallace
[1993]. There is no better reference text to be found on the subject. Be forewarned, however, that portions
of their text are aimed at graduate-level computer science students and researchers. You will need a strong
completely. On the other hand, it includes a wealth of technical details that, while beyond the scope of this
We have seen in this chapter that radiosity does in truth model light. We have also seen the elegant
simplicity of the approach, both in its intuitive concepts and in its mathematical foundations. With this
understanding, we can now develop the tools and techniques needed for a radiosity-based rendering
program.
References
Buckley, H. [1927]. “On the Radiation from the Inside of a Circular Cylinder”, Philosophical Magazine
(London) 4, 753.
Caracciolo, F.B. [1952]. “Calcolo dell’illuminazione artificiate degli ambienti chiusi”, L’Ingegnere 10
(Italy).
Global Illumination”, Computer Graphics 25:4 (Proc. ACM SIGGRAPH ‘91), 165-174.
Cohen, M.F. and D.P. Greenberg [1985]. “The Hemi-Cube - A Radiosity Solution for Complex
Cohen, M.F. and J. Wallace [1993]. Radiosity and Realistic Image Synthesis, Academic Press, San Diego,
CA.
Dourgnon, J. [1955]. “La Theorie des Reflexions Mutuelles Appliquee sur Calcul du Facteur
Eckbert, E.R.G. and R.M. Drake [1959]. Heat and Mass Transfer, McGraw-Hill, New York, NY.
DiLaura, D.L. and P. Franck [1993]. “On Setting Up and Solving Large Radiative Transfer Systems”, J.
Glassner, A.S., Ed. [1989]. An Introduction to Ray Tracing, Academic Press, San Diego, CA.
Golub, G.H. and C.F. Van Loan [1983]. Matrix Computations, John Hopkins University Press, Baltimore,
MD.
Goral, C.M., K.E. Torrance, D.P. Greenberg and B. Battaile [1984]. “Modeling the Interaction of Light
Between Diffuse Surfaces”, Computer Graphics 18:3 (Proc. ACM SIGGRAPH ‘84), 213 - 222.
Heckbert, P.S. [1991]. “Simulating Global Illumination Using Adaptive Meshing”, Ph.D. Thesis, U. of
Higbie, H.H. [1934]. Lighting Calculations, John Wiley & Sons, New York, NY.
Hottel, H.C. [1954]. “Radiant Heat Transmission”, in W.H. McAdams, Ed., Heat Transmission, McGraw-
Hottel, H.C. and A.F. Sarofim [1967]. Radiative Transfer, McGraw-Hill, New York, NY.
Moon, P. and D.E. Spencer [1946]. “Lighting Design by the Interflection Method”, J. Franklin Institute
242, 465.
Moon, P. and D.E. Spencer [1948]. Lighting Design, Addison-Wesley, Cambridge, MA.
Radiosity Theory 63
________________________________________________________________________
Nishita, T. and E. Nakamae [1985]. “Continuous Tone Representation of Three-Dimensional Objects
Taking Account of Shadows and Interreflection”, Computer Graphics 19:3 (Proc. ACM SIGGRAPH ‘85),
23 - 30.
O’Brien, P.F. [1955]. “Interreflections in Rooms by a Network Method”, J. Optical Society of America
O’Brien, P.F. and J.A. Howard [1959]. “Predetermination of Luminances by Finite Difference Equations”,
Phillips, R.O. [1957]. “The Calculation of Interreflected Illumination and Luminances in Rooms, Using an
Rushmeier, H.E. and K.E. Torrance [1987]. “The Zonal Method for Calculating Light Intensities in the
Presence of a Participating Medium”, Computer Graphics 21:4 (Proc. ACM SIGGRAPH ‘87), 293 - 302.
Rushmeier, H.E. and K.E. Torrance [1990]. “Extending the Radiosity Method to Include Specularly
Schröder, P. and P. Hanrahan [1993]. “On the Form Factor Between Two Polygons”, Computer Graphics
Siegel, R. and J.R. Howell [1992]. Thermal Radiation Heat Transfer, Third Edition, Hemisphere
Smits, B.E., J.R. Arvo and D.H. Salesin [1992]. “An Importance-Driven Radiosity Algorithm”, Computer
Sparrow, E.M. [1963]. “On the Calculation of Radiant Interchange Between Surfaces”, in W. Ibele, Ed.,
Varga, R.S. [1962]. Matrix Iterative Analysis, Prentice-Hall, Englewood Cliffs, NJ.
Verbeck, C.P. and D.P. Greenberg [1984]. “A Comprehensive Light-Source Description for Computer
Wallace, J.R., M.F. Cohen and D.P. Greenberg [1987]. “A Two-Pass Solution to the Rendering Equation:
A Synthesis of Ray Tracing and Radiosity Methods”, Computer Graphics 21:4 (Proc. ACM SIGGRAPH
II
Tools of the Trade
............................
But what Trade art thou? Answer me directly ...
Julius Caesar
Wm. Shakespeare, 1601
The tools of the trade are one: a graphics package to manage and display three-dimensional polygons.
Chapter Three examines polygon representations and view transformations. Chapter Four reviews viewing
systems, polygon clipping, hidden surface elimination, scan conversion and incremental shading
algorithms.
These tools are not part of the radiosity approach per se, and may be available as callable library
functions in certain environments. Even so, it's always a good idea to know your tools before embarking on
a major project.
Chapter 3
Building An Environment
3.0 Introduction
Having laid the theoretical foundations of radiosity, we can now begin writing a radiosity-based
rendering program. From Chapter Two, we see that our program will have to perform the following tasks:
In this and the following chapter we consider the tasks of building and rendering environments. These
are not part of the radiosity approach per se. However, our photic fields are due to and defined by their
environments. To model a field of light then, we first need to model its environment. For most radiosity
Our tools for doing so–that is, algorithms and data structures–include vector mathematics, view
transformations, polygon clipping, hidden surface elimination and polygon scan conversion. These are
familiar tools of the trade for 3-D computer graphics programming of any sort. Indeed, many high-end
graphics programming environments include them as callable library functions, while some desktop
workstations and advanced video display subsystems offer them as built-in hardware or firmware features.
In general however, we must assume that they are not available. We shall build–and in doing so better
The goal of this particular chapter is to develop a 3-D graphics toolkit for building environments. The
coverage given the underlying algorithms and data structures will be neither rigorous nor comprehensive;
to do so would fill the remainder of this book and more. Instead, the emphasis will be on developing a set
of C++ classes sufficient to model collections of 3-D polygons. Those readers interested in a more
definitive approach to 3-D computer graphics are encouraged to consult one of the many excellent
reference texts, including Foley et al. [1990], Hill [1990], Watt [1989] and Rogers and Adams [1976].
We must also take a minimalist approach to user interface design. In particular, we will develop a
simple parsing program that reads an ASCII text file and translates it into a representation of an
environment in memory. The complexity of our environments will therefore be limited to those we can
Of course, we will ultimately want to create complex and visually interesting environments consisting
of thousands to hundreds of thousands of polygons. In practical terms, this is a task best performed with a
commercial computer-aided drafting (CAD) program such as AutoCAD. Fortunately, we do not need most
of the features of this expensive product; there are more reasonably priced CAD programs that offer all of
the functionality we need. Specifically, we require three features: 1) the ability to draw in three
dimensions; 2) a command that renders curved surfaces as polygon meshes; and 3) the ability to generate
The DXF graphics file format is a de facto standard in the CAD industry. While it has several
deficiencies that limit its usefulness for radiosity rendering applications, these can be overcome with some
discipline on the part of the draftsperson. We can create complex environments using a commercial CAD
program, generate a DXF file, and use it as a basis for generating input files for our radiosity renderer.
We will develop a data file format later in this chapter that is optimized for radiosity applications. A
program (including an explanatory text file and full C++ source code) that partially converts DXF files into
this format is included with the diskette accompanying this book. That, however, is later; right now we
We begin with an include file that defines a few global typedefs and constants. Yes, it’s trivial and
#ifndef _GENERAL_H
#define _GENERAL_H
#ifndef _NOT_WIN_APP
#define STRICT // Win32 API compatibility
#include <windows.h> // MS-Windows application
#endif
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#ifdef _NOT_WIN_APP
#define FALSE 0
#define TRUE 1
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
#define PI 3.141592654
#define MIN_VALUE 1.0e-10 // Minimum value
#define MAX_VALUE 1.0e10 // Maximum value
#endif
Listing 3.1 - GENERAL.H
Building An Environment 69
________________________________________________________________________
GENERAL.H assumes MS-Windows 3.1 or Windows NT to be its target environment. If you have
another environment in mind, be sure to define _NOT_WINAPP somewhere for your compiler. (Most C++
compilers allow you to specify global definitions from the command line or workplace shell.)
Next, we need two C++ classes to define and manipulate 3-D points and vectors. Many C programmers
While this works, it obscures the mathematical definition of a vector. In particular, a point defines a
position in space; a vector defines a direction. This has important consequences for properly defined point
and vector classes. There are mathematical operations we can perform on points that have no meaning for
vectors, and vice versa. For instance, we can determine the distance between two points, but not vectors.
Thus, a vector class cannot–or at least should not–be derived from a point class, despite their similarities.
On the other hand, we can and should define an abstract base class for points and vectors that
#ifndef _VECTOR3_H
#define _VECTOR3_H
#include <math.h>
#include "general.h"
public:
Space3() { };
Space3( double xval, double yval, double zval )
{
x = (float) xval;
y = (float) yval;
z = (float) zval;
}
70 Building An Environment
________________________________________________________________________
// Assign scalar
Vector3 &operator=( double s )
{
x = (float) s;
y = (float) s;
z = (float) s;
return *this;
}
Building An Environment 71
________________________________________________________________________
// Add/assign vector v
Vector3 &operator+=( Vector3 &v )
{ x += v.x; y += v.y; z += v.z; return *this; }
// Subtract/assign vector v
Vector3 &operator-=( Vector3 &v )
{ x -= v.x; y -= v.y; z -= v.z; return *this; }
// Multiply/assign by scalar s
Vector3 &operator*=( double s )
{
x *= (float) s;
y *= (float) s;
z *= (float) s;
return *this;
}
// Divide/assign by scalar s
Vector3 &operator/=( double s )
{
x /= (float) s;
y /= (float) s;
z /= (float) s;
return *this;
}
// Negation
Vector3 operator-()
{
Vector3 temp; // Temporary 3-D vector
temp.x = -x;
temp.y = -y;
temp.z = -z;
return temp;
}
return temp;
}
return temp;
}
return temp;
}
return temp;
}
// Normalize
Vector3 &Norm()
{
double len = Length();
x /= (float) len;
y /= (float) len;
z /= (float) len;
return *this;
}
return temp;
}
};
#endif
Listing 3.2 - VECTOR3.H
and:
#include "vector3.h"
return temp;
}
The above Vector3 class includes two friend functions–Dot and Cross–that may not be familiar to you.
They aren’t difficult to understand, and they are incredibly useful in computer graphics. Remembering that
vectors represent directions, the dot product of two vectors v1 and v2 is related to the cosine of the angle θ
v 1 ⋅ v 2 = v 1 v 2 cos θ
where v1 and v 2 indicate the lengths of vectors v1 and v2 respectively. If both vectors are normalized
(i.e., have unit lengths), then their dot product is equal to the cosine of the angle θ between them. A dot
The dot product of two vectors is easily calculated as the sum of the products of their component co-
ordinates, or:
74 Building An Environment
________________________________________________________________________
The cross product of two vectors v1 and v2 is a third vector vC in a direction perpendicular to the plane
of v1 and v2 and with a length vC equal to the area of the parallelogram described by them (Fig. 3.2b).
v1 × v 2 = v C
v C = v 1 v 2 sin θ
v Cx = v1y ∗ v 2z − v1z ∗ v 2y
v Cy = v1z ∗ v2x − v1x ∗ v2z
v Cz = v1x ∗ v2y − v1y ∗ v2x
The direction of the cross product vector can be quickly determined without mathematics using the
right-hand rule mnemonic. Looking at Figure 3.2b, imagine grasping vC in your right hand such that your
thumb points in its direction. Your fingers will then always curl around vC from v1 to v2. (This assumes a
right-handed co-ordinate system; a left-handed co-ordinate system would have vC pointing in the opposite
direction.)
Finally, the class constructors Vector3( Point3 & ) and Vector3( Point3 &, Point3 & ) define bound
vectors, which have both a direction and a starting position. There is no need to create a separate data type
for bound vectors, since we can model them using our Vector3 class. Their starting positions will be
v
c
v2
v2
θ θ
v1
v1
While our Vector3 class is based on the commonly used rectangular co-ordinate system, it is sometimes
more convenient and even necessary to specify 3-D vectors in spherical co-ordinates. For example, we will
need in Chapter Four to specify a direction of view from a point in the environment. Spherical co-ordinates
allow a more intuitive user interface for this task, particularly if the direction must be specified from the
keyboard.
We could store both rectangular and spherical co-ordinates in the Vector3 class. However, this
redundant information would consume inordinate amounts of memory if applied to every Vector3 object.
Since we shall rarely need both co-ordinate types for the same object, we shall instead define a separate
C++ class for spherical co-ordinate vectors and convert between co-ordinate systems as necessary.
Converting from spherical to rectangular co-ordinates is the easier of the two tasks. Given the length
r , the horizontal angle (or colatitude) θ, and the vertical angle (or azimuth) φ of a vector r (Fig. 3.3), its
{ }
equivalent rectangular co-ordinates rx , ry , rz can be determined from:
rx = r sin φ cos θ
ry = r sin φ sin θ (3.1)
rz = r cos φ
Determining the spherical co-ordinates of a vector r from its rectangular representation requires a bit
r = rx 2 + ry 2 + rz 2
φ = arccos(rz r ) (3.2)
θ = arctan(ry , rx )
76 Building An Environment
________________________________________________________________________
r
φ
x θ
where r is the vector length and the function arctan(y,x) is the two-argument form of the arctangent
function. It returns:
arctan(y/x) if x > 0
arctan(y/x) + π if x < 0
π2 if x = 0 and y > 0
−π 2 if x = 0 and y < 0
This function is available in most C++ implementations as the standard library function atan(y, x).
#ifndef _SPHERIC3_H
#define _SPHERIC3_H
#include "vector3.h"
public:
Spheric3( double len = 1.0, double h = 0.0, double v =
0.0 )
{ length = len; horz = h; vert = v; }
#endif
Listing 3.4 - SPHERIC3.H
3.4 Polygons
We saw in the previous chapter that the radiosity approach subdivides each surface of an environment
into a mesh of elements called “patches”, where each patch is a three-dimensional polygon. A polygon
Most 3-D CAD programs model curved surfaces as polygon meshes. Unfortunately, many of them do
not allow the user to specify which side of the surface is exterior to an object. Clearly only one side of the
surface is visible. Nevertheless, programs such as AutoCAD can only distinguish sides (and their
subsequent visibility) by inference from the surface’s placement in an environment. This is a nuisance, to
say the least. For our purposes, we will consider each surface and its constituent polygons to have two
Polygons can be flat (i.e., planar), convex or concave (i.e., nonplanar). Unfortunately, nonplanarity
introduces a number of unwelcome complexities. For instance, the direction of the normal vector varies
across the polygon surface, and the curve of the surface must be represented somehow. Since most
radiosity methods assume flat patches, we will ignore these complexities and consider only planar
polygons.
78 Building An Environment
________________________________________________________________________
Surface
Polygon
A planar polygon can be uniquely represented by an ordered list of vertices (Fig. 3.5), where by
definition the vertices all lie on the same two-dimensional plane. Looking at the visible side of the polygon,
the vertices are ordered such that they follow a counterclockwise path around the polygon edges. This is
essential! We can then use the vertices to define the polygon normal n. If we define vectors v 1 and v 2 as
p1 − p 0 and p 3 − p 0 respectively, then n is given by the cross product of the two vectors:
n = v1 × v 2 (3.3)
While a polygon can have any number of vertices, it becomes awkward to manage the data structures
needed to represent them. For our purposes, we need consider only two polygon primitives: triangles and
quadrilaterals. All of our polygons will have four vertices–triangles will be represented as having equal
third and fourth vertices. We will also assume that our polygons are simple (i.e., none of their edges cross
one another, thereby forming two triangular polygons from a quadrilateral polygon) and that they are not
p0(x,y,z) v2(x,y,z)
p3(x,y,z)
n
v1(x,y,z)
Ordered List Representation
{ p0, p1, p2, p3 }
p1(x,y,z)
p2(x,y,z)
A polygon can also be convex or concave in another sense, as shown in Figure 3.6. A convex planar
polygon is one in which you can stretch an imaginary rubber band around it and not have any gaps between
Concave planar polygons are somewhat more difficult to deal with in computer graphics. Rather than
address these difficulties in this book, we shall simply issue a fiat to ourselves: all quadrilateral polygons
must be convex.
Figure 3.6a - Convex planar polygon Figure 3.6b - Concave planar polygon
Since a polygon only has one visible side (its face), we can ask whether we can see it from a given
point in space. A visibility test called “backface elimination” or “culling” allows us to quickly identify
which polygons face away from our viewing position (Fig. 3.7).
80 Building An Environment
________________________________________________________________________
Polygon face
and the line of sight vector s is less than ±90 degrees. Recalling the formula for the dot product of two
vectors v 1 and v 2 (and noting that s is pointing in the opposite direction from n), it’s evident that the
angle θ between n and s will be less than ±90 degrees only if the their dot product is less than zero. Thus:
IF n ⋅ s = 0
Polygon is visible
ELSE
Polygon is not visible
ENDIF
Our dot product function Vector3::Dot requires only three multiply and two addition operations,
making polygon visibility determination very fast. This is an important consideration, since we will be
viewing many thousands of polygons in a complex 3-D environment. Backface culling allows us to quickly
eliminate roughly half the polygons from further consideration before performing the computationally
expensive operations of view transformation, clipping, hidden surface elimination and scan conversion (to
We can now see why we must define the vertices of a polygon in counterclockwise order–doing so
ensures that the polygon normal points away from the visible face. Without this ordering, our simple
We shall later need to know the area of a polygon. If we limit our attention to planar triangles (Fig.
A = v1 × v 2 2 (3.4)
where A is the area and v1 and v2 are vectors defined by the polygon vertices. (Any convex planar
Why this works becomes clear when we consider the physical interpretation of the cross product
operation. Remember that the magnitude of the cross product of two vectors is equal to the area of the
parallelogram described by them (Fig 3.2b). Our triangle is exactly one half of the parallelogram,
vc
p2
v2
v1 p1
p0
We shall also later need to know the center of a polygon. More specifically, we will need to know its
center of gravity, or centroid. Imagine a physical polygon cut from a piece of stiff, flat cardboard. It will
m
C= ∑ ri m (3.5)
i =1
p1
r1
p2
C
p0
r2
p3
r0
r3
Origin
The centroid C is a 3-D point located on the surface of the polygon. However, we can only add vectors,
so Equation 3.5 considers C to be a bound vector from the origin to the centroid. Its x-y-z co-ordinates are
the same as the centroid’s position in 3-D space, and so we can simply copy them to a Point3 object after
While we can model a curved surface as an array of planar polygons, we have to pay careful attention
to the surface normal. The direction of the true surface normal varies continuously as we move across a
curved surface. Each polygon normal, on the other hand, has a constant direction. Moving across the
polygonal approximation of the surface results in discontinuous changes in the direction of the surface
normal.
These discontinuities are of particular concern in ray tracing applications, where the ray tracer needs to
know the true normal of a specular surface (or a close approximation) in order to determine the direction of
a reflected ray. In contrast, most radiosity applications are concerned with diffuse surfaces. As such, they
There are radiosity applications, however, where it is necessary to know the surface normal at the
polygon vertices (see Chapter Five). Looking at Figure 3.10, we can approximate the true normal at the
vertex as the average of the normals for the polygons sharing it. In other words, we have:
m
nv = ∑ ni m (3.6)
i =1
where n v is the vertex normal and n i is the normal of the ith of m polygons.
nv
n3
n4 n2
n1
Figure 3.10 - Determining the vertex normal from adjacent polygon normals
We have so far represented polygons as 3-D geometrical objects with no intrinsic physical properties.
To be useful for anything other than wireframe models, we need to add surface reflectances to our model.
As was noted in Chapter One, the physical reflectance properties of a surface usually depend on
wavelength. However, they can be approximated by specifying the average spectral reflectance within
three or more color bands. Subtle color aliasing effects can occur in photorealistic renderings when only
three bands are used (Hall [1989]). However, these are usually apparent only when compared to the
physical objects they are modeling. For most purposes, a choice of red, green and blue bands is sufficient.
Together, the three reflectance values define the intrinsic color of the polygon surface.
How many bits for each value? Under optimal viewing conditions, we can distinguish at most several
hundred thousand colors. This implies that the 16.7 million colors offered by a 24-bit representation (using
one byte for each primary color) are quite adequate for display purposes.
Spectral radiant exitance, on the other hand, requires much greater precision. Our radiosity methods
require us to repeatedly update a polygon’s exitance, possibly as many as several hundred times in the
84 Building An Environment
________________________________________________________________________
course of solving the radiosity equation. Each update requires that we multiply the flux received by the
polygon by its average spectral reflectance for each color band. A single byte per spectral band is clearly
We may also want to create and display grayscale images. Since our eyes are more sensitive to green
light than they are to red or blue (Fig. 1.7), we will need to take a weighted average of the three color band
where value is the grayscale value and R, G and B are the red, green and blue color band values
respectively. Assigning this value to each color band produces a monochromatic shade of gray.
We may also want to display pseudocolor images, where each color represents a given range of surface
exitance values. We have an almost infinite variety of choices when it comes assigning colors. One simple
but useful approach is offered by the color scheme shown in Figure 3.11, where the colors range from blue
through green to red in order of increasing exitance. This allows us to perform color mapping on the fly
1
R
G 0.8
B
0.6 Red
v
Green
a
0.4 Blue
l
u
e 0.2
s
0
0 0.25 0.5 0.75 1
Grayscale value
The following ColorRGB and Spectra classes incorporates these ideas in a simple but effective
representation:
#ifndef _COLOR_H
#define _COLOR_H
#include <limits.h>
#include "general.h"
Building An Environment 85
________________________________________________________________________
public:
float GetBlueBand() { return blue_band; }
float GetGreenBand() { return green_band; }
float GetRedBand() { return red_band; }
void Reset()
{ red_band = green_band = blue_band = 0.0; }
void SetBlueBand( float b ) { blue_band = b; }
void SetGreenBand( float g ) { green_band = g; }
void SetRedBand( float r ) { red_band = r; }
return *this;
}
return *this;
}
// Blend colors
friend Spectra Blend( Spectra &s1, Spectra &s2, double
alpha )
{
Spectra temp; // Temporary spectrum
// Linear interpolation
temp.red_band = s1.red_band + (s2.red_band -
s1.red_band) * (float) alpha;
temp.green_band = s1.green_band + (s2.green_band -
s1.green_band) * (float) alpha;
temp.blue_band = s1.blue_band + (s2.blue_band -
s1.blue_band) * (float) alpha;
return temp;
}
public:
BYTE GetBlue() { return blue; }
BYTE GetGreen() { return green; }
BYTE GetRed() { return red; }
void SetBlue( BYTE b ) { blue = b; }
void SetGreen( BYTE g ) { green = g; }
void SetRed( BYTE r ) { red = r; }
#endif
Listing 3.5 - COLOR.H
Spectra is used for two purposes: to represent surface reflectances and average spectral radiant
exitances. When used for surface reflectance, the three color band values red_band, green_band and
blue_band must range from 0.0 to 1.0 inclusive. For average spectral radiant exitance, however, they can
assume any non-negative number. This allows us to add bright light source patches to an environment
without adjusting the exitances of existing light source patches. However, ColorRGB implicitly assumes
that red_band, green_band and blue_band range from 0.0 to 1.0. This means that we need to appropriately
scale all Spectra objects before calling ColorRGB::SetColor to convert them to a 24-bit RGB
representation. (The same applies for ColorRGB::SetMono and ColorRGB::SetPseudo.) To do this, each
Spectra object is examined to determine the maximum color band value for the set of objects (by calling
Spectra::GetMaxColor). The inverse of this value becomes the parameter to be passed to Spectra::Scale.
(More sophisticated conversion algorithms can also be used–see for example Hall [1989]).
Specifying a color as a 24-bit ColorRGB object is not enough for photorealistic display purposes. Most
video monitors (monochrome and color) , photographic films, four-color printing processes and other
Consider, for example, a typical color video monitor. The video display adapter in our computer
converts each color value into a discrete voltage for the three electron guns inside the cathode ray tubes.
88 Building An Environment
________________________________________________________________________
The resultant beams of electrons are directed to a pixel on the screen, where rare earth phosphors convert
their energy into the visible (i.e., red, green and blue) light that we see.
The problem is that there is a nonlinear relation between electron gun voltage and light output. This
L = kv γ (3.8)
where L is the phosphor spectral radiance, k is a constant, v is the input voltage to the electron gun, and the
exponent γ (pronounced “gamma”) determines the degree of nonlinearity. The value of this exponent varies
between monitors, but generally ranges from 2.2 to 2.5 (Foley et al. [1990]). In visual terms, a displayed
image displayed “as is” will appear to have too much contrast.
We can compensate for this nonlinear behavior through gamma correction. Given an input value vinput
(such as one of the members of a ColorRGB object), the linearized output value v output is given by:
1
vinput γ
voutput =
(3.9)
k
In critical color rendition applications, it may be necessary to experimentally determine a value of γ for
each primary color. In most instances, however, the same gamma correction can be applied equally to all
Since each ColorRGB member has a limited range of discrete values it can assume, it will be
convenient to precompute the equivalent output values and store them in a lookup table. This gives us:
#ifndef _GAMMA_H
#define _GAMMA_H
#include "color.h"
void InitTable()
Building An Environment 89
________________________________________________________________________
{
int i; // Loop index
public:
Gamma( double g = 2.2 )
{
g_value = g;
InitTable();
}
#endif
Listing 3.6 - GAMMA.H
and:
#include "gamma.h"
Actually, this class can provide more than gamma correction. The defined constants G_Domain and
G_Range specifies the range of the input and output values respectively. For ColorRGB, these are both
assumed to be 8-bit BYTE data types. However, some video display adapters (the IBM-PC’s VGA and 256-
color SuperVGA adapters, for example) only support six bits per primary color. Gamma can support these
devices if G_Range is redefined to be 64. The gamma correction lookup table values will then be
calculated such that the output values are with the range 0 to 63.
90 Building An Environment
________________________________________________________________________
The g_value member specifies the gamma correction to be applied, and defaults to 2.2. Other values
can be used for specific video monitors or other display media. It can be updated at any time by calling
Gamma is something of an oddball class. It belongs with ColorRGB, but it has nothing to do with
building an environment. It’s one of the joys of trying to shoehorn the real world into a hierarchy of neatly
defined classes: sometimes you have bits and pieces left over. Gamma is one of those pieces. Having
While 24-bit color display adapters with their 16.7 million colors are becoming increasingly common,
there are still many personal desktop computers without such capabilities. Since our radiosity renderer will
inherently generate 24-bit color images, we need to consider color reduction techniques that match our
Many of the more recent personal computers support a maximum of 32,768 or 65,536 colors. This
includes those with display adapters that offer 24-bit support for their lower resolution modes only.
Displaying 24-bit color images is possible if the software reduces the gamut of image colors to those that
can be displayed. In most cases, this is done by simply dividing the 16.7 million possible colors into 32,768
or 65,536 equally-spaced regions. Unfortunately, this usually results in annoying color bands appearing on
One solution is to employ one of several dithering techniques (e.g., Foley et al. [1990]). While often
effective, a discussion of color dithering algorithms is beyond the scope of this book (see Thomas and
Bogart [1991] for two examples, including C source code). Fortunately, we can use a simpler approach that
The basic principle is that the human eye is fairly insensitive to random pixel-by-pixel variations in
color or shading–we tend to see the average color instead. This is useful: we can introduce a small amount
of random “noise” to an image without noticeably degrading its appearance. At worst, the image appears to
have a somewhat “grainy” appearance, much like a photograph taken with a high-speed color film.
Building An Environment 91
________________________________________________________________________
By itself, adding noise does nothing to improve the appearance a displayed 24-bit color image.
However, the noise very effectively masks the color bands we would otherwise see. Given a choice,
observers invariably choose images with random noise over those with visible color banding.
Bragg [1992] presented a simple color reduction “filter” that capitalizes on this effect by jittering each
color component of an RGB pixel by a small random amount. This random noise is weighted such that the
average RGB color of any small group of pixels closely approximates the average color of their original
24-bit colors. Each RGB component is then masked to produce a 5-bit value, resulting in a total of 32,768
In detail, Bragg’s algorithm begins by dividing each 8-bit RGB color component value into 32 equally-
spaced regions and saving the remainder. Each region represents one of 32 output values. This value is
divided by 8; its remainder is in the range of 0 to 7. A random number in the range of 0 to 8 is then chosen.
If the second remainder is less than or equal to this number, the original 8-bit RGB component value is
incremented by 8. The effect of this procedure is to produce a randomized component value that is
The component value is further randomized by adding another small random value. The range of this
noise is user-defined by a “noise level” parameter that can range from 0 (no noise) to 8. A value of 1 or 2 is
sufficient to mask any color banding in most images; 8 produces very grainy images. Finally, a 5-bit output
#ifndef _C_JITTER_H
#define _C_JITTER_H
#include <stdlib.h>
#include "color.h"
public:
ColorJitter();
~ColorJitter();
#endif
Listing 3.8 - C_JITTER.H
and:
#include "c_jitter.h"
status = TRUE;
if (pxrand != NULL)
delete [] pxrand;
if (pyrand != NULL)
delete [] pyrand;
}
The ColorJitter class constructor precalculates and stores random jitter values in three lookup tables.
The table lookup functions JitterX and JitterY are admittedly somewhat convoluted. However, they have
the valuable property that the returned random number always has the same magnitude for any given pair
of pixel co-ordinates (x and y). This is important if ColorJitter is to be used to color reduce a sequence of
24-bit images for an animation. Using rand for each jitter value would result in the animated sequence
displaying a highly objectionable amount of “snow”. A detailed explanation and analysis of the lookup
What about older-model desktop computers that offer a maximum of 256 colors? Attempting to display
24-bit color images with these systems usually produces unacceptably garish and posterized results.
Nevertheless, it is evident that they are quite capable of displaying reasonable quality photorealistic
images.
Building An Environment 95
________________________________________________________________________
The saving grace of these computers is that their 256-color display adapters feature programmable
palettes. At six bits per color channel, there are 262,144 ( 64 × 64 × 64 ) colors to choose from. Since most
scenes are dominated by relatively few colors, it often takes less than 256 colors to provide a reasonable
Unfortunately, this is not a simple problem. Basically, we need to group common colors together and
represent them with one averaged color for each group. There are several color quantization techniques
that we can use, but a full discussion would take us too far afield. The diskette accompanying this book
includes a text file that discusses the octree color quantization algorithm (Gervautz and Purgathofer [1990])
and presents full C++ source code for a standalone color quantization utility. Here, we simply note the
Many ray tracing and CAD programs model complex 3-D environments as a hierarchy of objects,
volumes, surfaces and polygons. That is, an environment consists of a collection of objects, each of which
is modeled as a set of volume primitives such as boxes, spheres, cylinders and tori. In the case of CAD
programs, the merged surfaces of these volumes are then approximated with polygon meshes.
This approach has numerous advantages. For example, we might be modeling an office that has several
identical tables located about the room. A hierarchical representation allows us to model one table as an
entity. Each table in the room then becomes an instance of this entity. We can scale, rotate and translate
these instances as required (see Section 3.11) to individually position them in the room.
The approach we must take is regrettably more common. Developing a 3-D CAD interface that would
enable us to interactively model objects as volume primitives and polygon meshes is beyond the scope of
this book. Instead, we will have to model entities as a hierarchy of surfaces and polygons by hand. (Again
however, the accompanying diskette includes a data file translator for those readers with access to a 3-D
CAD program that can generate AutoCAD-compatible DXF files. There is still a considerable amount of
hand work that has to be done, but at least you are spared the necessity of having to manually enter
Recalling Section 2.2, we realize that the solution of the radiosity equation is expressed in terms of
patch (polygon) exitances. Now exitance–as was emphasized in Section 1.9–is not a property of a polygon
surface per se. Nevertheless, it will be convenient to store this information as a Spectra data type in the
polygon data structure. This will allow us to solve the radiosity equation independently for each of the
We will also see in Chapter Five that the time needed to solve the radiosity algorithm can be reduced by
modeling surfaces as a two-level hierarchy of polygons. A surface is first divided into a coarse grid of
polygons called patches. Each patch is then divided into a smaller grid of polygons called elements (Fig.
3.12).
Patch
Element
Other radiosity methods go further, dividing the surfaces into a multi-level hierarchy of polygons; the
reasons for this will be explained in Chapter Eight. For our purposes, a two-level hierarchy is sufficient.
There are many possible ways to describe polygons in a complex 3-D environment. Cohen et al. [1986],
for example, used a winged-edge data structure to provide access to polygon data in constant time.
Winged-edge data structures (e.g., Baumgart [1975]) offer several computational advantages when
manipulating polygons. They are also quite complex and difficult to implement properly (Glassner [1991]).
We will therefore limit our attention to a simpler but still efficient and flexible linked list representation.
It is very important to ensure that we can access the information we need in an environment with a
minimum of effort. This leads to the linked list representation shown in Figure 3.13.
Building An Environment 97
________________________________________________________________________
Vertex
An environment consists of a linked list of instances. The purpose of the links are as follows:
Next Instance
Next Surface
Next Patch
Next Element
Next vertex
Next ElemList
To expand on this explanation, all the vertices defining a surface are stored once in memory as a linked
list. This list is owned by the instance, which provides it with access to the vertices without having to
The patches and elements each point to three or four of these vertices, depending on whether they
represent triangles or quadrilaterals. Each vertex is shared by one or more elements and patches.
We will later want to access the attributes of the elements sharing a given vertex as quickly as possible.
Each vertex therefore points to a linked list of ElemList objects, each of which points to an element sharing
Finally, each element has a pointer to its parent patch, and each patch has a pointer to its parent surface.
These will be used to access patch and surface attributes from an element without having to traverse the
One disadvantage of linked lists is that they have a voracious appetite for memory, especially when
relatively small objects must be allocated from C++’s free store (also referred to as global or heap
memory). This concerns memory management, which is discussed at length in a text file on the diskette
accompanying this book. For our current purposes, we can allocate and release memory as required using
C++’s default new and delete operators. A production-quality program, however, should really provide its
Beginning at the bottom of our hierarchy of entities, surfaces and polygons, we can represent patches
#ifndef _PATCH3_H
#define _PATCH3_H
#include "vector3.h"
#include "color.h"
public:
ElemList( Element3 *pe, ElemList *pel )
{ pelem = pe; pnext = pel; }
Building An Environment 99
________________________________________________________________________
Element3 *GetElemPtr() { return pelem; }
ElemList *GetNext() { return pnext; }
};
public:
PatchList( Patch3 *pp, PatchList *ppl )
{ ppatch = pp; pnext = ppl; }
public:
Vertex3( Point3 &coord )
{
posn = coord;
normal = 0.0;
pelhd = NULL;
pnext = NULL;
exitance.Reset();
}
~Vertex3()
{
ElemList *pel = pelhd;
ElemList *pelnext;
public:
Element3( Vertex3 *pvtx[4], Patch3 *pp )
{
int index; // Array index
ppatch = pp;
area = 0.0;
flags = (BYTE) 0;
pnext = NULL;
exitance.Reset();
public:
Patch3( Vertex3 *pvtx[4], Surface3 *ps ) :
Element3( pvtx, NULL )
{
pelhd = NULL;
psurf = ps;
}
Building An Environment 101
________________________________________________________________________
~Patch3()
{
Element3 *pe = pelhd;
Element3 *penext;
double GetUnsentFlux()
{
return ((exitance.GetRedBand() +
exitance.GetGreenBand() + exitance.GetBlueBand())
* (double) area);
}
#endif
Listing 3.10 - PATCH3.H
and:
#include "patch3.h"
if (IsQuad() == TRUE)
{
Vector3 vc(pvertex[3]->GetPosn(),
pvertex[0]->GetPosn());
num_vert = GetNumVert();
cv /= (double) num_vert;
ElemList is self-explanatory: each object of the class provides a singly linked list element that points to
an Element3 object and the next ElemList element. ElemList::GetNext returns NULL for the last element of
the list. PatchList provides the same services for Patch3 objects. We don’t use linked lists of patches in our
environment data structure, but we will need them later on in this chapter when we build environments
The Vertex3 class is slightly more interesting. Its private data members include the vertex co-ordinates
and normal, its color (to be used in the next chapter), a pointer to a linked list of elements that share the
vertex and a pointer to the next Vertex3 list element. Again, Vertex3::GetNext returns NULL for the last
Vertex3::CalcNormal calculates the vertex normal according to Equation 3.6; normalizing the sum of
the polygon normals is equivalent to dividing by the number of polygons sharing the vertex. These normals
are not available when the Vertex3 object is constructed, which is why CalcNormal is not part of the class
constructor.
The Element3 class can represent triangular and quadrilateral polygons. Each Element3 object is a
singly linked list element whose private data members include the polygon area and normal, a quadrilateral
flag, an array of four Vertex3 pointers, a pointer to its parent patch, and a pointer to the next Element3 list
element. If the polygon is a triangle, the third and fourth Vertex3 pointers should be equal; otherwise
Element3::CalcArea and Element3::CalcNormal calculate the polygon area and normal. Note that these
values are not calculated by the Element3 constructor; an object of this class initially belongs to an entity
with default values for its dimensions, orientation and position in space. Only when we create an instance
of this entity by scaling, rotation and translation (see Section 3.11) will we have the information necessary
Patch3 is derived from Element3, and so inherits its members and functions. To this it adds the patch
center, a pointer to a linked list of elements, and a pointer to its parent surface. Like the CalcArea and
CalcNormal functions, Patch3::CalcCenter should only be called after we’ve created an instance of the
entity.
Patch3 also provides Patch3::GetUnsentFlux to calculate the patch’s “unsent” flux. All this function
does is sum the patch’s spectral radiant exitances and multiply the value by the patch area. The result–the
amount of radiant flux leaving and/or reflected by the patch–will be used in Chapter Six when we solve the
radiosity equation.
You may question the complexity of these data structures, particularly the Element3 and Patch3 classes.
Keep in mind, however, that we want our data structures to 1) conserve memory; 2) provide quick and easy
104 Building An Environment
________________________________________________________________________
access to the polygon data members; and 3) allow for the dynamic addition, deletion and modification of
polygons and their vertices. The current C++ class designs, while perhaps not perfect, substantially achieve
these goals.
Moving up our hierarchy, we next consider the representation of surfaces. Their physical geometry is
described by their patches and elements; all we need to add arereflectance and initial spectral radiant
exitance.
In theory, we should specify exitance values in units of watts per square meter for each color band.
However, we are rarely interested in actual radiometric or photometric quantities when rendering radiosity
images. It’s like a camera, where you adjust the exposure and/or lens aperture to properly expose the film.
Our interest is in the relative distribution of spectral radiant exitance in the environment. Accordingly, we
can choose any convenient floating point range–say 0.0 to 1.0–where the maximum value represents the
maximum initial spectral radiant exitance in the environment. (Final calculated exitances may exceed this
One other point about surfaces: they do not share vertices where they join other surfaces. This allows
us to set vertex colors according to the color of their parent polygons and surfaces.
#ifndef _SURFACE3_H
#define _SURFACE3_H
#include "patch3.h"
public:
Surface3( Spectra reflect, Spectra emit )
{
reflectance = reflect;
emittance = emit;
pplhd = NULL;
Building An Environment 105
________________________________________________________________________
pnext = NULL;
}
~Surface3()
{
Patch3 *pp = pplhd;
Patch3 *ppnext;
#endif
Listing 3.12 - SURFACE3.H
Each Surface3 object is a singly linked list element that points to a linked list of Patch3 objects and the
next Surface3 element. As before, Surface3::GetNext returns NULL for the last element of the list.
Finally, we need a C++ class to represent entities, the top level of our hierarchy. We will later copy and
transform each entity into instances for our environment. While the transformation process may modify the
size, orientation and position of the entity in the environment, it does not result in any change to the
underlying data structure. In other words, an entity is morphologically equivalent to an instance. We can
therefore use the following Instance class to represent both entities and instances:
#ifndef _INSTANCE_H
#define _INSTANCE_H
#include "surface3.h"
~Instance()
{
Surface3 *psnext;
Surface3 *ps = pshead;
Vertex3 *pvnext;
Vertex3 *pv = pvhead;
// Delete surfaces
while (ps != NULL)
{
psnext = ps->GetNext();
delete ps;
ps = psnext;
}
// Delete vertices
while (pv != NULL)
{
pvnext = pv->GetNext();
delete pv;
pv = pvnext;
}
}
#endif
Listing 3.13 - INSTANCE.H
Each Instance object is a singly linked list element. Its private data members include a pointer to a
linked list of Surface3 objects, a pointer to a linked list of Vertex3 elements and a pointer to the next
Instance element. A linked list of Instance elements fully describes a complex 3-D environment.
The last requirement for our environment is a class that can provide some statistics about it, such as the
number of instances, surfaces and so forth. It should also provide a pointer to the first instance and delete
the memory allocated to the environment when we are through with it. This becomes:
Building An Environment 107
________________________________________________________________________
// ENVIRON.H - Environment Class
#ifndef _ENVIRON_H
#define _ENVIRON_H
#include "instance.h"
public:
Environ() { pinsthd = NULL; }
~Environ() { DeleteEnv(); }
pinst = pinsthd;
while (pinst != NULL)
{
pnext = pinst->GetNext();
delete pinst;
pinst= pnext;
}
pinsthd = NULL;
}
};
#endif
Listing 3.14 - ENVIRON.H
Having designed a hierarchical data structure, we need a data file format that will allow us to store and
retrieve our representations to and from disk, and possibly to transfer them across computer platforms.
Our first thought should be to consider one of the device-independent graphics standards, such as
IGES, GKS-3D or PHIGS. On the microcomputer front, there’s the popular AutoCAD DXF graphics file
108 Building An Environment
________________________________________________________________________
format. However, these all have complex specifications that cover far more than what we need. All we
want is a data file format that supports polygons, surfaces and entities. There’s little sense in choosing a
graphics standard that includes scaleable text, multiple fonts, polylines, linetype patterns, bicubic and
Bezier surfaces, constructive solid geometry and a host of other features that we’ll never use. Lacking any
existing standards for radiosity rendering programs, we shall simply have to create our own.
Actually, we shall require two data file formats: one to describe individual entities and another to
describe the transformations necessary to create instances of them in an environment. The entity file format
will be considered here; the environment file format will be addressed later.
The syntactic rules for our nameless file format specification are:
2. Each line must be terminated with an environment-specific “newline” character (typically <CR><LF>
3. The maximum length of a line is 256 characters, including the newline character(s).
Building An Environment 109
________________________________________________________________________
4. Multiple whitespace (ASCII space and horizontal tab) characters between data values and separators
are ignored.
optional entity_name character string that identifies the entity. Any printable ASCII character is
8. The ENTITY section header is followed by a VERTEX subsection. It begins with the “VERTEX”
keyword, followed on subsequent lines by a list of four or more vertex vectors. A maximum of 65,536
vertex vectors are allowed. Each vertex is implicitly assigned an index number according to its
position in the list, beginning with zero. The “END_VERT” keyword terminates the subsection
9. Each vertex vector consists of a ‘<‘ separator, followed by three floating point numbers representing
the x, y and z values of the vertex co-ordinates respectively, followed by a ‘>‘ separator.
10. The VERTEX subsection is followed by a SURFACE subsection. It begins with the “SURFACE”
keyword, followed on subsequent lines by a list of one or more RGB color vector pairs. The first
vector of each pair represents the surface reflectance for the entity; the second vector represents the
surface’s initial surface spectral radiant exitance. A maximum of 65,536 surfaces are allowed. Each
surface and its associated reflectance and initial exitance vectors are implicitly assigned an index
number according to its position in the list, beginning with zero. The “END_SURF” keyword
11. Each reflectance vector consists of a ‘[‘ separator, followed by three floating point numbers
representing the red, green and blue primary color values respectively, followed by a ‘]’ separator.
12. Each initial exitance vector consists of a ‘[‘ separator, followed by three floating point numbers
representing the red, green and blue primary color values respectively, followed by a ‘]’ separator.
13. The SURFACE subsection is followed by a PATCH subsection. It begins with the keyword
“PATCH”, followed on subsequent lines by one or more patch identifiers. A maximum of 65,536
polygon identifiers are allowed. The “END_PATCH” keyword terminates the subsection.
14. Each patch identifier consists of an integer number indicating the index number of the surface to
which the patch belongs, followed by a ‘{‘ separator, followed by four integer numbers indicating the
indices of the four patch vertices v0, v1, v2 and v3 respectively, followed by a ‘}’ separator. If the
patch is a triangle, the third and fourth vertex indices must be identical.
15. The PATCH subsection is followed by an ELEMENT subsection. It begins with the keyword
65,536 element identifiers are allowed. The “END_ELEM” keyword terminates the subsection.
16. Each element identifier consists of an integer number indicating the index number of the patch to
which the element belongs, followed by a ‘{‘ separator, followed by four integer numbers indicating
the indices of the four element vertices v0, v1, v2 and v3 respectively, followed by a ‘}’ separator. If
the element is a triangle, the third and fourth vertex indices must be identical.
17. The ELEMENT subsection is followed by an “END_ENTITY” keyword, which terminates the file.
To clarify the above, here’s an example of a small entity data file that describes a colored cube:
For the sake of simplicity, the surfaces described here consist of one patch each. Similarly, each patch
consists only one element. Clearly though, any surface or patch can be subdivided into multiple patches
We have so far defined an entity as an object floating in its own local co-ordinate space, independent
of all other entities. Our colored cube, for example (Listing 3.15), is aligned with the co-ordinate axes and
has one corner at the origin. Following the usual computer graphics conventions, it’s a right-handed co-
What we want, of course, is to place instances of our entities in the world co-ordinate space of our 3-D
environment. In general, this requires that we 1) scale the entity dimensions to that required for the
instance; 2) rotate the instance to properly align it with respect to the world co-ordinate axes; and 3)
translate the instance to its proper position in the world space. Taken together, these operations are
The subject of 3-D transformations, linear and otherwise, deserves an entire book in its own right.
Some of the more accessible texts include Watt [1990], Harrington [1987] and Foley et al. [1990].
Thorough coverage is provided by Hill [1990] and Rogers and Adams [1976]. The best we can afford here
x
Figure 3.15 - Cube in a right-handed co-ordinate system
Imagine we have a vertex v1 in space whose co-ordinates are {x1 , y1 , z1 } and that we want to move
x x 2 − x1
matrix notation as v = y , we can represent the translation as v 2 = v1 + t , where t = y 2 − y1 . We can
z z 2 − z1
clearly apply the same translation to every vertex of an object to move it anywhere in space.
Now suppose we want to scale the same object, either enlarging or reducing it in size. Our colored cube
has unit dimensions along each edge; we might want to change it into a rectangular box with say x = 2.0, y
= 1.5, z = 3.0. For any vertex v1, we must multiply each of its co-ordinates by the appropriate scaling factor
s x 0 0
for that dimension. Again using matrix notation, we have v 2 = sv1 , where s = 0 sy 0 is the scaling
0 0 s z
matrix.
Building An Environment 113
________________________________________________________________________
We can express our vertex co-ordinates in four-dimensional homogeneous co-ordinates as the matrix
V x
V
y , where w can be any value other than zero, and where:
V z
w
vx = Vx w
vy = Vy w (3.10)
vz = Vz w
In computer graphics, w is usually taken to be unity, so that the homogeneous co-ordinates of our
v x
v
vertex reduce to y .
v z
1
One of the advantages of homogeneous co-ordinates is that they allow us to unify the linear
transformation operations. Whereas translation required matrix addition and scaling required matrix
x 2 1 0 0 t x x1 x1
y 0 1 0 t y y1 y
Translation: 2 = = T 1 (3.11)
z 2 0 0 1 t z z1 z1
1 0 0 0 1 1 1
x2 s x 0 0 0 x1 x1
y 0 sy 0
0 y1 y
Scaling: 2 = = S 1 (3.12)
z2 0 0 sz 0 z1 z1
1 0 0 0 1 1 1
Anyone who has taken a formal course in matrix theory knows it is not for the mathematically timid.
Fortunately, matrix scaling, addition and multiplication are much easier to understand.
A matrix is a rectangular array of elements. A matrix with m horizontal rows and n vertical columns is
called an m×n matrix. A matrix with a single row or column of elements is called a row or column vector.
Thus, our vertex expressed in homogeneous co-ordinates is a 4 × 1 column vector. A square matrix has the
We can scale any matrix A by a number s by multiplying each element of A by s. For example, if A is a
2 × 2 matrix, then:
a a 01 sa 00 sa 01
sA = s 00 =
a10 a11 sa10 sa11
We can add two matrices A and B to produce a third matrix C only if they have the same number of
rows and columns (i.e., they have the same shape). Each element of C is the sum of its corresponding
Two matrices A and B can be multiplied only if the number of columns of A equals the number of rows
C = AB .
Given C = AB , the ijth element of C (that is, the element from the ith row and jth column) is the dot
product (Section 3.2) of the ith row of A with the jth column of B. For example:
k< j
cik = ∑ aij b jk
k =0
Note, however, B cannot be multiplied by A. That is, C = BA is undefined for this example. Since, in
general, the order of A and B cannot be reversed in multiplication (square matrices being the exception),
We define the identity matrix I as a square matrix whose elements are all zero except for those along
the main diagonal, which are one. For example, the 3×3 identity matrix is:
Building An Environment 115
________________________________________________________________________
1 0 0
I = 0 1 0
0 0 1
The identity matrix has the property that A = AI . That is, multiplying a matrix by an identity matrix
MM −1 = M −1M = I
Some matrices (called singular matrices) do not have definable inverses. Those of interest to us,
Finally, we can interchange the rows and columns of a matrix A. This gives us the transpose of A,
denoted as A T , where a ijT = a ji . This also means that we can represent 3-D and 4-D homogeneous co-
ordinates as 1 × 3 and 1 × 4 row vectors. In fact, some computer graphics textbooks (e.g., Hill [1990]) use
this notational style. It’s a matter of personal preference, since the following two representations produce
equivalent results:
and:
a00 a10 a 20
C T = [c0 c1 c2 ] = B T A T = [b0 b1 b2 ] a01 a11 a 21
a02 a12 a 22
= [(b0 a00 + b1a01 + b2 a02 ) (b0 a10 + b1a11 + b2 a12 ) (b0 a20 + b1a21 + b2 a22 )]
There is a vast body of literature available on matrix mathematics. Of this, the material in this text box
Translation and scaling are now in identical form, being a single matrix multiplication. While
multiplication is more time consuming than addition, there is another advantage to homogeneous co-
116 Building An Environment
________________________________________________________________________
ordinates which more than compensates. We will address this shortly; in the meantime, the three examples
z z
y y
x x
1 0 0 0 1.5 0 0 0
0 1 0 0 0 1.5 0 0
0 0 1 0 0 0 1 0
0 0 0 1 0 0 1 1
y
x
1 0 0 0
0 1 0 1.0
0 0 1 − 0.5
0 0 0 1
The same mathematical form applies to rotation about one of the co-ordinate axes:
x 2 1 0 0 0 x1 x1
y 0 cosθ − sin θ
0 y1 y
x-axis: 2 = = R x 1 (3.13)
z 2 0 sin θ cosθ 0 z1 z1
1 0 0 0 1 1 1
x2 cosθ 0 sin θ 0 x1 x1
y 0 1 0
0 y1 y
y-axis: 2 = = R y 1 (3.14)
z 2 − sin θ 0 cosθ 0 z1 z1
1 0 0 0 1 1 1
Building An Environment 117
________________________________________________________________________
x2 cosθ − sin θ 0 0 x1 x1
y sin θ cosθ 0
0 y1 y
z-axis: 2 = = R z 1 (3.15)
z2 0 0 1 0 z1 z1
1 0 0 0 1 1 1
where θ is the angle of rotation measured counterclockwise about the axis when looking towards the
z z
y y
x x
Figure 3.17a - 30° rotation about z-axis Figure 3.17b - Rotation and translation
The advantage of having one common mathematical form for translation, scaling and rotation is that
any sequence of these transformations can be concatenated (i.e., premultiplied) to yield a single net
please. That is, rather than separately translating, scaling and rotating each vertex, we can successively
Note that the 3 × 3 upper left submatrix A determines the net rotation and scaling, while the three elements
Any number of translation, scaling and rotation matrices can be concatenated in any order. However,
the results depend on the order of concatenation. Rotations, for example, are not commutative. Given any
two rotation matrices R1 and R2, R1R2 ≠ R2R1. (Try rotating an object 90 degrees vertically, then 90
degrees horizontally. Note its orientation, return it to its original orientation, then rotate it 90 degrees in the
same horizontal direction before rotating it 90 degrees vertically.) Similarly, scaling and then translating a
Any transformation can be reversed by multiplying the transformation M matrix by its inverse M-1. T-1
is obtained by negating t x , t y and t z , S-1 replaces s x , s y and s z by their inverses, and R-1 negates the
rotation angle θ.
It should also be remembered that rotation is defined with respect to the co-ordinate system origin.
In practice, this requires a single net transformation matrix M that is applied to all the vertices
#ifndef _3D_TRANS_H
#define _3D_TRANS_H
#include "vector3.h"
void Translate()
{
m[0][3] += trans_x;
m[1][3] += trans_y;
m[2][3] += trans_z;
}
public:
Transform3()
{
scale_x = scale_y = scale_z = 1.0;
trans_x = trans_y = trans_z = 0.0;
rot_x = rot_y = rot_z = 0.0;
Identity();
}
void BuildTransform()
{
Identity(); // Initialize identity matrix
pp->SetX(temp.GetX());
pp->SetY(temp.GetY());
pp->SetZ(temp.GetZ());
}
};
#endif
Listing 3.16 - TRANSFM3.H
There are two items of interest here. First, the transformation matrix m is stored as a 3 × 4 rather than a
4 × 4 matrix. As Equation 3.17 indicates, the fourth row of the transformation matrix is always the same
for scaling, translation and rotation. We can therefore ignore it in our calculations.
Second, the user is only allowed to specify the net transformation matrix in terms of scaling factors,
translation distances and rotation angles. Calling BuildTransform results in the transformation matrix being
recalculated based on the current set of parameters. Note that the private member functions responsible for
scaling, translation and rotation are designed for this specific use. That is, they modify the identity matrix
in a given order to produce the net transformation matrix. Equivalent public functions to perform scaling,
translation and rotation by premultiplying an arbitrary 3-D transformation matrix would each have to
Building an environment consists of copying and transforming entities into instances. For this, we need
an environment data file format to describe which entities are to be copied and what 3-D linear
WORLD world_name
COMMENT Environment Data File
entity_file_name
< sx sy sz >
< rx ry rz >
< tx ty tz >
entity_file_name
···
END_FILE
Figure 3.18 - Environment data file format
Similar to our entity data file format, the following syntax rules apply:
2. Each line must be terminated with an environment-specific “newline” character (typically <CR><LF>
3. The maximum length of a line is 256 characters, including the newline character(s).
4. Multiple whitespace (ASCII space and horizontal tab) characters between data values and separators
are ignored.
6. The data file begins with the keyword “WORLD”, followed on the same line by an optional
world_name character string that identifies the environment. Any printable ASCII character is
7. The remainder of the data file consists of one or more entity sections, followed by the “END_FILE”
9. The entity_file_name is an environment-specific file name that uniquely identifies the entity data file.
10. A scaling vector consists of a ‘<‘ separator, followed by three floating point numbers representing the
x-axis, y-axis and z-axis scaling factors respectively, followed by a ‘>‘ separator.
11. A rotation vector consists of a ‘<‘ separator, followed by three floating point numbers representing the
x-axis, y-axis and z-axis rotation angles (in degrees) respectively, followed by a ‘>‘ separator.
12. A translation vector consists of a ‘<‘ separator, followed by three floating point numbers representing
the x-axis, y-axis and z-axis translation values respectively, followed by a ‘>‘ separator.
Here’s an example of a data file that places two instances of our previously defined colored cube entity
in a world environment:
Our final requirement is for a C++ class that can read an environment data file and build an equivalent
data structure in memory. In terms of programming languages and compiler theory, we want to parse the
data file. Unlike even the smallest programming language, however, parsing our data file formats will be a
where most of the work will be handled by our previously defined classes.
So why is the following Parse class so lengthy? Most of its code is devoted to manipulating linked lists
and converting ASCII character strings into meaningful data primitives such as int and float. If you ignore
the bookkeeping, PARSE.CPP is fairly straightforward. Keeping this in mind, here’s the header file:
#ifndef _PARSE_H
#define _PARSE_H
#include "environ.h"
#include "transfm3.h"
#include "win_text.h"
BOOL ParseElements();
BOOL ParsePatches();
BOOL ReadVector( WinText &, double *, double *,
double * );
Instance *ParseEntityFile();
Surface3 *ParseSurfaces();
Surface3 *ReadSurface();
Vertex3 *ParseVertices();
Vertex3 *ReadVertex();
void ReadLine( WinText & );
void ReadTransform();
void TransformInstance( Instance * );
public:
BOOL ParseFile( char *, char *, Environ * );
};
#endif
Listing 3.18 - PARSE.H
If your target environment is not MS-Windows, you should note the MS-DOS specific file path
separator “\”. A UNIX-based implementation, for example, would require this to be “/”.
Another platform-dependent issue to watch out for is text file handling, which is handled in PARSE.H
by an MS-Windows specific class called WinText (described below). MS-Windows uses a 256-character
extended ASCII character set. It also provides no built-in functions for reading text files. You can use the
C++ iostream or stdio.h file functions, but you have to be careful about casting character strings and FILE
pointers if you’re using them in conjunction with MS-Windows functions (which typically expect _far
pointers).
We can sidestep these issues by using the large memory model when compiling our MS-Windows
application program and encapsulating the file handling functions in a separate class. While the following
WinText class is nominally specific to MS-Windows, it can applied without change to most other
environments.
#ifndef _WIN_TEXT_H
Building An Environment 125
________________________________________________________________________
#define _WIN_TEXT_H
#include <string.h>
#include "general.h"
public:
// Close file
void Close() { (void) fclose(pfile); }
if (pstr == NULL)
pstr = pline;
#endif
Listing 3.19 - WIN_TEXT.H
#include <string.h>
#include "error.h"
#include "parse.h"
for ( ; ; )
{
ReadLine(ifile); // Read entity file name
pinst = NULL;
ps = NULL;
pv = NULL;
pv = ParseVertices();
ps = ParseSurfaces();
status = ParsePatches();
if (status == TRUE)
status = ParseElements();
efile.Close();
return pinst;
}
128 Building An Environment
________________________________________________________________________
// Parse vertices
Vertex3 *Parse::ParseVertices()
{
WORD v_index; // Vertex pointer array index
Vertex3 *pv; // Vertex pointer
Vertex3 *pvhd; // Vertex list head ptr
pv = pvhd = NULL;
// Parse surfaces
Surface3 *Parse::ParseSurfaces()
{
WORD s_index; // Surface pointer array index
Surface3 *ps; // Surface pointer
Surface3 *pshd; // Surface list head ptr
ps = pshd = NULL;
for ( ; ; )
{
ReadLine(efile); // Read patch identifier
if (status == FALSE)
break;
return status;
}
for ( ; ; )
{
ReadLine(efile); // Read element identifier
if (status == FALSE)
break;
return status;
}
void Parse::ReadTransform()
{
double sx, sy, sz; // Scaling parameters
double rx, ry, rz; // Rotation parameters
double tx, ty, tz; // Translation parameters
// Read vector
BOOL Parse::ReadVector( WinText &file, double *px, double
*py, double *pz )
{
float x, y, z; // Temporary variables
char start[2], end[2]; // Data separators
return TRUE;
}
else
return FALSE;
}
pp->CalcArea();
pp->CalcCenter();
pp->CalcNormal();
pp = pp->GetNext();
}
ps = ps->GetNext();
}
Our program outline (Fig. 3.19) is handled by ParseFile, which accepts as its parameters an
environment data file name and an optional file path name to where the entity files are stored.
ParseFile extracts each entity file name from the environment data file and appends it to the entity file
path name (if one was specified). Using this fully expanded file name, it calls ParseEntityFile to read each
Building An Environment 135
________________________________________________________________________
entity file, after which it calls ReadTransform to read the associated transformation matrix. Each entity
If ParseFile is successful, a pointer to the environment can be obtained by calling GetEnv. The memory
allocated to this data structure can be released at any time by calling DeleteEnv. This memory is also
released if ParseFile is called again; each Parse object can only point to a single environment.
Finally, ParseFile calls ReportError if it can’t open an environment or entity file. This global function
is defined by:
#ifndef _ERROR_H
#define _ERROR_H
#ifndef _NOT_WIN_APP
#include <windows.h>
#else
#include <iostream.h>
#endif
#endif
Listing 3.21 - ERROR.H
and:
#include "error.h"
Note the use of the externally defined _NOT_WIN_APP to choose between a character-mode and an
MS-Windows application. MessageBox is an MS-Windows function that displays the error message in a
popup window.
PARSE.CPP and ERROR.CPP are not exactly laudable examples of robust user interface code. Unlike
the previous classes, Parse has to accept input from the outside world. Done properly, it should
exhaustively validate this data, provide meaningful error messages and exit gracefully. As a rule of thumb,
Using the example data files COL_CUBE.ENT and COL_CUBE.WLD (Listings 3.15 and 3.17), we
#include <stdio.h>
#include <iostream.h>
#include "parse.h"
pelem = pelem->GetNext();
}
ppatch = ppatch->GetNext();
}
psurf = psurf->GetNext();
}
return 0;
}
Listing 3.23 - TEST_1.CPP
Building An Environment 139
________________________________________________________________________
TEST_1 is a character-mode application that sends its output to the user console. As such,
To run TEST_1, make sure that both data files are in the current directory, then enter the following
command:
TEST_1 COL_CUBE.WLD
Alternatively, you can have COL_CUBE.ENT in a separate directory, say “C:\RADIANT\ENTITIES”, and
enter:
The output in either case will be a detailed listing of the surfaces, polygons and vertices belonging to
the two instances in the environment, along with their properties (surface colors, polygon normals, vertex
3.14 Conclusions
With Parse and its associated classes, we have the 3-D graphics toolkit necessary to build an
environment. There are of course opportunities for improvement. The RGB model used in the ColorRGB
class, for example, could be augmented with a more sophisticated representation such as the HSV (hue-
saturation-value) or HLS (hue-lightness-saturation) models (e.g., Foley et al. [1990], Hill [1990], Watt
[1990] and Hall [1989]). These models are particularly useful for interactive control of surface colors,
where equal changes in the color space parameters produce approximately equal changes in the perceived
color. Foley et al. [1990] and Watt [1990] both offer Pascal code for converting between HLS and HSV
A second approach is to use four or more color bands (Hall [1989]) for more accurate color rendition.
Chen [1991] offers C source code for mapping between such models and the simpler RGB color model.
The only problem is that there is very little information available on the spectral reflectance distribution of
most materials. Architectural finishes in particular are most often characterized using the subjective
Munsell color specification system (e.g., Munsell [1946], Judd and Wyszecki [1975] and Burnham et al.
[1963]) with its hue, value and chroma parameters. A Munsell color can only be mapped to the three color
The Element3, Patch3 and Surface3 classes are candidates for improvement. The winged-edge data
structure (Baumgart [1974], Baumgart [1975] and Glassner [1991]) for polygon representation is one
possibility, although developing a robust winged-edge class in C++ is not for the timid. Another possibility
is to replace the polygon-based representation of surfaces with the edge-based representation described in
Mitchell [1990] (see also Watt and Watt [1992]). This approach results in a data structure that is simpler
than Element3 and which consumes less memory. Unfortunately, it requires different rendering techniques
Finally, the Parse class could be made more robust for use in a stand-alone application. Given the
widespread availability of reasonably priced 3-D CAD packages however, it is probably more reasonable
to develop an AutoCAD DXF file translator (see the accompanying diskette for a simple example) to
generate complex environment descriptions. For our purposes, Parse and its associated classes are more
than adequate.
References
Arvo, J., Ed. [1991]. Graphics Gems II, Academic Press, San Diego, CA.
Baumgart, B.G. [1975]. “A Polyhedron Representation for Computer Vision”, Proc. National Computer
Bragg, D. [1992]. “A Simple Color Reduction Filter”, in Kirk [1992], 20 - 22, 429 - 431.
Burnham, R.W., R.M. Hanes and C.J. Bartleson [1963]. Color: A Guide To Basic Facts and Concepts,
Chen, S.E. [1991]. “Implementing Progressive Radiosity with User-Provided Polygon Display Routines”,
Cychosz, J.M. [1990]. “Efficient Generation of Sampling Jitter Using Look-Up Tables”, in Glassner
Foley, J.D., A. van Dam, S.K. Feiner and J.F. Hughes [1990]. Computer Graphics: Principles and Practice
Gervautz, M. and W. Purgathofer [1990]. "A Simple Method for Color Quantization: Octree Quantization",
Glassner, A.S. [1990]. Graphics Gems, Academic Press, San Diego, CA.
Glassner, A.S. [1991]. “Maintaining Winged-Edge Models”, in Arvo [1991], 191 - 201.
Hall, R. [1989]. Illumination and Color in Computer Generated Imagery, Springer-Verlag, New York,
NY.
Harrington, S. [1987]. Computer Graphics: A Programming Approach. McGraw-Hill, New York, NY.
Hill, F.S., Jr. [1990]. Computer Graphics, Macmillan, New York, NY.
Judd, D. and G. Wyszecki [1975]. Color in Business, Science and Industry, Wiley, New York, NY.
Kirk, D., Ed. [1992]. Graphics Gems III, Academic Press, San Diego, CA.
Mitchell, D.P. [1990]. Fast Algorithms for 3D Computer Graphics, Ph.D. thesis, University of Sheffield.
Munsell, A.H. [1946]. A Color Notation, Munsell Color Co., Baltimore, MD.
Rogers, D.F. and J.A. Adams [1976]. Mathematical Elements for Computer Graphics, McGraw-Hill, New
York, NY.
Thomas, S.W. and R.G. Bogart [1990]. “Color Dithering”, in Arvo [1990], 72 - 77, 509 - 513.
MA.
Watt, A. and M. Watt [1992]. Advanced Animation and Rendering Techniques, Addison-Wesley, Reading,
MA.
Chapter 4
A Viewing System
4.0 Introduction
Our environment consists of a complicated arrangement of data structures and pointers residing
somewhere in memory. Examining its contents is not easy; even a pair of colored cubes floating in space
presents us with an overwhelming stream of instance, surface, polygon and vertex values. Before doing
anything else, we need to develop a viewing system to display 3-D environments on our two-dimensional
computer screens.
What is a viewing system? Think of a computer screen as being a glass window looking into the
environment (Fig. 4.1). Examining the image on the screen from a fixed position with one eye closed, we
cannot say (with a bit of poetic license) whether we are viewing a 3-D environment or a 2-D representation
of it.
Window
That’s all there is to it! By tracing rays from a 3-D object to our eye position, we can “project” the
object onto the 2-D window. The ray luminances determines the luminances of the window at the points of
intersection. Looking at this window, we see a two-dimensional perspective projection of the 3-D
environment.
144 A Viewing System
________________________________________________________________________
Do not be misled by some of the more complex discussions of viewing systems in the computer
graphics literature. A viewing system–any viewing system– consists of one eye and a window. The
viewing system we will develop in this chapter is a slightly simplified version of the GKS-3D (ISO [1988])
and PHIGS (ANSI [1988]) systems. The principles of these industry standards are described at length in
Singleton [1987], with more generalized descriptions available in Foley et al. [1990] and Hill [1990].
The differences between our viewing system and GKS-3D or PHIGS are minimal and relatively
unimportant. It can show us everything we could see and photograph with a 35mm camera in real life. In
fact, the only advantage GKS-3D and PHIGS offer is their ability to model a professional photographer’s
view camera with its tilting lens holder. This is useful only if you want to correct for perspective distortion
(such as a tall building photographed from street level with a wide angle lens). Few of us own one of these
The advantage of our viewing system is that it is conceptually simple. Don’t let the mathematics
intimidate you. Look at the illustrations first and remind yourself that the equations are nothing more than a
formalized description of what you see. Taken one step at a time, they are actually quite easy to follow and
understand.
Imagine our window as being part of an infinite view plane that is some distance (called the view
distance) in front of our eye and perpendicular to our line of sight (Fig. 4.2). We can position this view
plane window anywhere in an environment and orient it such that we can look in any direction.
To simplify our understanding of what we see, we can define a left-handed view plane co-ordinate
system (or “view space”) whose origin lies at the center of our window. In accordance with computer
graphics convention, we label its axes u, v and n. The n-axis indicates the direction in which we are
looking, while the v-axis establishes our local “up” direction. Expressing the view space origin in world
{ }
co-ordinates (i.e., o x , o y , o z ) establishes our position, while expressing the n-axis and v-axis as vectors in
world co-ordinates uniquely orients our view space with respect to the environment. The n-axis unit vector
n is called the view direction vector, while the v-axis unit vector v is referred to as the view-up vector.
A Viewing System 145
________________________________________________________________________
v y x
View distance n
z
u
Eye position
View plane window
Our view plane window is a square with dimensions two units wide by two units high. What the units
actually represent–inches, feet or meters–is not important. Looking through the window, we can see that
the set of rays traced from its four corners to the eye position define an imaginary pyramidal cone (the view
pyramid) that delimits our angular field of view (Fig. 4.3). We can change this field of view by varying the
view distance. The effect is the same as that of changing the focal length setting of a zoom lens on a
camera–objects appear larger through the view plane window as the view distance is increased.
View pyramid
Figure 4.3 - Changing the field of view by varying the view distance
Actually, the “window” analogy is somewhat misleading. Unlike a physical window, we will not see an
object that is in front of the window (i.e., between the view plane and our eye position) but outside the
view pyramid. Conversely, any object contained within the view pyramid will be visible, regardless of
whether it is behind or in front of the window. A more accurate description of the view plane window is
that of an imaginary square, defined on the equally imaginary view plane, that determines the shape of the
view pyramid.
146 A Viewing System
________________________________________________________________________
We need two more components to make our minimal viewing system a useful tool. Suppose we want to
look at the interior of a room somewhere inside a large building. If the eye position we need to obtain the
proper perspective is located outside the room, we must somehow remove the intervening walls and
objects. Even if our eye position is within the room, we will still want to ignore anything that lies beyond
A simple but effective solution is to define two additional planes (called clipping planes) that are
perpendicular to the view direction vector (Fig. 4.4). Together with the view pyramid, these planes delimit
a view volume (also known as a view frustum). Only objects that are contained within this volume are
visible through the view plane window; those that lie partially or wholly outside the volume are clipped
from our field of view. In our example, we would likely set the front clipping plane to be just inside the
room and the back clipping plane to lie just beyond the far room walls.
Given a viewing system position and orientation within an environment, we may find that the nearest
objects of interest are between the eye position and the view plane window. This is not a problem! The
front clipping plane can be placed as close to the eye position as necessary, including in front of the view
plane window. We can always trace rays backwards from the eye position through the objects to the view
plane.
A Viewing System 147
________________________________________________________________________
In later developing a user interface for our viewing system, we will need to specify its position and
orientation in world co-ordinates. While specifying the position is trivial, orienting the viewing system
presents a minor problem. Designing an intuitive interface suggests that the view direction vector n and
view-up vector v should be specified using spherical co-ordinates. However, v must be exactly
One reasonable approach is to indicate an approximate view-up vector v' . The true view-up vector v
can then be determined by projecting v' onto the view plane (Fig. 4.5) and normalizing the resultant
where the only restriction is that v' cannot point in the same or opposite direction as n. In other words, v'
v
v' u
Figure 4.5 - Determining the view-up vector v from an approximate vector v'
Knowing v and n, the world co-ordinates of the unit vector u can be determined from:
u =n×v (4.2)
where n comes before v in the cross product only because u, v and n comprise a left-handed co-ordinate
system.
The objects in our environment are defined in terms of 3-D polygons with world co-ordinates. To
project them onto the view plane window, we first need to transform their co-ordinates into those of our
view space. This problem is similar to that of transforming an entity into an instance (Section 3.9), except
148 A Viewing System
________________________________________________________________________
that no scaling is required. We are also dealing with an environment (a “world space”) rather than a single
Imagine that we have an environment consisting of a cube and a viewing system as shown in Figure
4.6a. We need a linear 3-D transformation that will perform two operations. First, it should translate the
world space such that its origin coincides with our view space origin (Fig 4.6b). In other words, the world
co-ordinates of every object in the environment are shifted a distance equal to that between the two origins.
Second, the transformation should rotate the world space such that its axes are aligned with those of our
view space (Fig. 4.6c). Remember however that the world space has a right-handed co-ordinate system,
while our view space is left-handed. This means that when the x-axis unit vector is aligned with the u-axis
unit vector and the y-axis and v-axis unit vectors are similarly aligned, the z-axis unit vector will point in
u x x
v y
= RT = M y (4.3)
n z z
1 1 1
where T is the translation matrix, R is the rotation matrix, and M is the net view space transformation
matrix.
1 0 0 − ox
0 1 0 − o y
T= (4.4)
0 0 1 − oz
0 0 0 1
where ox , oy and oz are the world co-ordinates of the view space origin. The rotation component is
somewhat more complicated. We have the view space axes as unit vectors u, v and n expressed in world
{ }
space co-ordinates (e.g., u = u x u y , u z for the u-axis vector). We want a 3-D transformation matrix R that
u = {1, 0, 0}
v = {0, 1, 0} (4.5)
n = {0, 0, 1}
A Viewing System 149
________________________________________________________________________
u x 1
u 0
R y =
u z 0
1 1
v x 0
v 1
R y = (4.6)
v z 0
1 1
n x 0
n 0
R y =
n z 1
1 1
{2,2,0}
y u
{0,1,0} n
y
v
{0,0,0}
z u
{-2,-1,0} n
x
v,y
u,x
{0,0,0}
{0,0.7,2.1} n
It can be shown (e.g., Hill [1990]) that the matrix R must have the form:
u x uy uz 0
v vy vz 0
R= x (4.7)
n x ny nz 0
0 0 0 1
where u x , u y and u z are the world co-ordinates of the u-axis unit vector, and similarly for the v-axis and
n-axis unit vectors. For our purposes, it is sufficient to confirm that R satisfies Equation 4.6 (since
Concatenating these two matrices gives us the view space transformation matrix:
u x uy uz tx
v vy vz t y
M = RT = x (4.8)
n x ny nz tz
0 0 0 1
where:
t x = −o x ∗ u x − o y ∗ u y − o z ∗ u z
t y = −o x ∗ v x − o y ∗ v y − o z ∗ v z (4.9)
t z = −o x ∗ n x − o y ∗ n y − o z ∗ n z
from the definition of matrix multiplication. Put more succinctly, each of the components of the submatrix
t is the dot product of the view space origin o (expressed as a vector in world space co-ordinates) and one
− o ⋅ u
t = − o ⋅ v (4.10)
− o ⋅ n
Referring to Figure 4.6 as an example, suppose we have chosen an view space whose position and
n = −1{ 2 , −1 }
2 , 0 . This gives us the following view space transformation matrix:
0 0 −1 0
− 1 2 1 2 0 0
M= (4.11)
− 1 2 −1 2 0 2 2
0 0 0 1
If we then have (for example) a point in our environment with world co-ordinates {0, 1, 0} ,
0
1
premultiplying its homogeneous co-ordinates representation by M gives its view space co-ordinates of
0
1
{0, −1 2, 3 }
2 .
In summary, we can position and orient our viewing system anywhere in an environment. Having done
so, Equations 4.8 and 4.9 show us how to compute its transformation matrix. Applying this matrix to the
world co-ordinates of any point in the environment gives us its equivalent view space co-ordinates.
The objects in our environment consist of collections of 3-D polygons. Having transformed the world
co-ordinates of their vertices into view space co-ordinates, it remains to project these vertices onto the view
From Figure 4.7, it is evident that the co-ordinates of the projected point p' can be determined from
pu ' = pu w
(4.12)
pv ' = pv w
This is reminiscent of our definition of homogeneous co-ordinates (Eqn. 3.10). Suppose we expand
pu ' = pu w
pv ' = pv w (4.13)
pn ' = pn w
Pu 1 0 0 0 u u
P 0 1 0 0 v v
Perspective: v = = P (4.14)
Pn 0 0 1 0 n n
w 0 0 −1 d 1 1 1
v
p'(u,v,0)
p(u,v,n)
n
d
u
View plane window
pu ' = Pu w
pv ' = Pv w (4.15)
p n ' = Pn w
(The division of the first three homogeneous co-ordinates by the fourth co-ordinate is called the
This approach offers several advantages. First, it allows us to perform perspective projection as a 3-D
transformation using homogeneous co-ordinates. Recalling Section 3.11, we can concatenate the
A Viewing System 153
________________________________________________________________________
perspective transformation matrix P with our view space transformation matrix M (Eqn. 4.8), thereby
Second, the projected n-axis co-ordinate p' n has a physical meaning. It represents the perspective
depth (or pseudodepth) of the vertex. Given two vertices p1 and p2 where p1n > p 2 n , the projected n-
axis co-ordinates are such that p'1n > p' 2 n . In other words, the perspective transformation preserves the
depth ordering of the vertices relative to the view plane. (It does not preserve the true n-axis depth,
however. Plotting p' n versus pn will show that the n-axis scale is stretched as it approaches the back
clipping plane.) We will need this information later on to determine whether an object is hidden by any
Third and most importantly, the perspective transformation preserves straight lines and planes. That is,
a straight line between two vertices in our view space is projected onto the view plane as a straight line
while retaining the proper depth ordering of each point along the line. The same applies to points on a
plane. This is essential if we are to interpolate edges and planar polygon surfaces between vertices after a
The four homogeneous co-ordinates represent four dimensions. Unfortunately, the words “four
dimensions” bring to mind thoughts of general relativity and curved space-time, following which most of
us respond to social conditioning and switch our minds into neutral. To avoid this syndrome, we should
The diagram shown in Figure 4.8 illustrates two points ( p0 and p1 ) on a 3-D line being projected onto
the u-v plane. The projected points are p0 ' and p1 ' respectively. Notice that the two horizontal axes are
labeled u and v, while the vertical axis is labeled w. Notice also that p 0 ' = p1 ' w . This applies for any
There are two crucial concepts here: first, the w-axis plots our fourth co-ordinate, and therefore
represents the fourth dimension. It clearly shows that the co-ordinate w is nothing more than a scaling
factor that converts the u-v co-ordinates of a point to their projected co-ordinates on the view plane. This
same scaling factor converts the n-axis co-ordinate to its perspective depth.
154 A Viewing System
________________________________________________________________________
Second, the fourth homogeneous dimension is no different from the other three dimensions. We can
plot points, lines and planes in four dimensions as easily as we can in two or three. Moreover, the usual
rules of geometry and trigonometry apply. For example, the length of a 4-D vector is given by
u 2 + v 2 + n 2 + w2 .
There is one point to remember, however. Since w represents a scaling factor (as shown by Equation
4.13), any line or plane plotted along the w-axis must intersect the origin. There are exceptions to this rule
in computer graphics, but they do not occur in any area of concern to us.
w p1
v
2
p0 p1'
1
p0'
0 u
What happens if a point p is behind our eye position? Even though pn has a negative value, Equations
4.14 and 4.15 yield valid results. They can be interpreted by tracing a ray from the point through the eye
position to the view plane (Fig. 4.9). This emphasizes the need for our view volume. Without it, objects
behind the eye position are projected onto the view plane. Another reason is that any attempt to project a
point on the plane parallel to the view plane and intersecting the eye position (i.e., p n = d ) will result in a
division-by-zero error.
A Viewing System 155
________________________________________________________________________
The perspective division distorts the truncated pyramid of our perspective view volume (Fig. 4.10a)
View volume
v
View plane window
n
View volume
v
View plane window
n
The view volume is now a rectangular box with parallel sides, with our eye position removed to minus
infinity along the n-axis. Of course, all the points in the view space have been similarly distorted–we have
transformed our perspective projection of the world space into an equivalent parallel projection (Fig. 4.11).
156 A Viewing System
________________________________________________________________________
The projection of any point onto the view plane can now be performed by tracing a ray parallel to the n-
axis from the point to the view plane. The spatial distortions we have introduced with the perspective
transformation make this projection of the environment onto the view plane window look like our original
perspective projection.
Figure 4.11a - Before perspective division Figure 4.11b - After perspective division
Our view plane window is a square. Recalling the beginning of this chapter, our goal is to display 2-D
projected images of a 3-D environment. These images will typically be rectangular. We can think of them
having a left-handed screen space co-ordinate system (Fig. 4.12), with the x-axis and y-axis representing
the image width and height, and the z-axis representing the depth “behind” the screen. The question is,
once we project a point onto the square view plane window, how can we scale its u-v view space co-
Screen
width
We could of course simply crop the projected image before scaling. However, this entails an
unnecessary amount of work. We still have to clip, shade and perform hidden surface elimination
calculations for each polygon (discussed in the following sections) before we can scale them.
The aspect ratio of an image is defined as the ratio of its width to its height. What if we redefined our
view plane window as a rectangle with the same aspect ratio as the image we want to display?
Unfortunately, this complicates both our definition of a view volume and the following algorithms for
clipping, shading and hidden surface elimination. In particular, the algorithms must be made aware of the
The preferred solution is to scale our entire view space. Suppose we want to display a rectangular
image that measures 320 pixels horizontally and 240 pixels vertically on a computer screen with square
pixels. The aspect ratio of this image is approximately 1.33. By multiplying (i.e., scaling) the view space
v-axis co-ordinates by this ratio, we can stretch our view space vertically such that the rectangular image
becomes a square. This allows us to continue to use our square view plane window. (If the aspect ratio
were less than one–that is, if we want a vertically-oriented image–we would have to scale the u-axis co-
ordinates instead.)
We can now perform our clipping, shading and hidden surface elimination calculations for each
polygon in this distorted view space. More importantly, the algorithms do not need to know about the
aspect ratio. We only need to divide the distorted v-axis or u-axis co-ordinates by this ratio when we are
What about the front and back clipping plane distances? As a result of perspective division, the front
plane is now located at F (1 − F d ) units along the n-axis, where F is the front plane distance and d is the
view distance (with d < 0 ). Similarly, the back plane is located at B (1 − B d ) units, where B is the back
plane distance. By translating and then scaling our view volume in the n-axis direction prior to perspective
division, we can change these distances to 0 and +1 units respectively. By appropriately translating and
scaling in the u-axis and v-axis directions as well, we can create the canonical parallel view volume shown
in Figure 4.13, where 0 ≤ u ≤ 1 and 0 ≤ v ≤ 1 . These are normalized view space co-ordinates.
158 A Viewing System
________________________________________________________________________
The required translation and scaling can be performed with one normalization transformation,
u ' su 0 0 1 2 u u
v' 0 sv
0 1 2 v v
Normalization: = = N (4.16)
n' 0 0 s n rn n n
1 0 0 0 1 1 1
+1
n
+1
+1
u
where:
a
su =
2
(4.17)
b
sv =
2
−1
B
s n = −
F
=
(d − B )(d − F )
1 − B d 1 − F d d 2 (B − F )
F F (d − B )
rn = − s n =
1 − F d d (F − B )
and where:
a =1
b = aspect
if aspect ≥ 1 , otherwise:
a = 1 aspect
b =1
A Viewing System 159
________________________________________________________________________
We will later need the pseudodepth n' of our normalized view space co-ordinates to determine the
relative depth of object in the view volume. Meanwhile, we can scale u ' and v' to our screen space co-
ordinates using:
where x is the horizontal position in pixels from the left edge of the screen and y is the vertical position in
scan lines from the bottom. Similarly, the screen width is measured in pixels and its height is measured in
scan lines. Since u ' and v' can range from 0.0 to 1.0 inclusive, the min function needed to ensure that the
There are some differences of opinion in the computer graphics community regarding the co-ordinates
of a pixel. Our normalized view space co-ordinates are floating point values, implying a continuous image.
Our screen, on the other hand, is an array of pixels, which implies a discrete image. The question is, are
these pixels centered on integer co-ordinates or halfway between? Given a floating point value of 3.75, do
Heckbert [1990a] argues for the latter, stating that “the pixel with discrete co-ordinates (x, y) has its
center at continuous coordinates (x + 1/2, y + 1/2).” That is, we should truncate using the C++ math library
floor function. This is done implicitly when the compiler converts a floating point value to its integer
representation (Plauger and Brodie [1989]) through the cast to int in Equation 4.18.
Pu px
P
v = NPM p y (4.19)
Pn pz
w 1
{ }
where p x , p y , p z are the world co-ordinates of a point p, M is the view space transformation matrix
(Eqn. 4.8), P represents the perspective transformation (Eqn. 4.14) and N performs the normalization
transformation (Eqn. 4.16). The perspective division (Eqn. 4.15) then recovers the 3-D projected co-
160 A Viewing System
________________________________________________________________________
ordinates {p'u , p ' v , p' n } . The net transformation matrix NPM is called the 3-D projective transformation
matrix.
The beauty of homogeneous co-ordinates is that for any given set of viewing system parameters, these
three matrices can be concatenated to form a single 4×4 transformation matrix. This allows us to
accomplish our view space, normalization and perspective transformations with a single matrix multiply
operation, and to apply the identical operation to each point in the environment.
To illustrate Equation 4.19 assume we have a viewing system with view distance d = −4.0 , front plane
distance F = 2.0 and back plane distance B = 10.0 . Our image has an aspect ratio aspect = 1.33 . If we
orient this system such that its origin is located at the world co-ordinate space origin, its view direction
vector is n = {0, 0, 1} and its view-up vector is v = {0, 1, 0} , then its u-axis co-ordinates will be
− 1 0 0 0
0 1 0 0
M= (4.20
0 0 1 0
0 0 0 1
which in this case only does nothing more than convert right-handed world space co-ordinates into those of
1 0 0 0 − 1 0 0 0
0 1 0
0 0 1 0 0
PM = M= (4.21)
0 0 1 0 0 0 1 0
0 0 14 1 0 0 14 1
1 2 0 0 12 − 1 2 0 18 12
0 23 0 12 0 2 3 18 1 2
NPM = PM = (4.22)
0 0 21 32 − 7 8 0 0 7 16 − 7 8
0 0 0 1 0 0 14 1
A Viewing System 161
________________________________________________________________________
Applying this transformation matrix to a point with world space co-ordinates {4, 3, 7}, we obtain its
w = 1 + z 4 = 11 4
1 1 1
u = − x + z + w = − 5 22
2 8 2
2 1 1 (4.23)
v = y + z + w = 27 22
3 8 2
7 7
n = z − w = 35 44
16 8
Substituting the front and back clipping plane values of 2 and 10 for the point’s z-axis co-ordinate will
demonstrate that its perspective depth n becomes 0 and 1 respectively. Similar substitutions can be used to
We saw in the previous chapter (Section 3.4.1) that a polygon is only visible if the angle between its
normal and our line of sight vector is less than ±90 degrees, or equivalently if their dot product is less than
zero. Backface culling employs this concept to eliminate those polygons we cannot see before we perform
We already have the polygon normal in world co-ordinates. What we need is the view vector from our
eye position to any point on the polygon (Fig. 4.14). The polygon’s first vertex makes as good a choice as
any. The view vector is then defined as the vector from our eye position to this vertex. (Note that this
vector is not our view direction vector. The polygon may not even be in our field of view.)
View vector
θ
v0
Figure 4.14 - Backface culling in world space
We do not have the eye position in world co-ordinates. However, we do have the view system origin o
and view direction vector n. Given the view distance d, the eye position co-ordinates are given by:
162 A Viewing System
________________________________________________________________________
ex = ox + d ∗ nx
ey = oy + d ∗ ny (4.24)
ez = oz + d ∗ nz
or in vector notation, e = o + d ∗ n . (Note that this only applies when the eye position is on the n-axis.
While this is always true for our viewing system, it may not be true for a more generalized viewing system
The view vector has to be calculated for each polygon, which may seem like a fair amount of work.
Could we not perform backface culling after the projective transformations have been applied? The eye
position will have been removed to minus infinity, and so every view vector will parallel to the view
direction vector. A polygon will be visible only if its normal in view space points towards the eye position.
Unfortunately, the amount of work involved in the projective transformation of a polygon is greater than
We can neatly encapsulate the preceding equations and parameters of our minimal viewing system in
#ifndef _VIEW_SYS_H
#define _VIEW_SYS_H
#include "patch3.h"
protected:
double aspect; // Aspect ratio
public:
ViewSys()
A Viewing System 163
________________________________________________________________________
{
aspect = 1.0;
fpd = -0.99;
bpd = 10000.0;
eye = -1.0;
eye_posn = Point3(-1.0, 0.0, 0.0);
origin = Point3(0.0, 0.0, 0.0);
vdv = Vector3(-1.0, 0.0, 0.0);
vuv = Vector3(0.0, 0.0, 1.0);
#endif
Listing 4.1 - VIEW_SYS.H
and:
#include "view_sys.h"
ptm[1][0] = vuv.GetX();
ptm[1][1] = vuv.GetY();
ptm[1][2] = vuv.GetZ();
ptm[1][3] = -(Dot(o, vuv));
ptm[2][0] = vdv.GetX();
ptm[2][1] = vdv.GetY();
ptm[2][2] = vdv.GetZ();
ptm[2][3] = -(Dot(o, vdv));
ptm[3][0] = 0.0;
ptm[3][1] = 0.0;
ptm[3][2] = 0.0;
ptm[3][3] = 1.0;
Only one instance of ViewSys is required for our radiosity renderer. Its constructor positions the
viewing system at the world space origin with its view direction vector aligned with the x-axis in the
negative direction and its view-up vector aligned with the z-axis. The eye position is set at -1.0 and the
front and back plane distances are set to very small and large values respectively. The constructor then
calls BuildTransform to initialize the 3-D projective transformation matrix and determine the eye position.
ViewSys also presents the view distance to the user as a positive number through the functions
GetViewDist and SetViewDist. This is more for the user’s convenience than anything else; its internal
The viewing system parameters can be changed at any time by calling the appropriate class member
functions. However, any change to SetViewDir must be followed with a call to SetViewUp. This call is not
included in SetViewDir, since the user must specify an approximate view-up vector that is not collinear
with the new view direction vector. Once the parameters have been updated, BuildTransform must be
called to calculate the new transformation matrix elements and update the eye position.
166 A Viewing System
________________________________________________________________________
One final comment: the function GetProjMatrix represents one of the least elegant aspects of C++. All
it does is return a pointer to the projective transformation matrix ptm. Unfortunately, C++ function
declarations involving pointers to multidimensional arrays are something only a compiler writer can love.
Again, the objects in our environment consist of collections of 3-D polygons. While we want to project
these polygons onto the view plane, we must consider that a polygon may not be wholly within the view
volume. If it is completely outside, we can simply ignore it. However, it may be only partly within the
volume (e.g., Fig. 4.15). In this case we must somehow clip the portion that is outside the view volume
There are many different polygon clipping algorithms described in the literature, including Liang and
Barsky [1983], Weiler and Atherton [1980], Burkett and Noll [1988] and Vatt [ 1992]. For our purposes
however, we need look no further than the classic Sutherland-Hodgman algorithm (Sutherland and
Hodgman [1974]).
Looking at our view volume, we can imagine it as being the intersection of six clipping planes (Section
4.1.1). The Sutherland-Hodgman algorithm accepts as its input an n-sided polygon modeled as an ordered
list of vertices p 0 , K , p n −1 and clips it against each of these planes in sequence. Vertices within the view
A Viewing System 167
________________________________________________________________________
volume are retained, and new vertices are created wherever a polygon edge intersects one of the clipping
planes. The algorithm’s output is a new set of vertices q 0 , K , q m −1 that represents the clipped polygon.
We can best see how the algorithm works by first examining how it clips a polygon against a single
plane. It considers the vertices p 0 , K , p n −1 one vertex at a time, beginning with p0 . Each vertex pi is
considered to be the end vertex E of an edge of the polygon; the start vertex S is the preceding vertex p i −1 .
The algorithm may generate zero, one or two output vertices of the clipped polygon for each input vertex,
The plane divides the view plane space into two regions: a “visible” region that contains the view
volume and an “invisible” region. This leads to the four possibilities shown in Figure 4.16. First, the edge
may have both vertices in the visible region (Fig 4.16a), in which case the end vertex E is output (the start
vertex will have been previously output). (A vertex actually on the plane is assumed to be in the visible
region.) Second, the edge may have both vertices in the invisible region (Fig. 4.16b), in which case no
vertex is output. Third, the edge may leave the visible region (Fig. 4.16c), with only the start vertex in the
visible region. In this case, the intersection I between the edge and the plane is determined and output as a
vertex. Fourth, the edge may enter the visible region (Fig. 4.16d), with only the end vertex in the visible
region. Here two vertices are output: the intersection I between the edge and the plane, followed by the end
vertex E.
E
Visible region
S E
Invisible region
S
Figure 4.16a - Edge in visible region Figure 4.16b - Edge in invisible region
S E E S
I I
Figure 4.16c - Edge leaving visible region Figure 4.16d - Edge entering visible region
168 A Viewing System
________________________________________________________________________
Looking at Figure 4.17, we can follow the vertices of an arbitrary polygon intersected by a plane to see
that this algorithm works with one exception: the edge from p4 to p0 is not considered. If it crosses the
The solution is to save the first vertex p0 and “close” the polygon by examining the edge from p n −1 to
p0 after all the input vertices have been considered. A final output vertex is generated only if the edge
crosses the plane. (We could instead simply access p0 directly if the vertices are stored in an array.
However, one of the primary advantages of the Sutherland-Hodgman algorithm is that it does not need
intermediate storage for an indeterminate number of input or output vertices. All it needs to store for
p3
p4
p1
I3 I2 Visible
I0 I1 Invisible
p0
p2
Figure 4.17 - Clipping a polygon against a single plane
ENDIF
IF (E in visible region)
Output(E)
ENDIF
S=E
Close(plane) // Close polygon
IF (fflag == TRUE)
IF (edge SF intersects plane)
I = Intersect(S, F, plane)
Output(I)
ENDIF
ENDIF
Figure 4.18 - Sutherland-Hodgman algorithm (single plane)
where polygon is an ordered list of vertices p 0 , K , p n −1 , plane describes the clipping plane, Intersect
computes the intersection of the polygon edge and the plane, and Output generates an output vertex that is
To determine the intersection of a polygon edge and an arbitrary plane, we first need to describe both
objects mathematically. Given an edge with start vertex S and end vertex E, we can define the vector
p(t ) = S + t ∗ r (4.25)
where 0 ≤ t ≤ 1 is the parameter that describes the set of points p(t ) between S and E. For example, if
S = {1, 2, 0} , E = {− 2, 3, 1} and t = 0.7 , then the point p(0.7 ) has the co-ordinates
We can similarly define an arbitrary plane (shown in cross-section in Figure 4.19) using the equation:
nx x + n y y + nz z = d (4.26)
where the coefficients n x , n y and nz are the co-ordinates of the plane normal n and d is the distance from
the origin to the nearest point on the plane. Expressed in vector notation, this gives us the point normal
equation of a plane:
n⋅p = d (4.27)
where p is the bound vector from the origin to any point p on the plane.
170 A Viewing System
________________________________________________________________________
We adopt the convention that the visible region of the plane contains the plane normal n. An arbitrary
vertex p represented by the bound vector p from the origin to the vertex is then:
For example, given a plane with normal n = {2, − 1, 3} and distance d = 3 , its point normal equation
is {2, − 1, 3}⋅ {x, y, z} = 3 . The vertex p = {2, 5, − 1} is in the invisible region, since n ⋅ p = −4 .
y Plane
n
d p
x
Figure 4.19 - Determining the equation of a plane
A polygon edge intersects a plane only if its start and end vertices S and E are on opposite sides. If we
( )
n x ∗ (S x + rx ∗ t ) + n y ∗ S y + ry ∗ t + n z ∗ (S z + rz ∗ t ) = d (4.28)
t=
(
d − nx ∗ S x + n y ∗ S y + nz ∗ S z ) (4.29)
n x ∗ rx + n y ∗ ry + n z ∗ rz
d − n ⋅S
t= (4.30)
n ⋅r
where S is the vector from the origin to vertex S and r = E − S . Substituting t into Equation 4.25 gives us
the co-ordinates of the intersection point. For example, suppose we have a plane with normal
n = {2, − 1, 3} and distance d = 3 . The polygon edge described by the vertices S = {2, 5, − 1} and
Another advantage of the Sutherland-Hodgman algorithm is the ease with which it can be extended to
clip against multiple planes. We could of course clip against each of our six view volume clipping planes
in sequence, saving the intermediate polygon as an ordered list of vertices q 0 , K , q m −1 at each stage.
However, the Sutherland-Hodgman algorithm allows a more elegant approach. Apart from the Intersect
function, the code is identical for each plane. We can make the Clip function reentrant by defining separate
static F and S vertices for each plane. More importantly, we can modify Output such that it recursively
calls Clip for the current vertex and the next plane. In other words, the next clipping stage can begin as
soon as the current stage finds an acceptable vertex. This approach is often used to advantage in hardware
graphics accelerators, where the vertices can be processed in a “pipeline” without the need for intermediate
where the function Put generates the output vertex. The additional logic in Close is needed to ensure that
The behavior of the Sutherland-Hodgman algorithm is quite subtle. Even the authors (Sutherland and
Hodgman [1974]) admitted that “We are somewhat chagrined that the obvious extension of work on line
clipping with which we have been involved kept us so long from seeing the simplicity of the present
approach.” With this in mind, it may help to see the algorithm in action where a polygon is being clipped
P3 I1 P2
Top
I3 I2
Left
P0 I0 P1
Right
Bottom
Ordering the four clipping planes as Left, Right, Top and Bottom, the algorithm proceeds as follows:
We have to be careful when applying the Sutherland-Hodgman polygon clipper to our view volume.
Suppose we have a viewing system with view distance d = −3 and a polygon vertex p with view space co-
ordinates {0, 0, − 4} before perspective transformation. From Equation 4.13, its fourth homogeneous
174 A Viewing System
________________________________________________________________________
co-ordinate is w = − 1 3 , and so p n = 12 after perspective division. This implies that the vertex is behind
the view plane, which is clearly wrong. The vertex is behind our eye position!
The problem is that perspective division eliminates the sign of the vertex’s n-axis co-ordinate. The only
solution is to perform our polygon clipping before perspective division. In other words, we need to clip in
Clipping in four homogeneous dimensions is not as difficult as you might think. To begin with,
remember that we divide the first three homogeneous co-ordinates x, y and z by the fourth co-ordinate w to
obtain the transformed view space co-ordinates. Thus, our clipping plane limits in homogeneous co-
0≤ x≤w
0≤ y≤w (4.31)
0≤ z≤w
The fourth homogeneous dimension w is no different from the first three dimensions. Similarly, aside
from the additional co-ordinate, there is no difference between a 3-D and a 4-D vector. Allowing for the
additional co-ordinate, we can perform the same vector operations, including determining length,
normalization and multiplication by a scalar value. We can also add or subtract two 4-D vectors and
Following Equation 4.26, the point normal equation of a 4-D plane is:
n x x + n y y + n z z + nw w = d (4.32)
where the coefficients n x , n y , nz and n w are the coefficients of the plane normal n and d is the distance
from the origin to the nearest point on the plane. The clipping plane intersection calculations are identical
The plane normal coefficients can be determined from the 4-D clipping plane limits of Equation 4.31.
Consider the back clipping plane. Its 3-D point normal equation is z = 1 , which makes it parallel to the x-y
plane. Thus, n x and n y must both be zero, and so the plane normal must lie in the z-w plane (Fig. 4.23).
A Viewing System 175
________________________________________________________________________
n
Back clipping plane
1.0
z
1.0
From Equation 4.13, we know that any clipping plane in 4-D homogeneous co-ordinates must intersect
the w-axis. Thus, the back plane intercepts the origin in the z-w plane. Similarly, the 4-D plane must
intersect its equivalent 3-D clipping plane for w = 1 . Thus the line must intersect the point {1, 1} in the z-
w plane, giving it a slope of +1. The clipping limits for the z-axis show that the plane normal in the z-w
plane must point towards the w-axis for w > 0 . Finally, the 4-D length of the vector must equal one.
{
Therefore, the back plane normal must have homogeneous co-ordinates 0, 0, − 1 2, 1 }
2 .
By applying similar arguments to the other five clipping planes, we can see that their 4-D homogeneous
normals are:
Front: {0, 0, 1, 0}
Back: {0, 0, − 1 2 , 1 2 }
Left: {1, 0, 0, 0}
Right: {− 1 2 , 0, 0, 1 2}
Top: {0, − 1 2 , 0, 1 2}
Bottom: {0, 1, 0, 0}
While it may be difficult to imagine a clipping plane in four dimensions, polygon clipping in 4-D is not a
problem.
We can implement the Sutherland-Hodgman algorithm within the framework of our viewing system
using four new classes. First, we need a class to handle four dimensional homogeneous vectors:
176 A Viewing System
________________________________________________________________________
// VECTOR4.H - 4-D Homogeneous Co-ordinates Vector Class
#ifndef _VECTOR4_H
#define _VECTOR4_H
#include <math.h>
#include "vector3.h"
public:
Vector4() : Space3() { };
// Normalize vector
Vector4 &Norm()
{
double len = Length();
x /= (float) len;
y /= (float) len;
z /= (float) len;
w /= (float) len;
return *this;
}
// Multiply by scalar s
Vector4 &operator*=( double s )
{
x *= (float) s;
y *= (float) s;
z *= (float) s;
w *= (float) s;
return *this;
}
return temp;
}
return temp;
}
#endif
Listing 4.3 - VECTOR4.H
Vector4 is essentially identical in form to Vector3. Not included in Vector3 are ProjTransform and
Perspective. There are two versions of each function, one for 3-D points and the other for 3-D vectors.
Ideally, these functions should be written using C++ templates. In practice, several major compiler vendors
Next, we need to represent polygon vertices in 4-D homogeneous co-ordinates. The following Vertex4
class is not derived from Vertex3, since we no longer have a need to link polygons together into surfaces
and instances. All we need are the vertex color and its homogeneous co-ordinates. Thus:
#ifndef _VERTEX4_H
#define _VERTEX4_H
#include "patch3.h"
#include "vector4.h"
public:
Spectra &GetColor() { return color; }
Vector4 &GetCoord() { return coord; }
color = c;
}
#endif
Listing 4.4 - VERTEX4.H
The third class implements the pseudocode Put function and output vertex array discussed in Section
4.8.3:
#ifndef _OUT_POLY_H
#define _OUT_POLY_H
#include "vertex4.h"
public:
Point3 &GetPosn() { return posn; }
Spectra &GetColor() { return color; }
color = v.GetColor();
}
}
vertex[MaxOutVert]; // Output vertex array
int num_vert; // Number of vertices
public:
OutPolygon() { num_vert = 0; }
Since an Element3 object represents either a triangular or quadrilateral polygon, the maximum number
of output vertices resulting from clipping against six planes is ten. (To see why, imagine a diamond-shaped
quadrilateral that has been clipped by the side planes into an octagon. Now, rotate this polygon horizontally
about its center so that its top and bottom edges coincide with the boundaries of the front and back clipping
planes with the top and bottom planes. A total of ten vertices will be generated. In general, the maximum
number of vertices resulting from clipping a convex polgon against n planes will be n + 6 .)
This determines the constant value MaxOut and the size of the nested class OutVertex array in
OutPolygon. Only the friend classes ClipEdge and PolyClip4 (described below) are allowed to set the
As was previously noted in Section 4.8.3, hardware graphics accelerators typically implement the
Sutherland-Hodgman algorithm as a pipeline. Révész [1993] noted that each stage of this pipeline can be
modeled in C++ as an object with the same member functions but different data for the clipping plane
normals. The following ClipEdge class builds on this idea by linking together an array of six “edge-plane
clipper” objects, where each object is responsible for clipping and closing a polygon against a single plane.
Finally, we need an executive PolyClip4 class to translate Vertex3 objects into view space vertices and
to clip and close the polygon. This class is also responsible for initializing the array of ClipEdge objects.
#ifndef _P_CLIP4_H
#define _P_CLIP4_H
#include "out_poly.h"
public:
ClipEdge() { first_flag = FALSE; }
public:
PolyClip4();
#endif
Listing 4.6 - P_CLIP4.H
and:
#include "p_clip4.h"
// Clip polygon
int PolyClip4::Clip( Element3 *pelem, OutPolygon &out,
double (*ptm)[4] )
{
int i; // Loop index
int num_vert; // Number of vertices
Vertex3 *pvert; // 3-D world space vertex pointer
Vertex4 hv; // 4-D homogeneous co-ord vertex
num_vert = pelem->GetNumVert();
for (i = 0; i < num_vert; i++)
{
// Get world space vertex position pointer
pvert = pelem->GetVertexPtr(i);
return out.GetNumVert();
}
// Calculate parameter
r = (e.GetCoord() - s.GetCoord());
d = Dot(normal, r);
v.Set(p, color);
return v;
}
if (curr_inside == TRUE)
Output(current, out);
start = current;
start_inside = curr_inside;
}
// Close polygon
void ClipEdge::Close( OutPolygon &out )
{
Vertex4 isect; // Intersection vertex
if (first_flag == TRUE)
184 A Viewing System
________________________________________________________________________
{
// Does edge intersect plane ?
if (start_inside ^ first_inside)
{
isect = Intersect(start, first);
Output(isect, out);
}
In clipping a polygon edge, we must remember that our polygons vertices have color attributes, and the
color of a polygon may vary across its visible surface. ClipEdge::Intersect therefore linearly interpolates
the intersection vertex color from the start and end vertex colors. This assumes that we will later linearly
ClipEdge and PolyClip4 are a more or less straightforward implementation of the Sutherland-Hodgman
algorithm. Readers interested in optimizing their code for speed should examine the C implementation
presented in Heckbert [1990b]. It is production-quality code at its finest: fast, compact and well
documented.
We now have the tools to transform our polygons from world space to view space, perform a
perspective transformation and to clip them to a view volume. Our next step is an intermediate but very
Most computer graphics environments offer at a minimum the ability to display polygons in outline.
That is, given a polygon as an ordered list of vertices in 2-D screen space, we can usually call a C++
graphics library function that will display the polygon as a connected set of lines drawn between its
vertices. By displaying each visible polygon in the view volume, we can create a wireframe display such as
True, these images are somewhat less than photorealistic. On the other hand, wireframe displays can be
generated very quickly. A highly complex environment may take several seconds to a minute or so to
A Viewing System 185
________________________________________________________________________
render, but most of that time will be spent reading in the environment and entity files and clipping the
polygons to the view volume. Since the same image may takes minutes to an hour or more to render using
radiosity methods, the ability to preview it using a wireframe display is often invaluable.
where the C++ graphics library function needed to draw the 2-D polygon is compiler-dependent. We also
need to remember that the output polygon vertices generated by PolyClip4::Clip are in the normalized
device co-ordinates of our canonical view volume, and to use Equation 4.18 to convert them into screen
space co-ordinates.
While we have discussed screen space co-ordinates in terms of a video monitor, we can of course draw
polygons with a laser printer, a pen plotter, a photographic film recorder or (being somewhat ambitious
here) a video recorder to capture animated sequences of images. Regardless of which device we choose, it
186 A Viewing System
________________________________________________________________________
is a safe bet that it will require a unique set of initialization and polygon draw commands. There is no
remedy for this; drawing directly to the display device is an inherently device-specific task.
GUI-based environments such as Microsoft Windows are more forgiving. MS-Windows in particular is
designed to work with a wide variety of video display adapters, monitors and other display devices. With
this in mind, we shall temporarily abandon our device-independent approach and develop a wireframe
display capability for MS-Windows, followed by a discussion of how to emulate it in other GUI
environments.
Since MS-Windows is a GUI-based environment, we shall want to draw our wireframe display inside a
window. This means that the size of the “screen” we are drawing to is not fixed in terms of pixels or scan
lines, since the user can resize it at any time. We can either display a portion of the wireframe display in a
small window or redraw it each time according to the window’s size. Redrawing is a more useful approach,
since we can shrink a window to any size and still see the entire image.
The key to redrawing complex wireframe displays at interactive rates is the graphics metafile. Many
graphics programming environments support this feature (also known as display files or display lists). They
are used to temporarily or permanently store drawing instructions such as “draw polygon”. You can open a
metafile either in memory or on disk and write any number of draw instructions to it to build an image, one
instruction at a time. When you are finished, you close the file and store a metafile “handle” for it. This
allows you to later display the entire image by requesting the Windows manager to “play” the file. Finally,
you can delete the metafile when you no longer need its image.
The advantage of metafiles over writing directly to the display device is that while an image may take
the same amount of time to build, it can be redisplayed at any time with minimal delay. They also conserve
system resources–a metafile typically occupies far less memory or disk space than an equivalent bitmap
file.
The MS-Windows API (Applications Programming Interface) supports metafiles, but only as a loose
collection of C-callable functions. They can be encapsulated in a reasonably robust C++ class as follows:
#ifndef _WIN_META_H
A Viewing System 187
________________________________________________________________________
#define _WIN_META_H
#include <windows.h>
#include <stdio.h>
public:
WinMetaFile()
{
*file_name = '\0';
file_flag = FALSE;
hmdc = NULL;
hmf = NULL;
}
~WinMetaFile() { Erase(); }
if (hmf != NULL)
{
DeleteMetaFile(hmf); // Delete metafile handle
hmf = NULL;
}
if (file_flag == TRUE)
{
unlink(file_name); // Remove metafile
file_flag = FALSE;
}
}
if (hmf != NULL)
{
hdc = BeginPaint(hwnd, &ps);
PlayMetaFile(hdc, hmf);
188 A Viewing System
________________________________________________________________________
EndPaint(hwnd, &ps);
}
}
if (fname != NULL)
{
// Save metafile file name
lstrcpy(file_name, fname);
file_flag = TRUE;
return TRUE;
}
#endif
Listing 4.8 - WIN_META.H
As you may have noticed, WinMetaFile models a videocassette recorder. You call Record to begin
recording an image. Polygons are written to the metafile by calling (what else?) Polygon. Note the global
scope specifier used in the body of this function. Since Polygon is also the name of the MS-Windows API
A Viewing System 189
________________________________________________________________________
function, it has to be called as ::Polygon to avoid an infinite loop. Calling Stop closes the metafile, while
Play displays it in a window indicated by the parameter hwnd. Finally, Erase deletes the metafile.
It should not be too difficult to port WinMetaFile to another GUI environment. Its member functions
are almost completely generic, and the MS-Windows API functions are mostly self-explanatory. The
exception is Play, where BeginPaint initializes the window for drawing and EndPaint requests the
Windows manager to update its display. The functions SetMapMode, SetWindowExt, SetViewPort and
SetWindowOrg are responsible for telling the Windows manager how to position and scale the logical
(screen space) co-ordinates of the wireframe display in the physical co-ordinates of the window.
At worst, you may have to roll your own metafile support for your target environment. All you need is
a “draw polygon” primitive, which is presumably available from your C++ compiler’s graphics library.
The metafile can be a block of memory or a binary file that you fill with polygon records having a structure
similar to:
Number of vertices
Vertex 0 : { float x, float y }
Vertex 1 : { float x, float y }
…
Vertex n : { float x, float y }
where each vertex field contains its floating point x-y co-ordinates. The number of vertex fields in each
polygon record is variable, depending on the value of the leading “number of vertices” field.
These records can be written to the metafile using sprintf or fprintf as required. To play the file back,
read each record using sscanf (or fscanf) and pass the retrieved values as parameters to your “draw
polygon” function.
So where is the wireframe display? Unfortunately, we need more than WIN_META.H to display an
image in an MS-Windows application. After all, displaying “Hello, World” in MS-Windows usually
requires some 200 lines of C source code (e.g., Petzold [1992]). Rather than introducing C and C++ source
code for a full-blown application at this point, we should continue on with the device-independent aspects
Going from a wireframe display to a photorealistic image takes less work than you might think.
However, displaying these images requires a bitmapped display. Our device-independent approach
therefore takes another detour into the intricacies of bitmap file formats.
BMP, PCX, TARGA, TIFF, JPEG … there are innumerable formats to choose from, and a number of
excellent books and technical publications which describe them. Our concern being radiosity, we will not
dwell on their relative merits and peculiarities. Instead, we will simply choose one of the simplest:
Yes, BMP is specific to the Microsoft Windows 3.x and NT environments. If we were to choose a more
platform-independent format, TARGA would be the likely choice. However, the 24-bit RGB version of
Photorealistic images usually require a 24-bit (16.7 million color) RGB color display to do them full
justice. You can display them using an 8-bit (256 color) display by carefully optimizing the color palette,
but the results will not always be satisfactory. Furthermore, you have to generate a 24-bit bitmap first in
order to determine the color gamut and select the 256 colors which best represent it for an 8-bit display.
There are several techniques for color palette optimization, including the popularity and median cut
algorithms (Heckbert [1982]) and octree quantization (Gervautz and Purgathofer [1990]). The latter
technique requires the least amount of memory while still producing good quality images.
As of this writing, most desktop PCs support 8-bit rather than 24-bit color displays. Accordingly, the
diskette accompanying this book includes a standalone utility for generating 8-bit BMP files with
optimized color palettes (using octree quantization) from 24-bit BMP files.
That said, we will design our viewing system to generate 24-bit BMP files. They require more memory
and disk space than do 8-bit BMP files, but their quality is unsurpassed.
BMP is actually the file extension used to identify MS-Windows device-independent bitmap files,
otherwise known as DIB files. While aficionados of other GUIs may dispute the moniker, it certainly
A Viewing System 191
________________________________________________________________________
applies within the MS-Windows environment. A 24-bit color DIB can be displayed on any 24-bit color
Unlike some file formats such as JPEG, 24-bit DIBs are not compressed. The bitmap is a 2-D array of
Note carefully that this data structure reverses the normal R-G-B order of the three members.
A 24-bit DIB file consists of a file header (BITMAPFILEHEADER), a bitmap information header
(BITMAPINFOHEADER), an optional dummy palette (RGBQUAD) and the bitmap array. It has the same
representation in memory, except that the file header is removed. This simple representation make it easy
to both generate DIB files and to convert them to other file formats.
There is one minor complication. The 80x86 CPU architecture segments memory into 64K blocks.
While an array can be larger than 64K, no element of the array can span a 64K block boundary (at least for
16-bit operating systems such as MS-DOS, which underlays Windows 3.1). Each scan line in the bitmap
array must therefore be padded to a multiple of 4 bytes. For example, a bitmap that measures 498 pixels
across requires 1494 bytes of space, but the bitmap row width must be 1496 bytes.
So, assuming once again that our target environment is MS-Windows, we have the following bitmap
class:
#ifndef _WIN_BMAP_H
#define _WIN_BMAP_H
#include <windows.h>
#include <stdio.h>
#include "color.h"
BOOL AllocBitmap();
BOOL WriteBitmap( int );
void FreeBitmap();
public:
WinBitmap()
{
bm_file.bfType = 0x4d42; // 'BM' signature
bm_file.bfSize = 0L;
bm_file.bfReserved1 = 0;
bm_file.bfReserved2 = 0;
bm_file.bfOffBits = (DWORD) (sizeof(BITMAPFILEHEADER)
+ sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD));
bm_info.bmiHeader.biSize = (DWORD)
sizeof(BITMAPINFOHEADER);
bm_info.bmiHeader.biWidth = 0L;
bm_info.bmiHeader.biHeight = 0L;
bm_info.bmiHeader.biPlanes = 1;
bm_info.bmiHeader.biBitCount = 24;
bm_info.bmiHeader.biCompression = BI_RGB;
bm_info.bmiHeader.biSizeImage = 0L;
bm_info.bmiHeader.biXPelsPerMeter = 0L;
bm_info.bmiHeader.biYPelsPerMeter = 0L;
bm_info.bmiHeader.biClrUsed = 0L;
bm_info.bmiHeader.biClrImportant = 0L;
bm_info.bmiColors[0].rgbBlue = 0;
bm_info.bmiColors[0].rgbGreen = 0;
bm_info.bmiColors[0].rgbRed = 0;
bm_info.bmiColors[0].rgbReserved = 0;
pbm = NULL;
hdib = NULL;
hddb = NULL;
width = height = 0;
}
~WinBitmap() { FreeBitmap(); }
#endif
Listing 4.9 - WIN_BMAP.H
The details of the MS-Windows API structures used in this class are not important, as long as they
work. If you need to write an equivalent class for another bitmap file format, you can ignore them
altogether. As you can see, the WinBitmap function prototypes are almost completely generic. (The HDC
data type in Display is a handle to a data structure describing the display device, while POINT and RECT
describe the co-ordinates of a rectangle within the display window.) Their internal details, on the other
#include "win_bmap.h"
if (hddb == NULL)
{
// Convert DIB to device-dependent bitmap
if ((hddb = CreateDIBitmap(hdc, &(bm_info.bmiHeader),
CBM_INIT, (LPSTR) pbm, &bm_info, DIB_RGB_COLORS)) ==
NULL)
return FALSE;
}
status = TRUE;
}
return TRUE;
}
void WinBitmap::FreeBitmap()
{
if (hdib != NULL) // Release DIB memory
{
GlobalUnlock(hdib);
GlobalFree(hdib);
pbm = NULL;
hdib = NULL;
}
width = height = 0;
}
Listing 4.10 - WIN_BMAP.CPP
While WinBitmap is obviously tailored to MS-Windows, you can easily create a similar class for other
environments. The _lopen, _lwrite and _lclose functions are equivalent to the unbuffered creat, open, write
and close functions available in K&R and most UNIX C compilers (but not Standard C). If you are not
fettered with 80x86 segmented architecture restrictions, you can replace them with fopen, fwrite and fclose.
Similarly, GlobalAlloc, GlobalLock, GlobalUnlock and GlobalFree can be replaced with new and delete.
MS-Windows cannot display a device-independent bitmap (DIB) directly. Instead, Display has to
convert the DIB to a device-dependent bitmap (DDB) by calling CreateDIBitmap. This bitmap is
compatible with the current display device, but it first has to be linked to a “memory device context” by
A Viewing System 197
________________________________________________________________________
calling CreateCompatibleDC before it can be “bit-blitted” to the display window. Both the DIB and DDB
are kept in memory to allow the bitmapped image to be displayed or written to a file at any time.
If you need to port Display to another environment, you will likely find that it has similar functions. If
not, you will have to find some other way of displaying the DIB. Fortunately, this should not be too
difficult–a 24-bit RGB bitmap is probably the lowest common denominator of all bitmap file formats.
That’s about it for device-dependent code. WinBitmap allows us to allocate memory for a bitmap using
Open, set individual pixels with SetPixel, create a DIB (BMP) file using Write, and release the bitmap
memory with Close when we are done. We can now look at what we why we need a bitmap class in the
first place.
Taking another step towards our goal of photorealistic images, we now consider how to draw a filled
polygon to an arbitrary bitmap. Surely this is a trivial problem! After all, all we want to do is to draw a
polygon outline and then fill its interior with pixels of whatever color we choose. Most graphics libraries
On closer inspection though, it becomes evident that we have to be careful. While filling an isolated
polygon is not all that difficult, we need to ensure that adjacent polygons will always be drawn such that
there are no overlapping or missing pixels along their shared edges. Figure 4.26 shows a filled polygon as a
graphics library function might display it on a video monitor. However, the edge pixels of this polygon
0 8
Figure 4.26 - Filling polygons - a naive approach
198 A Viewing System
________________________________________________________________________
We can avoid this problem by adopting some rigid rules regarding the plotting of edges and vertices.
Recalling Section 4.4, we convert from view space to screen space co-ordinates by truncating the floating
point view space values. A pixel with integer screen space co-ordinates {x, y} therefore has continuous co-
1 1
ordinates x + , y + , and can represent any pair of view space co-ordinates ranging from x to x + 1
2 2
along the x-axis and y to y + 1 along the y-axis. Based on this, we can avoid overlapping and missing
pixels if we:
2. Plot a polygon that extends from scan line co-ordinates y min to y max as scan lines y min to y max − 1 .
3. Plot a scan line segment that extends from pixel co-ordinates x min to x max as pixels x min to
x max − 1 .
The first rule makes sense, since any horizontal edge will be automatically drawn by the scan line
connecting its vertices. The second rule implies that we should not draw the top scan line of a polygon,
whether it is a single pixel or a horizontal scan line. This prevents any overlap with the bottom scan line of
a polygon of an adjoining polygon. Similarly, the third rule implies that we should not draw the right edge
of a polygon, again to avoid overlapping pixels. It also implies that we should not plot a scan line where
x min = x max .
It may take a few tries with pencil and paper to convince yourself, but these rules do work (e.g., Fig.
4.27). True, they do have a few shortcomings. Edge-on polygons are not displayed (which is usually
desirable), small polygons may be distorted from their true geometrical shapes, and thin polygonal slivers
may have missing pixels where x min = x max . In addition, all polygons are displaced by up to one-half pixel
to the left and downwards from their true positions. While some of these deficiencies can be corrected by
employing a larger and more complex set of rules, they are usually not worth bothering about.
A Viewing System 199
________________________________________________________________________
0 8
Figure 4.27 - Filling polygons - a better approach
Implementing these rules can be a challenge, particularly if we allow concave polygons and polygons
with edges that cross each other. However, our polygons are invariably convex (Section 3.4), which
We begin by noting that a horizontal scan line can only intersect a convex polygon at one or two points
(i.e., a vertex or two edges). For each scan line then, we need to store information about at most two
intersection points. (This is not true for a concave polygon with an arbitrary number of edges.)
Referring to our OutPolygon class (Section 4.8.6), each output vertex has a 3-D position and a color,
where the n-axis component of its position is the pseudodepth. If a scan line intersects an edge, we can
determine the intersection’s pseudodepth by linearly interpolating between the edge’s vertices. We can
similarly determine the intersection’s color by linearly interpolating each of the three color bands between
the vertices. (We will see why we do this in the following section.) This gives us a data structure
something like:
Suppose we allocate an edge list, a 2-D array of ScanInfo structures, arranged as two columns (one for
each intersection) by however many scan lines (i.e., rows) are in our bitmap. Each polygon edge is
represented by a pair of adjacent vertices in its vertex array. By stepping through the vertex array, we can
compute the x-axis intersection of each scan line with each polygon edge (with appropriate allowances for
200 A Viewing System
________________________________________________________________________
Rules 1 and 2 above), interpolate the intersection pseudodepth and color, and enter the data into the edge
list.
Once all the edges have been entered (or scan converted) into the edge list, we can step through the list
and for every valid entry plot the pixels of the scan line segment between the x-axis points indicated by
Calculating the x-axis co-ordinate of each scan line-edge intersection requires a digital differential
analyzer (DDA) algorithm. Terminology aside, this means we have to determine the floating point
incremental change in x for each integer scan line step in y for each edge. Then, given a pair of vertex co-
ordinates {sx, sy} and {ex, ey} where ey > sy , we execute the following algorithm:
x = sx
m = (ex − sx ) (ey − sy )
FOR y = sy TO y < ey
SetPixel(x, y, color )
x += m
ENDFOR
Figure 4.28 - Digital differential analyzer pseudocode
where x and m (which is the inverse slope of the edge) are floating point numbers.
An integer-only version of this algorithm is possible (Swanson and Thayer [1986]). It is much like the
classic Bresenham line scan algorithm (e.g., Foley et al. [1990]), except that only one point per scan line is
computed. The following example is adapted from Fleisher and Salesin [1992]:
#include <stdio.h>
#include <stdlib.h>
public:
int FloorDiv( int, int );
void Setup( int, int, int, int );
void Scan( int, int );
};
int main()
A Viewing System 201
________________________________________________________________________
{
int x0, x1, y0, y1;
IntDDA dda;
char buffer[80];
if (y1 != y0)
{
dda.Setup(x0, y0, x1, y1);
dda.Scan(y0, y1);
}
else
printf("Horizontal line\n");
return 0;
}
si = FloorDiv(dx, dy);
xi = x0;
sf = dx - si * dy;
r = 2 * sf - dy;
inc = sf;
dec = sf - dy;
}
This is an example only! While it is definitely faster than an equivalent floating point implementation
(at least for the Intel 80x86 architecture; floating point and integer calculations on RISC CPUs are typically
comparable in speed), it represents only a small part of the time needed to render a photorealistic image.
Also, the forthcoming code is going to be difficult enough to follow without it. We will use the floating
point version shown in Figure 4.28; Listing 4.11 is provided for those readers interested in improving the
Now that we can draw a filled polygon to a bitmap without overlapping or missing pixels, we can ask
what color or colors should be passed to SetPixel. Recalling our initial discussion of the radiosity approach
in Section 2.4, let us assume that we know the radiance of a polygon. More accurately, we assume that we
know its average spectral radiant exitance in each color band. Converting this into a ColorRGB class object
gives us a 24-bit color that we can use to fill the polygon when we draw it in our bitmap.
This simple approach has one major disadvantage. Adjacent polygons representing a contiguous
surface may have different colors. If the polygons are small and numerous, we will probably perceive the
surface as having a continuous gradation of color when we view it in a bitmap image. As we zoom in for a
closer look, however, the individual polygons will occupy more of the display screen. At some point the
Henri Gouraud (Gouraud [1971]) addressed this problem by assigning individual colors to a polygon’s
vertices rather than a single color to the entire polygon. Colors are then linearly interpolated at each scan
line-edge intersection (as we just did in scan converting a polygon edge above) and also along each scan
A Viewing System 203
________________________________________________________________________
line segment between the edge intersections. The result is a smoothly varying color gradation across the
entire surface.
D
y1 y3
I1 P I2
y2
A y4
x1 x2
where:
x2 A ∗ y1 + D ∗ y 2 x1 D ∗ y 4 + C ∗ y3
P= ∗ + ∗ (4.33)
x1 + x 2 y1 + y 2 x1 + x 2 y3 + y 4
and where A, C, D and P are the Spectra color band values of interest at the polygon and vertices and
pixels. However, it is also an incremental technique that proceeds exactly as our DDA algorithm above.
Instead of x-y vertex and pixel co-ordinates, we have three Spectra color band values for each vertex.
These simply replace the x-axis co-ordinates in Figure 4.28. Implementing the linear interpolation as the
One of the primary advantages of Gouraud shading is that it is extremely simple and fast, particularly
when it can be implemented in a hardware graphics accelerator. On the downside are its disadvantages.
The worst of these is that the interpolated color of an interior point is dependent on the orientation of a
quadrilateral polygon in screen space. (Apply Equation 4.33 to a point inside a rectangle, then do the same
after rotating the rectangle through 45 and 90 degrees.) This means that different views of an environment
may result in noticeably different color gradations across large quadrilateral polygons. Fortunately,
Another problem occurs when polygons have “T-vertices”, where the vertex of one polygon lies on the
edge of another. Again, there may be undesirable color artifacts in the rendered image. Since both T-
vertices and quadrilateral polygons can be eliminated by subdividing the polygons into triangles (see
It must be remembered, however, that Gouraud shading provides linear color interpolation only. This
can result in first derivative discontinuities across polygon edges, where the slope of the color gradation
changes abruptly. Unfortunately, the human visual system can be acutely sensitive to such changes. The
visual effect is called Mach banding (e.g., Foley et al. [1990]), and can be quite noticeable on what should
be evenly shaded surfaces. Cohen and Wallace [1993] discuss this problem and review several possible
solutions. These are advanced rendering techniques that are beyond the scope of this book. For our
purposes, Gouraud shading provides a useful and effective color rendering technique for radiosity images.
Our final problem really is a trivial one. Looking into a real 3-D environment, we see objects obscuring
one another. Backface culling eliminates those surfaces that are directed away from our line of sight, but it
does not solve the problem of hidden surface elimination. How do we determine whether a visible polygon
There have been numerous hidden surface elimination algorithms developed over the years–Sutherland
et al. [1974] and Rogers [1985] offer excellent summaries. In recent years, however, the availability of
sufficient memory has made a brute force technique known as the Z-buffer algorithm (Catmull [1974]) the
Think of a geometrical ray extending from our eye position through a screen pixel and into the
environment (Fig. 4.30). This ray may intersect one or more visible polygons, each of which will be
Suppose we assign a “depth” value to the ray (or equivalently, the pixel) and initialize it to infinity.
Then, as we scan convert each visible polygon, we determine the pseudodepth of the point where the ray
intersects the polygon surface. If this value is less than the current ray depth, we plot the pixel in the
bitmap and set the ray depth to this value. In other words, the polygon is visible at this point. If, on the
other hand, the polygon’s pseudodepth at the point of intersection is equal to or greater than the current ray
depth, then the polygon is hidden at this point and we do nothing but continue on to the next pixel or
polygon.
Of course, we need a depth value for each pixel in our bitmap. This can require a lot of memory.
Assuming we use a 16-bit float data type, a 1024 × 768 bitmap will require 1.5 megabytes of RAM
memory! It should come as no surprise that graphics workstations usually have dedicated Z-buffers. For
personal desktop computers, we must either have the memory available or limit our maximum bitmap sizes
accordingly. (An alternative is to successively apply the Z-buffer algorithm to bands of scan lines. This
limits the amount of memory required, but at the expense of scanning the list of polygons to be displayed
Much of the Z-buffer algorithm is identical in form to the polygon fill and Gouraud shading algorithms.
Similar to linear color interpolation for Gouraud shading, we can substitute the pseudodepth for the x-axis
co-ordinates in our DDA algorithm (Figure 4.28). Even better, we can combine all three algorithms into
one procedure. We can also perform color mapping (to grayscale or pseudocolor), gamma correction and
color jittering (Section 3.5) immediately before writing the pixel to the frame buffer. This gives us:
The Z-buffer algorithm has one minor disadvantage. Remember that perspective projection distorts the
view space n-axis (depth), resulting in a pseudodepth scale (Section 4.3). It may happen that two distinct
floating point depth values are mapped to the same pseudodepth, due to the limited precision of the float
data type. Consequently, a polygon that should be hidden may be displayed or vice versa. This problem can
be alleviated only by increasing the number of bits used to represent the Z-buffer pseudodepth. For a C++
software implementation, this means going to a double representation, with its consequent doubling of the
Z-buffer memory requirements. (An unsigned long data type could be used for an integer-only version.)
Fortunately, typical radiosity images rarely require this level of pseudodepth precision.
A Viewing System 207
________________________________________________________________________
As Figure 4.31 indicates, we can incorporate our polygon fill, Gouraud shading and hidden surface
#ifndef _P_RENDER_H
#define _P_RENDER_H
#include <limits.h>
#include "out_poly.h"
#include "gamma.h"
#include "c_jitter.h"
#include "win_bmap.h"
public:
PolyRender()
{
gamma_flag = TRUE;
jitter_flag = FALSE;
color_type = PR_RGB;
}
#endif
Listing 4.12 - P_RENDER.H
and:
#include "p_render.h"
height = pbmap->GetHeight();
width = pbmap->GetWidth();
return FALSE;
}
}
}
else
{
delete [] edge_list; // Release edge list memory
return FALSE;
}
return TRUE;
}
// Render polygon
void PolyRender::Render( OutPolygon &out )
{
GetVertexInfo(out); // Get vertex information
ScanEdges(); // Scan convert edges
DrawEdgeList(); // Draw edge list
}
if (psv->screen.y == pev->screen.y)
{
continue; // Ignore horizontal edges
}
dc.SetRedBand((pev->color.GetRedBand() -
psv->color.GetRedBand()) / (float) y_dist);
dc.SetGreenBand((pev->color.GetGreenBand() -
psv->color.GetGreenBand()) / (float) y_dist);
dc.SetBlueBand((pev->color.GetBlueBand() -
psv->color.GetBlueBand()) / (float) y_dist);
pedge = &(edge_list[ymin]);
for (y = ymin; y < ymax; y++)
{
// Get scan line info pointers
pss = &(pedge->isect[0]);
pse = &(pedge->isect[1]);
dc.SetRedBand((pse->color.GetRedBand() -
pss->color.GetRedBand()) / (float) x_dist);
dc.SetGreenBand((pse->color.GetGreenBand() -
pss->color.GetGreenBand()) / (float) x_dist);
dc.SetBlueBand((pse->color.GetBlueBand() -
pss->color.GetBlueBand()) / (float) x_dist);
switch (color_type)
{
case PR_RGB: // RGB color
rgb.SetColor(ic);
break;
default:
break;
}
if (gamma_flag == TRUE)
{
// Perform gamma correction
gamma.Correct(rgb);
}
if (jitter_flag == TRUE)
{
// Perform color reduction
jitter.Reduce(&rgb, x, y);
}
algorithms discussed in the previous three sections. Open dynamically allocates memory for a Z-buffer and
an edge list that are sized according to the dimensions of the bitmap, while Close releases it when it is no
longer needed.
A large bitmap may require a megabyte or more of memory for its Z-buffer. Rather than allocating this
memory in one monolithic block, Open requests it one scan line at a time. The details of this technique
(including a discussion of its advantages and disadvantages) are explained in a text file included with the
214 A Viewing System
________________________________________________________________________
diskette accompanying this book. As currently implemented, PolyRender assumes that the entire Z-buffer
will be allocated from physical memory and that it will not be paged to disk by a virtual memory manager
while DrawEdgeList is being executed. This should only be a concern for pre-emptive multitasking
environments such as Windows NT and UNIX. If paging does occur, the scan conversion execution time
There are two minor discrepancies between our environment and viewing system models that we need
to resolve. First, reflectance and initial exitance values are only defined for surfaces. When Parse reads an
environment data file, it sets the vertex exitances to zero. However, we need these exitances in order to
One trivial solution is to simply copy the appropriate surface reflectance values to the exitance of each
vertex. Since vertices are shared by patches and elements but not surfaces, each surface will be displayed
as having a solid color. This will prove useful later on as a quick means of displaying color images. If
nothing else, it will let us determine whether our polygon rendering software is functioning properly.
The second discrepancy is somewhat more involved. Recalling our discussion of radiosity theory in
Chapter Two, radiosity methods generally (but not always) calculate the final exitance of each element.
Again, we need transfer these exitances to the element vertices in order to display them. The problem here,
of course, is that each vertex may be shared by one or more elements (but not adjoining surfaces).
What we are trying to model is a continuously shaded surface. Figure 4.32 shows a cross-section
through a surface with its exitance plotted as a continuously varying function above it. The vertex
exitances sample this function at the position of each vertex on the surface. Similarly, the element exitances
sample the function at the center of each element. Given only the element exitances as a result of our
Vertex exitance
Element center exitance Exitance
Surface
Figure 4.32 - Sampling the continuous exitance distribution across a surface
This is a common problem in many different fields of mathematics and engineering (particularly finite
element methods, which are closely related to the radiosity problem). Of course, we do not know the exact
exitance distribution across the surface. All we can do is to interpolate a reasonable approximation.
The easiest solution is to use piecewise linear interpolation. In the one-dimensional example shown in
Figure 4.32, we simply draw a straight line between each pair of element exitances and interpolate the
vertex exitances where they intersect the lines (Fig. 4.33). We can clearly extend this approach to 2-D
surfaces by using piecewise bilinear interpolation. This can be applied to both triangular and quadrilateral
Surface
Figure 4.33 - Piecewise linear interpolation of vertex exitances
An even simpler approach is to assume that the elements form a regular spaced grid across the surface.
If this is true, then each vertex exitance can be interpolated by averaging the exitances of the elements that
share the vertex (Fig. 4.34). The technique is called nodal averaging. It has an advantage over bilinear
interpolation in that we do not need to account for the dimensions of each element.
216 A Viewing System
________________________________________________________________________
3 4 4
3.5 4.0 4.5 4.5
4 5 5
3.0 4.0 5.75 6.5
2 5 8
2.0 3.0 6.5 8.0
Element exitances Interpolated vertex exitances
One problem with piecewise bilinear interpolation is that the surface shading becomes discontinuous at
the element boundaries. This may lead to visible Mach bands (see Section 4.13) extending across what
should be smoothly shaded surfaces. There are several solutions to this problem, but they are beyond the
scope of this book. See Cohen and Wallace [1993] for a detailed discussion and references to the
associated literature. For our purposes, nodal averaging will generally provide quite adequate results.
Another problem we have to address is that of tone reproduction. The human eye is capable adapting to
a very wide range of average scene luminances. We can see during broad daylight as well as by starlight–a
truly astounding luminance range of nearly ten trillion to one. Unfortunately, our methods of reproducing
these scenes have luminance scales ranging from 50:1 (four-color printing) to 1000:1 (photographic
Our radiosity methods will accurately calculate the exitances that we need to display a photorealistic
image. However, if these images include any light sources, that is likely all we will see. Their exitances
may be in excess of the other surfaces by a factor of 100:1 or more, in which case our display devices will
be unable to render them and the surfaces at the same time. This is not what we see when we look at a
typical scene in real life. We need to devise a tone reproduction technique that compensates for this
problem.
One ad hoc but usually satisfactory solution is to scale the vertex exitances according to the vertex with
the greatest reflected exitance. That is, each exitance value is scaled such that the greatest reflected
A Viewing System 217
________________________________________________________________________
exitance (in whichever color band of the Spectra data type) is assigned a value of slightly less than 1.0. If
the exitance of a light source exceeds this value, it is individually scaled to equal 1.0 (again in whichever
color band) as well. This ensures that the light sources will be displayed in their proper colors. They will
also appear as the “brightest” objects in the image, closely approximating what we would expect to see. We
#ifndef _TONE_REP_H
#define _TONE_REP_H
#include "instance.h"
#endif
Listing 4.14 - TONE_REP.H
and:
#include "tone_rep.h"
pvert = pvert->GetNext();
}
pinst = pinst->GetNext();
}
}
pel = pel->GetNext();
num_elem++;
}
pvert = pvert->GetNext();
}
pinst = pinst->GetNext();
}
}
pvert = pvert->GetNext();
}
pinst = pinst->GetNext();
}
pvert = pvert->GetNext();
}
pinst = pinst->GetNext();
}
}
}
Listing 4.15 - TONE_REP.CPP
ToneRep is a catch-all class that also implements the vertex shading and exitance interpolation
discussed in Section 4.16. In that it has no data members, ToneRep should not even be an independent class
at all. Unfortunately, there are no other classes that these functions can be logically assigned to.
220 A Viewing System
________________________________________________________________________
Exitance normalization has no physical justification–it simply produces results that are visually
appealing. The reality is much more complicated. We can clearly sense whether a room is dark or brightly
lit, and we can definitely tell the difference between starlight and sunlight! Unfortunately, our approach
Fortunately, there is a growing body of literature on tone reproduction algorithms that takes the
observer into account. Two papers of particular interest are Meyer [1986] and Tumblin and Rushmeier
[1993] (see also Barbour and Meyer [1992]). This will undoubtedly become a more important topic as
Finally, it is possible to store floating point color representations using 32 bits (four bytes) per pixel
(Ward [1991]). Each color is represented by an eight-bit mantissa, followed by an eight-bit exponent.
While this does not address the limited dynamic range of most display media, it does allow the user to
That’s it–we finally have all the components we need to construct our viewing system! We can model
this system as a synthetic camera, with a wireframe display as its viewfinder and a bitmap file as its film.
As we saw in Section 4.1, changing the view distance is equivalent to changing the focal length setting of a
zoom lens.
The viewfinder image lets us preview our image, and to adjust the camera’s position and orientation.
Once we have the desired composition, we can “shoot” a fully rendered view of the environment. We can
even “crop” the image by specifying the bitmap width and height, and we can choose our film (RGB,
Implementing this model requires ViewSys for the viewing system, PolyClip4 for clipping the polygons,
PolyRender to render them, WinMetaFile for the wireframe display and WinBitmap for the bitmap file
manager. The following SynCamera class provides a wrapper that makes it easier to access these classes
#ifndef _SYN_CAM_H
#define _SYN_CAM_H
A Viewing System 221
________________________________________________________________________
#include "instance.h"
#include "p_clip4.h"
#include "p_render.h"
#include "win_meta.h"
#include "win_bmap.h"
#include "view_sys.h"
#ifdef _NOT_WINAPP
struct POINT // Raster display point
{
int x; // X-axis co-ordinate
int y; // Y-axis co-ordinate
};
#endif
public:
SynCamera( int w, int h, double vdvh, double vdvv,
double vuph, double vupv ) : ViewSys()
{
width = w; height = h;
vdv_horz = vdvh; vdv_vert = vdvv;
vup_horz = vuph; vup_vert = vupv;
aspect = (double) w / (double) h;
SetViewDirVector(vdvh, vdvv);
SetViewUpVector(vuph, vupv);
UpdateViewSystem();
EnableGamma();
}
#endif
Listing 4.16 - SYM_CAM.H
Our ViewSys class represents the viewing system’s orientation in rectangular co-ordinates. To this
SynCamera adds a set of spherical co-ordinates, mostly as a convenience for the application program’s user
interface, and information about the width and height of the bitmap.
SynCamera also adds to ViewSys the ability to preview and shoot a view of an environment:
#include "spheric3.h"
#include "syn_cam.h"
ppatch = psurf->GetPatchPtr();
while (ppatch != NULL)
{
// Determine patch visibility
if (BackFaceCull(ppatch) == FALSE)
{
// Walk the element list
pelem = ppatch->GetElementPtr();
while (pelem != NULL)
{
// Clip the 3-D element (polygon)
num_vert = clipper.Clip(pelem, out,
GetProjMatrix());
pelem = pelem->GetNext();
}
}
ppatch = ppatch->GetNext();
}
psurf = psurf->GetNext();
}
pinst = pinst->GetNext();
}
return pmeta->Stop(); // Stop metafile recording
}
pelem = pelem->GetNext();
}
}
ppatch = ppatch->GetNext();
}
psurf = psurf->GetNext();
}
pinst = pinst->GetNext();
}
vdv_horz = h; vdv_vert = v;
angle.SetVert(DegToRad(v));
angle.SetHorz(DegToRad(h));
angle.SpherToRect(&view_dir);
SetViewDir(view_dir);
}
{
Spheric3 angle; // View-up vector angles (radians)
Vector3 view_up; // View-up vector
vup_horz = h; vup_vert = v;
angle.SetVert(DegToRad(v));
angle.SetHorz(DegToRad(h));
angle.SpherToRect(&view_up);
SetViewUp(view_up);
}
Listing 4.17 - SYN_CAM.CPP
Preview implements the wireframe display pseudocode presented in Figure 4.25 with one difference:
the “display device” is a metafile. It sets the metafile to record mode, then walks through the linked list of
polygons representing the parsed environment, performing backface culling, clipping and co-ordinate
conversion before drawing the visible polygons to the metafile. The metafile recording is stopped when all
of the polygons have been processed. Playing the completed metafile afterwards is the responsibility of the
application program.
Shoot is almost identical to Preview. Instead of drawing the visible polygons to a metafile, however, it
renders them in a bitmap. (The PolyRender class performs its own co-ordinate conversion.) Again, the
Finally, UpdateViewSystem should be called to update the view system’s aspect ratio and
transformation matrix whenever any of the view system parameters are changed, either through
SetViewDirVector or SetViewUpVector, or through calling one of the ViewSys public member functions
such as ViewSys::SetOrigin.
We have written some 2,500 lines of C++ source code so far, but does it work? The only way to answer
this question–and to provide a non-trivial example of its use–is to build an application around it. Rather
than writing a demonstration program, we might as well bite the bullet and develop a complete user
Our program development and target environments will be the same: Microsoft MS-Windows. The
following code is therefore completely and unabashedly concerned with MS-Windows programming. In
226 A Viewing System
________________________________________________________________________
that this book is not about MS-Windows programming tricks and techniques, the commentary will not
address Windows-specific programming issues or belabor porting the code to other environments.
The good news is that the following application program does little more than provide pull-down
menus and pop-up dialog boxes for the user. If you need to write a user interface for another platform, your
best bet is to emulate the interface of the MS-Windows executable provided on the accompanying diskette.
Porting MS-Windows source code verbatim to another GUI environment is not recommended unless you
are fully familiar with the MS-Windows API (see Petzold [1992]).
A few specifications before we begin. Naturally, our program should display both wireframe and
bitmapped images. MS-Windows does this with relative ease, with the added bonus that it is device-
independent. Unlike its underlying MS-DOS operating system, MS-Windows 3.1 is fully cognizant of its
display device’s capabilities. We thankfully do not have to concern ourselves with the many varieties of
video display adapters and their arcane programming requirements. (The same capabilities are of course
Beyond this, we should take full advantage of the graphical user interface provided MS-Windows. In
particular, we should have pull-down menus and their options that provide the following:
Menu Options
_______________________________________________________________________
File Open File dialog box to open world (environment) files.
Save As dialog box to save the displayed bitmapped image as a BMP file.
Directories dialog box to specify a path to where the entity files can be found.
Camera Camera Parameters dialog box to set the view distance, the front and back clipping plane
View View Parameters dialog box to set the eye position, view direction vector and view-up
Render Wireframe menu item to display a wireframe image of the specified view of the
environment.
Shaded menu item to display a full-color (but not photorealistic) view of the environment.
A Viewing System 227
________________________________________________________________________
Rendering menu item to perform the radiosity calculations and display a photorealistic view
of the environment.
Redisplay menu item to redisplay the bitmapped image without having to repeat the radiosity
calculations.
Options Convergence dialog box to specify the maximum number of allowed iterations for solving
the radiosity equation (see Chapter Six), to specify a “stopping criterion” (see below), and to
toggle the “ambient exitance” and “positive overshoot” features (to be discussed in Chapter
Six).
Display Parameters dialog box to enable or disable gamma correction and to specify a
gamma correction value (see Section 3.5.1), to enable or disable color jittering and to specify
a “noise level” value (see Section 3.5.2), and choose 24-bit color, grayscale or pseudocolor
This short list completely describes our user interface requirements. It accepts an environment files,
allows us to specify a view of the environment, and displays both wireframe and bitmapped images. We
As for the Rendering and Convergence menu items, we have yet to develop our radiosity rendering
code. All we can do for now is provide the following do-nothing base class:
#ifndef _RAD_EQN_H
#define _RAD_EQN_H
#include "environ.h"
#include "tone_rep.h"
void CalcAmbient();
void CalcInterReflect();
void InitExitance();
void UpdateUnsentStats();
public:
RadEqnSolve()
{
amb_flag = FALSE;
max_step = 100;
stop_criterion = 0.001;
}
#endif
Listing 4.18 - RAD_EQN.H
A quick preview: RadEqnSolve will later serve as a base class for one of several radiosity equation
solvers (described in Chapter Six). It will accept a pointer to a parsed environment and then compute the
polygon vertex colors needed to generate a photorealistic image. We call GetStatus to ensure that the
derived class object was properly constructed. If so, we call Open to initialize the equation solver. If this
function returns TRUE, we then repeatedly call Calculate until it returns TRUE.
The radiosity equation solvers are iterative procedures that begin with a trial solution and successively
refine it with each call to Calculate. The max_pass member specifies the maximum number of allowed
A Viewing System 229
________________________________________________________________________
iterations before the derived Calculate function returns TRUE. The stop_criterion member provides a
single quantity that Calculate will use to determine whether the latest solution is “close enough.”
Once Calculate returns TRUE, we can call ToneRep::Interpolate (if necessary) and
ToneRep::Normalize to generate element vertex exitances that are suitable for viewing purposes. The
Shade is not really part of a radiosity equation solver, since it only calls ToneRep::Shade to set the
vertex exitances to their parent surface reflectances (Section 4.17). Nevertheless, it is convenient to include
it with RadEqnSolve.
Finally, calling Close releases any memory that was dynamically allocated to the equation solver.
RadEqnSolve has a number of other functions whose purpose will become evident in Chapter Six. In
this base class, they essentially return dummy values that we can ignore. This requires the following set of
“stub” functions:
#include "rad_eqn.h"
void RadEqnSolve::CalcAmbient() { }
void RadEqnSolve::CalcInterReflect() { }
void RadEqnSolve::InitExitance() { }
void RadEqnSolve::UpdateUnsentStats() { }
Listing 4.19 - RAD_TMP.CPP
which do nothing other than allow us to continue our development without having to come back and
change the code later on. RAD_TMP.CPP is a temporary file that will be replaced by RAD_EQN.CPP in
Chapter Six.
That’s it for platform-independent code in this chapter. The rest of our application program is entirely
Our bitmapped image can be whatever size we choose, subject only to the limits of available memory.
As such, it may be larger than our display screen. To view the image in its entirety, we need to implement
scroll bars. These are traditionally implemented in C within the dreaded “big switch” statement of
230 A Viewing System
________________________________________________________________________
WinMain. (e.g., Petzold [1992]). However, the same code must be repeated for every child window that
requires scroll bars. In C++, it makes more sense to create a scroll bar control class:
#ifndef _WIN_SBAR_H
#define _WIN_SBAR_H
#include "general.h"
public:
WinScroll( HWND hw)
{
RECT rect; // Rectangle structure
curr_pos.x = curr_pos.y = 0;
max_range.x = max_range.y = 0;
inc.x = inc.y = 0;
hwnd = hw;
GetClientRect(hwnd, &rect);
size.x = rect.right;
size.y = rect.bottom;
Hide();
}
#endif
Listing 4.20 - WIN_SBAR.H
where a WinScroll object is dynamically created for each window when the WM_CREATE message is
As for the public member functions, Pos returns the current scroll bar button positions, Hide hides the
scroll bars from view, Init initializes the scroll bars for a given bitmap image, Set reinitializes the scroll
A Viewing System 231
________________________________________________________________________
bars after the window has been resized, and Horz and Vert process messages from the mouse and
#include "win_sbar.h"
GetClientRect(hwnd, &rect);
size.x = rect.right;
size.y = rect.bottom;
}
Listing 4.21 - WIN_SBAR.CPP
WinScroll can be considered much like any other set of library functions: a black box. As long as it
works, we need not concern ourselves with the details. We will see an example of its use shortly, but first
API is not designed for C++. Worse, the dreaded “big switch” statement in WinMain can be hidden but not
ignored. Several C++ compiler vendors market class libraries designed to make Windows development in
Lacking an industry standard C++ compiler for MS-Windows (there are currently two strong
contenders and several dark horses), we must take the traditional approach of programming in C. We
thankfully do not have to abandon our C++ code, since C and C++ can (by design) coexist quite nicely.
In fact, the only real problem lies in C++’s delightful habit of “name mangling”. While this may be
necessary in order for the linker and debugger to distinguish between class functions with the same name,
it wreaks havoc with callback functions (i.e., functions that are called by Windows rather than your own
code). You declare your callback functions (such as MainWndProc) in the EXPORTS section of your
module definition (.DEF) files. If the C++ compiler changes the names of these functions from
“func_name” to something like “?func_name@@YAHH@Z”, your linker will be unable to resolve (i.e.,
There are two solutions. First, you can add the _export keyword to the function prototypes and remove
the function declarations from your .DEF file. Unfortunately, this precludes using ordinals to identify the
EXPORTS
MainWndProc @1
About @2
Ordinals serve two purposes. One, Windows can process them faster, since it can use the ordinal to
directly index a function pointer table instead of first matching a text string when calling the function.
234 A Viewing System
________________________________________________________________________
Two, they hide the function names from people doing reverse engineering–an important issue for
commercial applications.
You could write your program using _export, then use the EXEHDR utility to look up the C++
mangled function names, add them to your .DEF file with accompanying ordinals, remove the _export
The second and simpler solution is to write the callback functions in C and declare them as such using
C++’s extern “C” mechanism. The C++ compiler considers them to be C functions and compiles them
without name mangling. This allows you to declare them in your module definition file as is and with
ordinals.
No, this book is not about MS-Windows programming. However, finding this particular information in
One more comment regarding programming issues. Many older books on MS-Windows 3.x
programming recommend using the medium memory model. This advice made sense when MS-Windows
3.0 could run in real mode on an Intel 80286 or 8088 CPU. However, support for this mode was thankfully
dropped from MS-Windows 3.1, which runs in standard or enhanced mode only. (Of course, there are no
Another argument is that by using near rather than far pointers, a medium model program runs faster.
While this may be true, the difference is usually minimal. Moreover, the source code becomes
exponentially unintelligible with endless typecasts to far pointers. Worst of all, many otherwise standard C
library functions are not usable in the medium model. You have to either copy function arguments between
far and near memory or writing your own far code versions that accept near data. What a mess!
This leads to one simple recommendation for all non-trivial 16-bit MS-Windows programs:
HELIOS is our “minimal” viewing system for MS-Windows 3.1 and MS-Windows NT. None of the
following pertains directly to radiosity rendering. For those readers familiar with MS-Windows
A Viewing System 235
________________________________________________________________________
Fortunately, we can view it as the proverbial black box. It works, and it provides all the user interface
support we need for our radiosity renderer. As we saw in Listing 4.18, its relation to our radiosity renderer
per se consists of a few function calls. If you must understand its details, a copy of Petzold [1992] and the
#ifndef _HELIOS_H
#define _HELIOS_H
// Display type
#define H_NONE 0 // None
#define H_WIRE 1 // Wireframe
#define H_BMAP 2 // Bitmap
#ifdef WIN32
// WIN32 message cracking macros
#define GET_WM_COMMAND_ID(wp, lp) LOWORD(wp)
#define GET_WM_HSCROLL_POS(wp, lp) HIWORD(wp)
#define GET_WM_VSCROLL_POS(wp, lp) HIWORD(wp)
#else
// WIN16 message cracking macros
#define GET_WM_COMMAND_ID(wp, lp) (wp)
#define GET_WM_HSCROLL_POS(wp, lp) LOWORD(lp)
#define GET_WM_VSCROLL_POS(wp, lp) LOWORD(lp)
#endif
extern "C"
{
LRESULT WINAPI MainWndProc( HWND, UINT, WPARAM,
LPARAM );
LRESULT WINAPI WireWndProc( HWND, UINT, WPARAM,
LPARAM );
BOOL CALLBACK About( HWND, UINT, WPARAM, LPARAM );
BOOL CALLBACK SetCamera( HWND, UINT, WPARAM, LPARAM );
BOOL CALLBACK SetConverge( HWND, UINT, WPARAM, LPARAM );
BOOL CALLBACK SetDisplay( HWND, UINT, WPARAM, LPARAM );
236 A Viewing System
________________________________________________________________________
BOOL CALLBACK SetEntityDir( HWND, UINT, WPARAM, LPARAM );
BOOL CALLBACK SetView( HWND, UINT, WPARAM, LPARAM );
}
#endif
Listing 4.22 - HELIOS.H
Note the use of the extern “C” mechanism. This is the one C++ language feature makes writing MS-
Next, and with no apologies for its length, is the (again, mostly) C source for HELIOS. Thanks to the
intimate relation between C and C++, HELIOS.CPP can be compiled as a C++ program.
#include <windows.h>
#include <windowsx.h>
#include <commdlg.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include "error.h"
#include "spheric3.h"
#include "parse.h"
#include "syn_cam.h"
#include "win_meta.h"
#include "win_bmap.h"
#include "win_sbar.h"
#include "resource.h"
#include "helios.h"
// Synthetic camera
static SynCamera Camera(640, 480, -180.0, 90.0, 0.0, 0.0);
if (!RegisterClass(&wc))
return FALSE;
if (hwnd == 0)
return FALSE;
A Viewing System 239
________________________________________________________________________
return TRUE;
}
switch (msg)
{
case WM_CREATE: // Create window
// Instantiate scroll bar manager
pscroll = new WinScroll(hwnd);
break;
case WM_SIZE: // Get client area dimensions
xclient = LOWORD(lparam);
yclient = HIWORD(lparam);
switch (d_type)
{
case H_WIRE:
// Update wireframe display
CalcWireDim(xclient, yclient, &xwire, &ywire);
MoveWindow(hwnd_wire, Offset, Offset, xwire,
ywire, TRUE);
240 A Viewing System
________________________________________________________________________
break;
case H_BMAP:
// Set scroll bar manager
pscroll->Set(Camera.GetWidth(),
Camera.GetHeight());
break;
default:
break;
}
break;
case WM_PAINT: // Paint client area
hdc = BeginPaint(hwnd, &ps);
if (d_type == H_BMAP) // Display bitmap ?
{
GetClientRect(hwnd, &rc);
pos = pscroll->Pos();
if (Bitmap.Display(hdc, pos, rc) == FALSE)
{
d_type = H_NONE;
pscroll->Hide();
}
}
EndPaint(hwnd, &ps);
break;
case WM_HSCROLL: // Process horz scroll bar message
pscroll->Horz(wparam, GET_WM_HSCROLL_POS(wparam,
lparam));
break;
case WM_VSCROLL: // Process vertical scroll bar msg
pscroll->Vert(wparam, GET_WM_VSCROLL_POS(wparam,
lparam));
break;
case WM_KEYDOWN: // Process key down message
DoKeyDown(hwnd, wparam);
break;
case WM_COMMAND: // Process window message
hmenu = GetMenu(hwnd); // Get menu handle
switch (GET_WM_COMMAND_ID(wparam, lparam))
{
case IDM_FILEOPEN: // Open file
Ofn.lpstrDefExt = "WLD";
Ofn.lpstrFilter = InputFilterSpec;
Ofn.lpstrFile = WorldName;
Ofn.Flags = OFN_HIDEREADONLY | OFN_READONLY;
if (GetOpenFileName((LPOPENFILENAME) &Ofn))
{
switch (d_type)
{
case H_WIRE:
// Erase wireframe metafile
Wire.Erase();
d_type = H_NONE;
if (d_type == H_WIRE)
{
// Record wireframe display
Camera.Preview(Environment.GetInstPtr(),
&Wire);
if (d_type == H_WIRE)
{
// Record wireframe display
Camera.Preview(Environment.GetInstPtr(),
&Wire);
InvalidateRect(hwnd_wire, NULL, TRUE);
}
}
break;
case IDM_WIREFRAME: // Wireframe display
if (d_type != H_WIRE)
{
if (d_type == H_BMAP)
{
Bitmap.Close(); // Close bitmap
d_type = H_NONE;
pscroll->Hide(); // Hide scroll bars
if (wparam == IDM_RENDER)
{
// Confirm radiosity equation solver status
if (Radiosity.GetStatus() == FALSE)
{
OutOfMemory();
break;
}
// Open bitmap
if (Bitmap.Open(Camera.GetWidth(),
Camera.GetHeight()) == TRUE)
{
// Record shaded display
if (Camera.Shoot(Environment.GetInstPtr(),
&Bitmap) == TRUE)
{
if (d_type == H_WIRE)
{
// Erase wireframe metafile (if any)
Wire.Erase();
{
if (wparam == IDM_RENDER)
{
MessageBeep(MB_OK); // Signal completion
// Open bitmap
if (Bitmap.Open(Camera.GetWidth(),
Camera.GetHeight()) == TRUE)
{
// Record shaded display
if (Camera.Shoot(Environment.GetInstPtr(),
&Bitmap) == TRUE)
{
if (d_type == H_WIRE)
{
// Erase wireframe metafile (if any)
Wire.Erase();
switch (msg)
{
case WM_SIZE:
xclient = LOWORD(lparam);
yclient = HIWORD(lparam);
break;
case WM_PAINT: // Paint client area
Wire.Play(hwnd, Camera.GetWidth(), Camera.GetHeight(),
xclient, yclient);
break;
A Viewing System 247
________________________________________________________________________
default:
return DefWindowProc(hwnd, msg, wparam, lparam);
}
return NULL;
}
switch (msg)
{
case WM_INITDIALOG:
// Get camera distances
SetDlgItemFloat(hdlg, IDC_VDIST,
Camera.GetViewDist());
SetDlgItemFloat(hdlg, IDC_FDIST,
Camera.GetFrontDist());
SetDlgItemFloat(hdlg, IDC_BDIST,
Camera.GetBackDist());
return TRUE;
case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wparam, lparam))
{
case IDOK:
// Validate distances
vpd = GetDlgItemFloat(hdlg, IDC_VDIST);
fpd = GetDlgItemFloat(hdlg, IDC_FDIST);
bpd = GetDlgItemFloat(hdlg, IDC_BDIST);
// Set distances
Camera.SetViewDist(vpd);
Camera.SetFrontDist(fpd);
Camera.SetBackDist(bpd);
EndDialog(hdlg, TRUE);
return TRUE;
A Viewing System 249
________________________________________________________________________
case IDCANCEL:
EndDialog(hdlg, FALSE);
return TRUE;
default:
break;
}
break;
default:
break;
}
return FALSE;
}
switch (msg)
{
case WM_INITDIALOG:
// Get camera eye position
eye_posn = Camera.GetEyePosn();
SetDlgItemFloat(hdlg, IDC_XPOS, eye_posn.GetX());
SetDlgItemFloat(hdlg, IDC_YPOS, eye_posn.GetY());
SetDlgItemFloat(hdlg, IDC_ZPOS, eye_posn.GetZ());
return TRUE;
case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wparam, lparam))
{
case IDOK:
// Get eye position
eye_posn.SetX(GetDlgItemFloat(hdlg, IDC_XPOS));
eye_posn.SetY(GetDlgItemFloat(hdlg, IDC_YPOS));
eye_posn.SetZ(GetDlgItemFloat(hdlg, IDC_ZPOS));
vdv_angle.SetVert(DegToRad(vdvv));
vdv_angle.SetHorz(DegToRad(vdvh));
vdv_angle.SpherToRect(&view_dir);
vup_angle.SetVert(DegToRad(vupv));
vup_angle.SetHorz(DegToRad(vuph));
EndDialog(hdlg, TRUE);
return TRUE;
case IDCANCEL:
EndDialog(hdlg, FALSE);
return TRUE;
default:
break;
}
break;
default:
break;
}
return FALSE;
}
switch (msg)
{
case WM_INITDIALOG:
SetDlgItemInt(hdlg, IDC_MSTEP, Radiosity.GetMaxStep(),
FALSE);
SetDlgItemFloat(hdlg, IDC_STOPC,
Radiosity.GetStopCriterion());
CheckDlgButton(hdlg, IDC_AMBIENT_EN,
Radiosity.AmbientFlag());
if (Radiosity.OverShootFlag() == TRUE)
CheckDlgButton(hdlg, IDC_OVER_EN, TRUE);
return TRUE;
case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wparam, lparam))
{
case IDOK:
// Validate parameters
mp = GetDlgItemInt(hdlg, IDC_MSTEP, &dummy, TRUE);
sc = GetDlgItemFloat(hdlg, IDC_STOPC);
if (IsDlgButtonChecked(hdlg, IDC_AMBIENT_EN) != 0)
Radiosity.EnableAmbient();
else
Radiosity.DisableAmbient();
if (IsDlgButtonChecked(hdlg, IDC_OVER_EN) != 0)
Radiosity.EnableOverShoot();
else
Radiosity.DisableOverShoot();
EndDialog(hdlg, TRUE);
return TRUE;
case IDCANCEL:
EndDialog(hdlg, FALSE);
return TRUE;
default:
break;
}
break;
default:
break;
}
return FALSE;
}
switch (msg)
{
case WM_INITDIALOG:
c_type = Camera.GetColorType();
CheckDlgButton(hdlg, IDC_GAMMA_EN,
Camera.GammaFlag());
SetDlgItemFloat(hdlg, IDC_GAMMA, Camera.GetGamma());
CheckDlgButton(hdlg, IDC_JITTER_EN,
Camera.JitterFlag());
SetDlgItemInt(hdlg, IDC_JITTER,
Camera.GetNoiseLevel(), FALSE);
CheckRadioButton(hdlg, IDC_RGB, IDC_PSEUDO, c_type +
IDC_RGB);
return TRUE;
case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wparam, lparam))
{
case IDC_RGB:
case IDC_MONO:
case IDC_PSEUDO:
c_type = wparam - IDC_RGB;
CheckRadioButton(hdlg, IDC_RGB, IDC_PSEUDO,
wparam);
A Viewing System 253
________________________________________________________________________
break;
case IDOK:
if (IsDlgButtonChecked(hdlg, IDC_GAMMA_EN) != 0)
Camera.EnableGamma();
else
Camera.DisableGamma();
if (IsDlgButtonChecked(hdlg, IDC_JITTER_EN) != 0)
Camera.EnableJitter();
else
Camera.DisableJitter();
EndDialog(hdlg, TRUE);
return TRUE;
case IDCANCEL:
EndDialog(hdlg, FALSE);
return TRUE;
default:
break;
}
break;
default:
break;
}
return FALSE;
}
if (yclient > 0)
{
client_aspect = (double) xclient / (double) yclient;
child_aspect = (double) Camera.GetWidth() / (double)
Camera.GetHeight();
if (client_aspect >= child_aspect)
{
*pychild = (short) max(yclient - Offset * 2, Offset);
*pxchild = (short) ((double) *pychild * child_aspect);
}
else
{
*pxchild = (short) max(xclient - Offset * 2, Offset);
*pychild = (short) ((double) *pxchild / child_aspect);
}
}
else
*pxchild = *pychild = Offset;
}
Being an MS-Windows program, HELIOS needs a few additional files. Its menus and dialog boxes are
defined in its “resource script” file, HELIOS.RC. This file is compiled separately and appended to the
#ifndef _RESOURCE_H
#define _RESOURCE_H
#endif
Listing 4.24 - RESOURCE.H
#include <windows.h>
#include "resource.h"
#ifdef _RAY_CAST
SETCONVERGE DIALOG DISCARDABLE 32, 32, 178, 74
STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
CAPTION "Convergence Parameters"
FONT 8, "MS Sans Serif"
BEGIN
LTEXT "Maximum Steps:",IDC_STATIC,6,14,69,8
LTEXT "Stopping Criterion:",IDC_STATIC,6,34,69,8
EDITTEXT IDC_MSTEP,78,12,32,12,ES_AUTOHSCROLL
EDITTEXT IDC_STOPC,78,32,32,12,ES_AUTOHSCROLL
CONTROL "Ambient Exitance",IDC_AMBIENT_EN,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,6,54,122,10
DEFPUSHBUTTON "OK",IDOK,122,10,48,16
PUSHBUTTON "Cancel",IDCANCEL,122,30,48,16
END
#else
SETCONVERGE DIALOG DISCARDABLE 32, 32, 178, 94
STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
CAPTION "Convergence Parameters"
FONT 8, "MS Sans Serif"
BEGIN
LTEXT "Maximum Steps:",IDC_STATIC,6,14,69,8
LTEXT "Stopping Criterion:",IDC_STATIC,6,34,69,8
EDITTEXT IDC_MSTEP,78,12,32,12,ES_AUTOHSCROLL
EDITTEXT IDC_STOPC,78,32,32,12,ES_AUTOHSCROLL
CONTROL "Ambient Exitance",IDC_AMBIENT_EN,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,6,54,122,10
CONTROL "Positive Overshoot",IDC_OVER_EN,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,6,74,122,10
DEFPUSHBUTTON "OK",IDOK,122,10,48,16
PUSHBUTTON "Cancel",IDCANCEL,122,30,48,16
END
#endif
EDITTEXT IDC_GAMMA,50,18,28,12,ES_AUTOHSCROLL
CONTROL "Enabled",IDC_GAMMA_EN,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,12,36,40,10
GROUPBOX "Color Reduction",IDC_STATIC,6,61,81,48
LTEXT "Noise Level:",IDC_STATIC,12,75,49,8
EDITTEXT IDC_JITTER,66,73,12,12,ES_AUTOHSCROLL
CONTROL "Enabled",IDC_JITTER_EN,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,12,91,40,10
GROUPBOX "Color Display",IDC_STATIC,5,116,81,66
CONTROL "RGB Color",IDC_RGB,"Button",
BS_AUTORADIOBUTTON,10,130,62,10
CONTROL "Grayscale",IDC_MONO,"Button",
BS_AUTORADIOBUTTON,10,147,62,10
CONTROL "Pseudocolor",IDC_PSEUDO,"Button",
BS_AUTORADIOBUTTON,10,165,62,10
DEFPUSHBUTTON "OK",IDOK,96,10,48,16
PUSHBUTTON "Cancel",IDCANCEL,96,30,48,16
END
Finally, we need a “module definition” file, HELIOS.DEF, to instruct the linker on how HELIOS is to
be linked:
NAME Helios
DESCRIPTION 'HELIOS Radiosity Renderer'
EXETYPE WINDOWS
STUB 'WINSTUB.EXE'
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE MULTIPLE
STACKSIZE 5120
EXPORTS
MAINWNDPROC @1
WIREWNDPROC @2
SETENTITYDIR @3
SETCAMERA @4
260 A Viewing System
________________________________________________________________________
SETVIEW @5
SETCONVERGE @6
SETDISPLAY @7
ABOUT @8
Listing 4.26 - HELIOS.DEF
A few comments regarding compilation and linking HELIOS may be helpful. First, you need to specify
the large memory model–this is essential. The WinText class (Section 3.13) in particular assumes that its
Second, be sure to compile and link the necessary files, using either a “make” file or a project file from
within an integrated development environment (IDE). The complete list consists of:
Other files will be added to this list in later chapters. However, no changes to HELIOS.CPP will be
needed, since the necessary hooks have already been included via the conditional compilation directives
_HEMI_CUBE and _CUBIC_TETRA (in HELIOS.CPP) and _RAY_CAST (in HELIOS.CPP and
Third, a C++ compiler run from an IDE may assume a default stack size that conflicts with that
specified in HELIOS.DEF. If so, the linker will be certain to complain about it. You can either clear this
Fourth but not finally, you may see inscrutable error messages such as:
Fatal error RW1031: Segment 1 and its relocation information is too large for load optimization. Make
the segment LOADONCALL or rerun RC using the -K switch if the segment must be preloaded.
This particular message came from an IDE resource compiler. It occurred using the default compiler
settings when the build mode was set to include debugging information. Setting the build mode to “release”
(i.e., no debugging information) allowed the program to compile and link successfully. It took an
A Viewing System 261
________________________________________________________________________
unreasonably long time to find that load optimization could be turned off from within the IDE. On the
other hand, the compiler then made an incorrect assumption about pointer aliasing that caused the program
HELIOS was developed and tested using the Microsoft Visual C++ Version 1.5 and Borland C++
Version 4.0 compilers. Command-line “make” files for these compilers are included on the diskette
accompanying this book. If you use either of these products, you should have no problems. Otherwise, you
may encounter an embarrassment of error messages when you first attempt to compile and link HELIOS.
As MS-Windows programmers, it is a price we all have to pay. Curse freely, try different options and
perhaps even read the printed IDE documentation. Take heart, for it will compile eventually.
We now have some 3,700 lines of C and C++ source code. Once you successfully compile and link
HELIOS, you can use it to view both wireframe and full-color bitmap images on any personal computer
that can run MS-Windows 3.1 or MS-Windows NT, including monochrome laptops (in grayscale, of
course).
What is there to view? Well, COL_CUBE.WLD (Listing 3.17) presents two colored cubes floating in
space. For something with a bit more visual interest (one of the chairs shown in Figure 4.24), you can try
the following:
WORLD chair
COMMENT seat
col_cube.ent
< 2.0 2.0 0.1>
< 0.0 0.0 0.0 >
< -1.0 -1.0 -0.05 >
COMMENT back
col_cube.ent
< 2.0 0.2 3.0 >
< 0.0 0.0 0.0 >
< -1.0 -1.0 0.05 >
COMMENT leg #1
col_cube.ent
< 0.2 0.1 2.5 >
< 0.0 0.0 0.0 >
< -0.85 -0.8 -2.55 >
COMMENT leg #2
col_cube.ent
< 0.2 0.1 2.5 >
< 0.0 0.0 0.0 >
< -0.85 0.8 -2.55 >
COMMENT leg #3
262 A Viewing System
________________________________________________________________________
col_cube.ent
< 0.2 0.1 2.5 >
< 0.0 0.0 0.0 >
< 0.75 -0.8 -2.55 >
COMMENT leg #4
col_cube.ent
< 0.2 0.1 2.5 >
< 0.0 0.0 0.0 >
< 0.75 0.8 -2.55 >
END_FILE
Listing 4.27 - CHAIR.WLD
To display a wireframe image of this chair, first make sure that COL_CUBE.ENT and CHAIR.WLD
are in the same directory, then run HELIOS as an MS-Windows program. Once its main window is
2, Choose the Open… menu item to display the Open common dialog box.
An Environment Statistics dialog box will then appear with an enumeration of the instances, surfaces,
If the COL_CUBE.ENT file is not in the same directory as CHAIR.WLD, an error message will appear
2. Choose the Directories… menu item to display the Directories dialog box.
3. Enter the correct file path in the Entities File Path edit control.
and follow the above three steps to select the CHAIR.WLD file again.
With the environment file parsed and loaded into memory, you can now:
2. Choose the Set Parameters menu item to display the Camera Parameters dialog box.
This sets the camera view distance at 2.5 units, giving a field of view roughly equivalent to a 50 mm
lens on a 35 mm camera. It also tells HELIOS to display the image as a vertically-oriented bitmap of
A Viewing System 263
________________________________________________________________________
240 × 320 pixels. You can change this to whatever size you want, from a minimum of 32 pixels to a
2. Choose the Specify View… menu item to display the View Parameters dialog box.
6. Enter “-125” (note the minus sign) in the View Direction Horizontal Degrees edit control.
(Note that the Render menu items are grayed (deactivated) until an environment data file is read into
memory.)
A wireframe image of the chair will be displayed. This image will automatically resize itself whenever
the display window size is changed. You can also go back and change any of the previous entries to change
the view or camera parameters; the wireframe image will update itself accordingly.
It may take a few seconds to display the image, depending on the CPU speed and whether a math
coprocessor is present. If the window’s client (display) area is smaller than the specified horizontal or
2. Choose the Set Display… menu item to display the Display Parameters dialog box.
(The other parameters in the Display Parameters dialog box and the parameters in the Convergence
Parameters dialog box accesible from the Set Convergence… menu item do not have any discernable
You can also choose Rendering from the Render menu item. However, only a blank bitmap will appear
on the screen, along with a Convergence Statistics dialog box. Choose Render and Shaded again to
2. Choose the Save As… menu item to display the Save As common dialog box.
and specify an appropriate directory and file name. The file can later be viewed using Microsoft Paintbrush
2. Choose the About Helios… menu item to display the About HELIOS dialog box.
to view the program’s copyright notice, version number (which should be “1.00A/SH”, where “SH” stands
If all of the above actions work as described, congratulations! HELIOS is alive and well.
4.20 Conclusions
What began as a “minimal” viewing system somehow grew into a major component of this book. Even
so, our MS-Windows implementation is far from being production quality. It lacks any sort of on-line help,
it provides a minimal number of error messages, and it does not offer the currently fashionable “chiseled-
The platform-independent portions of our code are also less than perfect. No attempt has been made to
profile the code to identify those components that should be rewritten by hand using assembly language.
PolyRender should be rewritten using integer-only DDA algorithms (see Section 4.12) for the Intel 80x86
platform and other CPUs with slow floating point implementations. This includes not only scan conversion
for the polygon edges, but also pseudodepth and RGB color interpolation for Gouraud shading. (See also
Blinn [1992] for further details and comments on Gouraud shading and perspective projection).
There is more, of course. Support should be added for other bitmap file formats. Antialiasing should be
added to minimize the “jaggies” on diagonally-oriented polygon edges (Fleisher and Salesin [1992] offer a
very effective solution for polygons, including C source code). The list goes on and on.
Somewhere, however, we have to stop. HELIOS is a minimal but effective viewing system that can
References
Hierarchical Interactive Graphics System (PHIGS) Functional Description, Archive File Format, Clear-
Text Encoding of Archive File, ANSI X3.144-1988, American National Standards Institute, New York,
NY.
Arvo, J. [1991]. Graphics Gems II, Academic Press, San Diego, CA.
Barbour, C.G. and G.W. Meyer [1992]. “Visual Cues and Pictorial Limitations for Computer Generated
Blinn, J.F. [1992]. “Hyperbolic Interpolation”, IEEE Computer Graphics & Applications 12:4, 89 - 94.
Bono, P.R. and I. Herman, Eds. [1987]. GKS Theory and Practice, Springer-Verlag, Berlin, Germany.
Bresenham, J.E. [1965]. “Algorithm for Computer Control of a Digital Plotter”, IBM Systems Journal 4:1,
25 - 30.
Burkett, A. and S. Noll [1988]. “Fast Algorithm for Polygon Clipping with 3D Windows”, Eurographics
‘88 (Proc. European Computer Graphics Conference and Exhibition), D.A. Duce and P. Jancene, Eds.,
Cohen, M.F. and J.R. Wallace [1993]. Radiosity and Realistic Image Synthesis, Academic Press, San
Diego, CA.
Fleisher, K. and D. Salesin [1992]. “Accurate Polygon Scan Conversion Using Half-Open Intervals”, in
Foley, J.D., A. van Dam, S.K. Feiner and J.F. Hughes [1990]. Computer Graphics: Principles and Practice
Gervautz, M. and W. Purgathofer [1990]. “A Simple Method for Color Quantization: Octree
Glassner, A.S. [1990]. Graphics Gems, Academic Press, San Diego, CA.
Gouraud, H. [1971]. “Illumination for Computer Generated Pictures”, Comm. ACM 18:6, 311 - 317.
Heckbert, P..S. [1982]. “Color Image Quantization for Frame Buffer Display”, Computer Graphics 16:3
Heckbert, P.S. [1990a]. “What are the Coordinates of a Pixel?”, in Glassner [1990], 246 - 248.
Heckbert, P.S. [1990b]. “Generic Convex Polygon Scan Conversion and Clipping”, in Glassner [1990], 84
Hill, F.S., Jr. [1990]. Computer Graphics, Macmillan, New York, NY.
Kernel System for Three Dimensions (GKS-3D) Functional Description, ISO Document Number
Kirk, D. [1992]. Graphics Gems III, Academic Press, San Diego, CA.
Liang, Y. and B.A. Barsky [1983]. “An Analysis and Algorithm for Polygon Clipping”, Comm. ACM
26:11, 868 - 877, and Corrigenda, Comm. ACM 27:2, 151 and Comm. ACM 27:4, 383.
Meyer , G.W., H.E. Rushmeier, M.F. Cohen, D.P. Greenberg and K.E. Torrance [1986]. “An Experimental
Newman, W.M. and R.F. Sproull [1979]. Principles of Interactive Computer Graphics, 2nd Edition,
Petzold, C. [1992]. Programming Windows 3.1, Third Edition, Microsoft Press, Redmond, WA.
Plauger, P.J. and J. Brodie [1989]. Standard C, Microsoft Press, Redmond, WA.
A Viewing System 267
________________________________________________________________________
Révész, T. [1993]. “Clipping Polygons with Sutherland-Hodgman’s Algorithm”, The C Users Journal 11:8
Rogers, D.F. [1985]. Procedural Elements for Computer Graphics, McGraw-Hill, New York, NY.
Singleton, K. [1987]. “An Implementation of the GKS-3D/PHIGS Viewing Pipeline”, in Bono and Herman
[1987].
Swanson, R.W. and L.J. Thayer [1986]. “A Fast Shaded-Polygon Renderer”, Computer Graphics 20:4, 107
- 116.
Sutherland, I.E. and G.W. Hodgman [1974]. “Reentrant Polygon Clipping”, Comm. ACM 17:1, 32 - 42.
Sutherland, I.E., R.F. Sproull and R. Schumacker [1974]. “A Characterization of Ten Hidden-Surface
Tumblin, J. and H.E. Rushmeier [1993]. “Tone Reproduction for Realistic Images”, IEEE Computer
Vatti, B.R. [1992]. “A Generic Solution to Polygon Clipping”, Comm. ACM 35:7, 57 - 63.
Weiler, K. and P. Atherton [1977]. “Hidden Surface Removal Using Polygon Area Sorting”, Computer
III
Radiosity and Realism
............................
Our canvas is a 3-D viewing system, carefully constructed to support the needs of radiosity-based
Chapter Five investigates the art and science of form factor determination as an essential component of
the radiosity approach. If the way seems long and tortuous, it is. The problem of form factor determination
Chapter Six looks at the variety of approaches we can take to solving the radiosity equation. From
them are derived not one but three fully functional radiosity-based rendering programs. Our dragons
… and yes, there is art in radiosity, or rather an art to it. More than anything else, choosing an
appropriate polygon mesh for radiosity-based images requires experience and skill. Chapter Seven
considers the conundrums of meshing and substructuring techniques for complex environments.
Finally, Chapter Eight looks at extending the capabilities of our tools and the future of radiosity. There
Having developed a graphics toolkit to manage and display 3-D polygons, we can take some
satisfaction in being half way to our goal of a functional radiosity-based rendering program (Fig. 5.1). In
this chapter, we will address the problem of determining form factors between polygons in our
environments.
Form factors are an essential component of the radiosity approach, as much so as geometrical rays are
essential to ray tracing. As we saw in Chapter Two, a form factor Fij is a dimensionless constant
representing the fraction of radiant flux leaving a Lambertian emitter Ei that is intercepted by another
surface element (or patch) E j (Fig. 5.2). It is based solely on the geometry and geometric relation between
Ej
ni Φij θj
r nj F ij = Φ ij / Φ i
θi
Ei
Figure 5.2 - Patch Ej receiving flux Φij from Lambertian emitter Ei (from Fig. 2.5)
Successfully solving the radiosity equation requires accurate form factors. Unfortunately, form factor
determination for a complex environment containing several thousand possibly occluded patches can be
difficult and extremely time consuming. Pietrek [1993] and others have commented that form factor
calculations can consume up to ninety percent of the time required to solve the radiosity equation. It is
therefore vitally important that we optimize these calculations, first through a careful choice of algorithms,
Despite their apparent simplicity, form factors are notoriously difficult to solve using analytic methods.
Johann Lambert, a pioneer researcher in photometry and likely the first person to consider the problem,
Although this task appears very simple, its solution is considerably more knotted than one would expect
... the highly laborious computation would fill even the most patient with disgust and drive them away
...
which does not bode well for our own investigations!
Lambert expressed this opinion in reference to the problem (discussed below) of two perpendicular
rectangles sharing a common edge. However, his comments apply equally well to form factor
determination in general. As we saw in Section 2.5, the form factor from a finite area patch Ei to another
1 cosθ i cosθ j
Fij =
Ai ∫∫ πr 2
dA j dAi (5.1)
Ai A j
Form Factor Determination 273
________________________________________________________________________
where Ai and A j are the areas of patches Ei and E j respectively (Fig. 5.2). This equation cannot be
solved directly. Instead, we must either find an analytic solution (that is, transform Equation 5.1 into one
that does not involve integration) or solve it using numerical integration techniques.
We will examine a few analytic (or “closed form”) solutions, but only to see why numerical integration
is the more useful approach. Don’t let the mathematics deter you! If nothing else, keep in mind that:
Following Lambert’s pioneering efforts, it took 230 years to find an exact solution for the general case
of two arbitrary but unoccluded polygons (Schröder and Hanrahan [1993]). Schröder reported that it took
Mathematica (a symbolic mathematics program) only fifteen minutes to solve ninety percent of the
problem; the remaining ten percent took eight months of research. As you might have guessed, their “non-
Sparrow [1963] found that by applying Stokes’ Theorem to Equation 5.1, it could be converted to a
1
Fij =
2πAi ∫C ∫C ln(r )dxi dx j + ln(r )dyi dy j + ln(r )dzi dz j
i j
(5.2)
where Ci and C j are the patch boundaries. While this equation can be solved for many polygons and
other shapes (see for example Siegel and Howell [1992]), it is quite impracticable for our purposes. It does
however have some historical interest: it was used in one of the two papers that introduced radiosity to the
Note that Equations 5.1 and 5.2 assume that patches Ei and E j are fully visible to one another. In
other words, the form factor determination method used by Goral et al. [1984] is only applicable to simple
unoccluded environments. It cannot be extended to handle our complex environments with possibly
occluded polygons.
274 Form Factor Determination
________________________________________________________________________
A second approach is to consider special cases for which closed form solutions to Equation 5.1 can be
derived. Mechanical and aeronautics engineers have long used published tables of formulae for specific
area-to-area geometries in their radiant heat transfer studies, including those by Howell [1982], Siegel and
Howell [1992] and Sparrow and Cess [1978]. These include simple shapes such as parallel and
perpendicular rectangles, circles and hollow tubes. More complex geometries can be analyzed using form
factor algebra (Section 2.5) to geometrically add and subtract these shapes and their associated form
factors.
Despite their availability, these tables are not particularly useful for complex environments. Consider
one of the simplest geometries, that of two adjoining and perpendicular rectangles (Fig. 5.3).
C
H=A/C
W=B/C
Ej
A Ei
B
Figure 5.3 - Form factor geometry between perpendicular rectangles
While the geometry may be simple, the following equation for its form factor Fij from Ei to E j is
anything but!
Fij =
1
(W ∗ arctan 1 + H ∗ arctan 1 − H 2 + W 2 ∗ arctan 1
(5.3)
πW W H 2
H +W
2
( )( ) (
1 1+W 2 1+ H 2 W 2 1+W 2 + H 2
+ ln ∗
W2
) (
H 2 1+W 2 + H 2
∗
H2
)
4 1+W 2 + H 2
2
(2
1 + W W + H )(
2
) 2
( 2
)(
2
1 + H W + H
)
Remember, this is a “simple” example! Lambert [1760] was clearly justified in his comments. Not shown
is the equation for two adjoining but non-perpendicular rectangles–it fills an entire page.
Form Factor Determination 275
________________________________________________________________________
Even if we had closed form solutions for a useful set of patch geometries, it would not do us much
good. Like the contour integration approach, these solutions assume that the patches are fully visible to one
We can simplify our problem by considering the form factor from a differential area patch dEi to a
finite area patch E j . In other words, we can model our luminous surface emitter as a point source of light.
As we saw in Section 2.5, the form factor FdEi − Ej is given by the area integral equation:
cos θ i cos θ j
FdEi − Ej = ∫ dFdEi−dEj = ∫ πr 2
dA j (5.4)
Aj Aj
Again, this equation cannot be solved directly for an arbitrary patch E j . However, there is a
surprisingly simple analytic solution for planar convex polygons (Lambert [1760]), which is just what we
n −1
1
FdEi − Ej =
2π
∑ β k cosα k (5.5)
k =0
or equivalently:
n −1
∑ β k n i ⋅ (rk × r(k +1)%n )
1
FdEi − Ej = (5.6)
2π k =0
where n is the number of polygon edges, β k is the angle (in radians) between the vectors rk and r(k +1)% n
defined from dEi to each pair of vertices k and (k+1)%n (where “%” is the modulo arithmetic operator),
αk is the angle (again in radians) between the plane of dEi and the triangle formed by dEi and the kth
Actually, Equation 5.6 is the contour integration approach applied to the special case of a differential
area emitter and a planar convex polygon receiver. It was used to calculate form factors in the second paper
that introduced radiosity to the computer graphics community (Nishita and Nakamae [1984]). While it is
certainly simpler than the general contour integration approach used by Goral et al. [1984], it too assumes
1
2
Ej
r2
3 0
r1
r3 r0
ni
β
0
α
3
dEi
But wait! The emitting patch dEi is an infinitesimally small point source. If an intervening polygon
partially occludes E j , we can subdivide E j into convex polygons that are either fully visible to or
completely hidden from dEi (e.g., Fig. 5.5). We can then apply Equation 5.6 to each visible polygon; the
form factor from dEi to E j is the sum of their individual form factors.
This is essentially a hidden surface problem. Seen from dEi , what polygons in the environment are
visible to it, and what other polygons partially or fully occlude each one? What we need is an area
subdivision algorithm for hidden surface elimination, such as Warnock’s Algorithm (e.g., Sutherland et al.
[1974]), that successively divides polygons into smaller and smaller polygons until each one is either fully
Unfortunately, area subdivision algorithms are at least an order of magnitude more complex than the
Z-buffer algorithm presented in the previous chapter (see Rogers [1985] for implementation details of
Warnock’s Algorithm). While Nishita and Nakamae [1984] demonstrated that their technique works for
complex environments with partially occluded polygons, numerical integration offers a simpler approach.
Form Factor Determination 277
________________________________________________________________________
Ej1
Ek Ej2
dEi
Our simplified approach led to an analytic solution for planar convex polygons. Given two arbitrary
In general, no. If a small but finite polygon is placed parallel to and an infinitesimal distance above a
large emitter, it will clearly intercept only a small fraction of the emitted flux. Modeling the emitter as a
point source, however, would lead us to conclude that it intercepts nearly all of the emitted flux. Wrong!
So, our simplified approach is an approximation. We therefore need to consider the consequences of
this approximation, and under what conditions we are justified in modeling a luminous patch as a point
source.
It is a thorny question, since the differences between approximate and actual form factors are not
directly manifested in the rendered image. The predicted distribution of light within the environment will
be subtly different from what it would be in real life, but there are many other approximations in the
rendering process that can overshadow these differences (e.g., Meyer et al. [1986] ).
Murdoch [1981] investigated this problem as part of a theoretical study in illumination engineering. He
demonstrated that modeling a Lambertian luminous rectangle as a point source results in worst-case
illuminance prediction errors (using the inverse square law) of less than ±1 percent if the distance from the
illuminated point to the rectangle is at least five times its maximum projected width. In other words, the
278 Form Factor Determination
________________________________________________________________________
luminous rectangle should subtend an angle of less than 0.2 radians, or approximately 11.5 degrees, as seen
from the illuminated point. (Note the caveat projected width: a long but narrow light source will subtend a
This Five-Times Rule (Fig. 5.6) has been used by illumination engineers for nearly a century. If the
maximum dimension of a lighting fixture is less than five times its distance from a surface being
illuminated, then the fixture is modeled as a point source and the inverse square law for point sources (Eqn.
>5
Figure 5.6 - Illumination engineering’s Five-Times Rule
There have been several other detailed studies of form factor calculation errors, including Saraiji and
Mistrick [1992], Emery et al. [1991], Baum et al. [1989], Max and Troutman [1993] and Sbert [1993].
While there is no firm consensus on the topic, it appears that the Five-Times Rule can be applied to form
A finite area Lambertian emitter should be modeled as a point source only when the distance to the
receiving surface is greater than five times the maximum projected width of the emitter.
We should keep in mind that this does not limit the applicability of our simplified approach. If the Five-
Times Rule is violated for any two patches, we can always subdivide the emitting patch until the rule is
satisfied for each subdivided area. Of course, this fails for the two adjoining patches shown in Figure 5.3–
we would be subdividing forever as we approach their common edge. We need a heuristic rule that stops
subdividing when the patches become too small to be significant in any rendered image of the
We can take yet another approach to solving Equation 5.4. Imagine dEi being centered on the base of
an imaginary hemisphere with unit radius (Fig. 5.7). Tracing geometric rays from dEi to E j , we can
project the outline of E j onto the surface of the hemisphere. We can then trace rays from this projection
directly down onto the base of the hemisphere to outline the area A. From this, the form factor Fij is given
by:
A
FdEi − Ej = (5.7)
π
This entirely geometric solution is known as Nusselt’s analogy (Nusselt [1928]). While it strictly
applies only when dE i is a differential area, it serves as a useful approximation for any two finite patches
Ei and E j where Ei is much smaller than either E j or the distance between them (i.e., the Five-Times
Rule applies).
n
Ej
radius = 1
dEi
A
Nusselt’s analogy works as follows. Suppose E j is a differential patch, dE j . Recalling once again the
discussion of solid angles and projected areas from Chapter One, we can see that the solid angle dω
dω = cosθ j dA j r 2 (5.8)
280 Form Factor Determination
________________________________________________________________________
where dA j is the differential area of dE j . (This is in part the discussion presented in Section 2.5, but it
nj
θ dE j
j
ni r
dω
θ
i
dE i
Figure 5.8 - Differential area form factor geometry (from Fig. 2.6)
The solid angle dω is equal to the area of the projection of dE j onto the unit hemisphere’s surface;
this accounts for the factor cos θ j r 2 in Equation 5.4. The cos θ i term comes from the second projection
where dA is the (now differential) projected area on the hemisphere base. Finally, the denominator of π
comes from the base’s area (a unit circle). We obtain the finite projected area A by integrating Equation 5.9
Unlike our previous contour integration approach, Nusselt’s analogy applies to any finite area patch
E j , regardless of its outline. Unfortunately, it leaves us with the problem of projecting the polygon’s
outline onto the hemisphere’s surface and thence onto its base.
In the past, illumination engineers have relied on mechanical and photographic contrivances (e.g.,
Cherry et al. [1939] and O’Brien [1963]) to perform these projections and measure form factors for real-
life objects such as windows and building skylights. More usefully, Bian [1992] and Bian et al. [1992]
show how to project n-sided polygons onto the surface of a hemisphere and analytically calculate their
form factors. Once again, however, we need an accompanying area subdivision algorithm to solve the
determine form factors in complex environments. Rather than pursue this issue any further, we should
In considering Nusselt’s Analogy, Cohen and Greenberg [1985] realized that patches that have the
same projected area on a hemisphere will occupy the same solid angle as seen from the emitting patch (Fig.
5.9). In other words, both patches have the same form factor. This is perfectly sensible, since both patches
will receive the same emitted flux if either one has an unobstructed view of the emitter.
Ek
Ej
dEi
Figure 5.9 - Patches Ej and Ek have same form factor from patch dEi
Suppose then that we replace Nusselt’s hemisphere with a hemi-cube1. As Figure 5.10 shows, we can
equally well project a patch onto the surface of the hemi-cube. Suppose further that each surface (or face)
of the hemi-cube is divided into a grid of small cells2. If we can determine their individual form factors
(called delta form factors, ∆F), we can determine the form factor of the projected patch simply by
1Ifa hemisphere is half of a sphere, then a hemi-cube is half of a cube. There are two commonly used
spellings: "hemi-cube" and "hemicube". Cohen and Greenberg [1985] used "hemi-cube" in their original
paper, but Cohen and Wallace [1993] later chose "hemicube" for their book. The spelling used here was
chosen by flipping a coin.
2The computer graphics literature also confusingly refers to hemi-cube cells as “elements”, “pixels” and
“patches”. The terms “elements” and “patches” are unfortunate, since they are so easily confused with the
282 Form Factor Determination
________________________________________________________________________
Ej
dEi
where ∆Fcovered refers to the delta form factors of those cells covered by the projection of E j onto one
The accuracy of Equation 5.10 is clearly dependent on the hemi-cube’s grid spacing. This spacing is
measured in terms of the number of cells on the top face ( 256 × 256 cells, for example), and is referred to
as the hemi-cube’s resolution. Typical resolutions used by researchers have ranged from 32 × 32 to
The hemi-cube algorithm is a classic example of a numerical integration technique known as numerical
b n −1
∫ ( )
f (x )dx ≈ ∑ w j f x j (5.11)
a j =0
and where f(x) (called the kernel of the integral function) is evaluated at a series of n distinct sample points
{x0 , K , x n−1 } , with w i being a “weight” determined by the size of the interval between the sample points.
surface elements and patches introduced in Chapter Three. The terms “cells” follows Cohen and Wallace
[1993].
Form Factor Determination 283
________________________________________________________________________
The approximation clearly improves as the interval between the sample points decreases. (Further details
are available in any good text on numerical analysis.) Substituting Equation 5.9 into Equation 5.7, we get:
cosθ i cosθ j
∆FdEi − Ej ≈ ∆A j (5.12)
πr 2
where E j now refers to a hemi-cube cell and ∆A j is its area as a finite fraction of the entire face. The
approximation is due to the substitution of the finite cell area ∆A j for the differential area dA j in
Equation 5.9. (See Section 2.5 for an alternate derivation.) The kernel f(x) of Equation 5.11 is composed of
the two cosine terms, the square of the distance r and the factor π; the weight wj is the cell’s area, ∆A j .
Cohen and Wallace [1993] examine a number of fascinating mathematical properties relating to form
factors and numerical integration. Fortunately, these issues are not essential to our understanding of the
hemi-cube algorithm’s theory. Indeed, all we need to remember is that the hemi-cube is analogous to
Nusselt’s hemisphere. Given this and an understanding of the reasoning behind Figures 5.9 and 5.10, what
The hemi-cube algorithm will only be useful if we can easily calculate its delta form factors. Happily,
we can. Consider the hemi-cube cell shown on the top face3 in Figure 5.11. It does not matter what the
actual dimensions of the hemi-cube are, since we are only interested in the solid angle subtended by each
cell. If we choose a height of one unit for computational convenience, we can see that:
r = u2 + v2 +1 (5.13)
and
3It should be noted that most discussions of hemi-cubes use a right-handed x-y-z co-ordinate system.
However, since we are "looking" outwards from the surface of dEi into the environment, we instead use a
left-handed u-v-n co-ordinate system to emphasize that we are in the patch's “view space”. Apart from a
change of axis labels, the equations remain the same. The origin, however, is located at dEi rather than the
hemi-cube face (see Section 5.11).
284 Form Factor Determination
________________________________________________________________________
where ∆Atop is the hemi-cube cell area as a fraction of the top face area of four square units.
∆A
θ 1
j
θi r U
u
dEi v V
2 2
r = u + n +1 (5.16)
and
cosθ i = n r
(5.17)
cosθ j = 1 r
Thus:
and similarly for side face cells where u = ±1 by substituting v for u. The hemi-cube cell area ∆Aside is
once again a fraction of the full side face area of four square units, including the bottom half hidden below
∆A θj
n 1
r U
θi
-1 u
dEi V
Figures 5.11 and 5.12 show that the hemi-cube’s n-axis is always aligned with the plane normal of
dEi . By the same token, the orientation of u and v with respect to the world co-ordinate system is entirely
arbitrary. That is, we can arbitrarily rotate the hemi-cube about its n-axis when positioning it over a patch
in the environment. Having chosen an orientation, we can substitute the world co-ordinates of u, v and n
axes into Equations 4.8 and 4.9 to derive a view space transformation matrix for the hemi-cube. This
allows us to transform the world co-ordinates of any other patch E j into the hemi-cube’s “view space”.
One of the advantages of the hemi-cube algorithm is that the delta form factors can be precalculated
and stored in a lookup table (Cohen and Greenberg [1985]). Even better, the hemi-cube top has an eight-
fold symmetry, while each side has two-fold symmetry. That is, the delta form factors in each octant of the
hemi-cube top face are identical, and similarly for each vertical half of the four side faces. If we add these
2
up and consider a hemi-cube resolution of n × n cells, we can see that we need to store only 3n 8 floating
point values.
The hemi-cube algorithm is probably the most widely used and popular method of form factor
determination among radiosity researchers. This is not to say, however, that it is the most efficient or even
the most elegant algorithm available. In keeping with our promise of “a careful choice of algorithms”, we
should investigate at least one alternative in depth. Besides providing further insights into the hemi-cube
algorithm, implementing both algorithms will give us a valuable sanity check. While the two algorithms
286 Form Factor Determination
________________________________________________________________________
will not provide identical form factor estimates, their answers should at least be comparable within some
Compared to Nusselt’s hemisphere, Cohen and Greenberg’s hemi-cube provides a very simple
geometry for polygon projection and form factor determination. However, there is one nagging asymmetry:
the top face and the four side faces have different geometries and delta form factor equations. This means
that we have to project every polygon onto five separate faces, a considerable nuisance for a complex
environment with thousands of polygons. It also means that we will probably need different sets of
Can we remedy this situation? Yes! There is nothing sacrosanct about the hemi-cube. All we need is a
simple geometrical object with planar surfaces to project our polygons onto. The simplest possible three-
Beran-Koehn and Pavicic [1991] observed that we can think of the hemi-cube as a cube that has been
bisected by the polygon it rests on (Fig. 5.13). Suppose we rotate this cube and its view space co-ordinate
system such that the polygon intersects three of its vertices (Fig. 5.14). This results in a geometrical object
Polygon
Again, we are only interested in the solid angle subtended by each cell, and so the size of the cube is
immaterial. It will be convenient to use a cube measuring 3 units across each face. This places the cubic
Form Factor Determination 287
________________________________________________________________________
apex vertex A is exactly one unit directly above the cubic tetrahedron center at {1, 1, 1} . (Note that the
v1
Polygon
v2
A
U v0 = { 1, 1, -2 }
v1 = { 1, -2, 1 }
v2 = { -2, 1, 1 }
V
v0
We now have three identical but triangular faces to project our polygons onto. More importantly, this
was accomplished without unduly complicating the underlying theory of the hemi-cube algorithm. All else
being equal, this should substantially increase the performance of our form factor determination code.
How much of an increase we can expect is an open question that depends in part on how carefully we
craft our C++ code. While we could quantify the maximum possible improvement on theoretical grounds,
it will be easier to perform experimental timing measurements on our completed implementations. Before
then, we need to examine a few details, beginning with delta form factor calculations for cubic
tetrahedrons.
The geometry of a cubic tetrahedron cell is shown in Figure 5.15, where dEi is the differential patch
located at the center of the cubic tetrahedron (that is, the polygon’s view space origin) and E j is the cell
whose form factor we are interested in. Recalling Equation 5.12, we have:
cosθ i cosθ j
∆FdEi − Ej ≈ ∆A j (5.19)
πr 2
Ej
nj
θ
j
ni S
θ r
i
dE i
Following the development presented in Beran-Koehn and Pavicic [1992], the term cos θ i is given by:
S ⋅ ni S ⋅ ni
cos θ i = = (5.20)
S r
where S is the bound vector from the origin to the cell center and r is its length. Expressed in terms of the
cubic tetrahedron’s view space co-ordinate system, the polygon normal n i is described by the vector
1 1 1
, , . This means that:
3 3 3
su + sv + s n
cosθ i = (5.21)
r 3
For cells on the cubic tetrahedron face perpendicular to the v-axis, the term cos θ j is given by:
−S ⋅ n j −S ⋅ n j
cosθ j = = (5.22)
S r
where the cell normal n j is described by the vector {0,−1,0} . Also, the face lies on the plane v = 1 . Thus:
sv 1
cosθ j = = (5.23)
r r
The same result can be derived for the other two faces. Thus, for any cubic tetrahedron cell E j , we
have:
su + s v + s n
∆FdEi − Ej = ∆A j (5.24)
πr 4 3
Form Factor Determination 289
________________________________________________________________________
However, r 2 = s u 2 + s v 2 + s n 2 , and for each face, one of s u , sv or s n will always be one. Thus:
x + y +1
∆FdEi − Ej = ∆A j (5.25)
(
π x2 + y2 +1) 2
3
where x and y range from 1 to -2 (Fig. 5.14). (Note that these co-ordinates do not refer to the world x-y-z
co-ordinate system.)
Equation 5.25 describes the delta form factors for square cubic tetrahedron cells. It does not consider
the triangular cells at the base of each face (Fig. 5.16). Beran-Koehn and Pavicic [1992] noted that we have
two choices. If our resolution is sufficiently high, we can simply ignore these cells –their contribution to
the summed form factor will be minuscule. Otherwise, we must include them, but recognize that their areas
The symmetry of the cubic tetrahedron is such that we only need to store delta form factors for one half
of one face. For a resolution of n × n cells on one full face of the underlying cube, we need to store n 2 4
floating point values. This is less than the 3n 2 8 values required for a hemi-cube with the same resolution.
Moreover, the cubic tetrahedron has 3n 2 2 cells; the equivalent hemi-cube has 3n 2 cells.
But are they equivalent? Beran-Koehn and Pavicic [1992] noted that a hemi-cube samples its
environment with twice the number of cells as a cubic tetrahedron with the same resolution. It can be
shown that the average delta form factor is the same for both geometries when they have the same number
290 Form Factor Determination
________________________________________________________________________
of cells. Thus, a cubic tetrahedron must have a resolution of 2 ∗ n × 2 ∗ n cells in order to be equivalent
Details aside, the cubic tetrahedron is an uncomplicated variant of the hemi-cube. Except where noted,
the following discussions referring to hemi-cubes and the hemi-cube algorithm also apply to cubic
tetrahedrons.
Before eulogizing either the hemi-cube or cubic tetrahedral algorithm as the solution to form factor
determination, we should consider their limitations. Most importantly, we must remember that these
algorithms can only estimate the form factor between any two patches. There will always be some error
A very thorough study of this problem with respect to hemi-cubes (but not cubic tetrahedrons) is
presented in Max and Troutman [1993]. We will not attempt to review this study or otherwise quantify
these errors here. Instead, we will examine their causes and effects. This knowledge will later prove useful
in visually assessing the results of our radiosity renderer. It will also highlight some of the fundamental
If we choose a hemi-cube or cubic tetrahedron resolution that is too coarse, we may end up with
annoyingly visible aliasing artifacts in our images. Consider Figure 5.17, where the surface S is discretized
into a regular array of patches and projected onto a hemi-cube centered over patch Ei . (A cubic
tetrahedron could also be used; the following arguments remain the same.) Some of the patches cover two
cells while the others cover only one each. If the hemi-cube patch is emitting light, these patches may
“receive” (according to their calculated form factors) approximately twice as much flux as their neighbors.
This problem is particularly evident when the discretization of a surface into polygons is such that their
projection onto the hemi-cube nearly matches that of the spacing of the hemi-cube cells. It can be further
aggravated by moving the hemi-cube to patches adjacent to Ei and repeating the process. Depending on
the spacing between these patches relative to S, the erroneous distribution of flux on S may be reinforced.
Displayed in an image, the surface will appear to have a distinctly plaid-like variation in shading.
Form Factor Determination 291
________________________________________________________________________
Ei
1 2 2 1 1 2 2 1
Figure 5.17 - Hemi-cube aliasing
A partial solution is to randomly vary the hemi-cube’s orientation about the surface normal as it is
moved from patch to patch (Wallace et al. [1987]). While this will not solve the aliasing problem for
individual patches, the likelihood of their shading patterns reinforcing one another will be greatly
diminished. The sum of these patterns will appear as low contrast, random noise, to which our eyes are
fairly insensitive.
A second, more serious problem is that small patches may cover less than one cell, in which case they
will be missed entirely. This can seriously affect small but highly luminous patches in an environment,
particularly high intensity light sources. Reversing roles with the patch beneath the hemi-cube as a
receiver, it may “receive” no flux at all from the emitting patch, even though both are fully visible to one
another.
We can of course alleviate this problem by increasing the hemi-cube resolution. However, the hemi-
cube algorithm has a time complexity (Section 2.6) of approximately O(n2), where n is the hemi-cube
resolution (e.g., Vilaplana and Pueyo [1992]). In other words, doubling the hemi-cube resolution
approximately quadruples the algorithm’s execution time. This also applies to the cubic tetrahedral
algorithm. It is the inevitable tradeoff in radiosity rendering between image quality and rendering time.
Before proceeding any further, we should consider the role of form factors in solving the radiosity
equation. Figure 5.18 shows one surface (labeled “source”) illuminating another (labeled “receiver”). Both
surfaces are divided into patches and elements as explained in Section 3.7. So far, it appears as if we must
292 Form Factor Determination
________________________________________________________________________
determine the form factors between each pair of elements. For an environment with 50,000 elements, this
Patch
Element
Φ ij
Receiver
Source
Figure 5.18 - Radiant flux transfer between surfaces
The surfaces in an environment should be discretized into patches and elements such that Gouraud
shading each element does not result in objectionable aliasing artifacts. The elements must be closely
spaced in order to capture the fine shading details across surfaces in a rendered image, particularly at
shadow boundaries. (This will be discussed in detail in Chapter Seven). We will eventually have to
However, this is primarily a visual criterion. In terms of calculating the flux transfer between two
surfaces, we need to apply the Five-Times Rule (Section 5.5). Suppose the receiving surface in Figure 5.18
is discretized into patches and elements such that each patch of the emitting surface satisfies the Five-
Times Rule. If so, then we can safely model each patch as a point source. This means that we only need to
determine the form factor from the source patch to the receiving element. There is no point in considering
element-to-element form factors; the calculated flux transfer between the elements of a source patch and a
receiving element will be (approximately) the same as that calculated between the patch itself and the
This explains why we created a two-level hierarchy of patches and elements in Section 3.7. If we have
an environment consisting of m patches and n elements, we only need to determine m × n form factors
between patches and elements. As an example, an environment with 5,000 patches and 50,000 elements
Fortunately, this is not as bad as it looks: the hemi-cube algorithm calculates form factors from a patch
to all elements in the environment in parallel. An environment with 5,000 patches therefore requires only
one hemi-cube calculation per patch. Furthermore, we will see in the next chapter that we only need to
There are other computational advantages to using a two-level hierarchy of patches and elements.
These will be examined in detail in Chapter Six. Before then, however, we need to implement the hemi-
The hemi-cube algorithm is much easier to explain than it is to implement in software. Seen in
isolation, the myriad details tend to overshadow and obscure the underlying algorithm. Like our viewing
Fortunately, we have already seen most of these details before–it’s our viewing system! Consider the
similarities:
The hemi-cube algorithm is essentially a polygon scan conversion process. Suppose we want to
determine the form factor Fij from a polygon Ei to another polygon E j in an environment. Each hemi-
cube face defines a view volume whose back clipping plane is at plus infinity and whose front clipping
plane is (almost) at the hemi-cube’s center (Fig. 5.19a). In other words, it defines an essentially infinite
four-sided pyramid. (The cubic tetrahedron’s view volume shown Figure 5.19b is similar, except that it
If we position the hemi-cube over Ei , we can perform a perspective projection of E j onto each of its
faces. Filling the projected polygon on each face allows us to determine which hemi-cube cells are covered
by the projection. Once this is done, the approximate form factor Fij is given by Equation 5.10.
294 Form Factor Determination
________________________________________________________________________
One difference is that the viewing system described in Chapter Four has its origin centered on the view
plane window, while the hemi-cube’s u-v-n co-ordinate system is centered on the eye position (Fig 5.20).
A moment’s reflection, however, will reveal that the two systems are essentially equivalent; the only
difference is that the hemi-cube’s origin has been translated a distance of one unit along the n-axis with
respect to our viewing system’s origin. Allowing for this, we can treat the hemi-cube face no differently
from a view plane window. In particular, we can reuse much of our viewing system code from Chapter
Hemi-cube face
v
n
1
Eye position
u
Figure 5.20 - Hemi-cube face co-ordinate system
Unlike our previous attempts at form factor determination, the hemi-cube algorithm trivially solves the
polygon occlusion problem by using a variation of the Z-buffer algorithm presented in Section 4.14.
Instead of storing the closest polygon color for each screen pixel in a frame buffer, we can store an
identifier for the closest polygon in an equivalent item buffer, with one entry for each hemi-cube cell. A
Suppose we assign a unique identifier to each polygon in the environment, after which we initialize the
depth array to INFINITY and set the item buffer entries to NONE. As we project each visible polygon in the
environment onto the hemi-cube, we compare its depth at each covered hemi-cube cell with the current
depth array entry. If it is closer than the current depth, we update the entry and assign the polygon
identifier to the item buffer entry. When all of the polygons in the environment have been considered, we
scan the item buffer and calculate the form factor for each polygon using Equation 5.10.
Thus, given a polygon Ei , the hemi-cube algorithm calculates the form factors Fij from Ei to all other
polygons E j in the environment. We can express this algorithm in the following pseudocode (from
ENDFOR
ENDFOR
FOR each polygon E j j // Initialize polygon form factors
Fij = 0
ENDFOR
FOR each hemi-cube face
Transform E j co-ordinates to E i (hemi-cube) view space
FOR each polygon E j j // Scan convert polygon E j
IF E j is visible
Clip E j to hemi-cube face view volume
IF clipped polygon is inside view volume
Project polygon onto hemi-cube face
FOR each hemi-cube face cell k
IF cell k is covered
IF depth of E j at cell k < cell_depth(k)
cell_depth(k) = depth of E j at cell k
polygon_id(k) = j
ENDIF
ENDIF
ENDFOR
ENDIF
ENDIF
ENDFOR
FOR each hemi-cube face cell k // Sum delta form factors
m = polygon_id(k)
Fim = Fim + ∆Fk
ENDFOR
ENDFOR
Figure 5.21 - Hemi-cube algorithm
The pseudocode for cubic tetrahedral algorithm is essentially identical. All we have to do is substitute
the words “cubic tetrahedron” where “hemi-cube” appears. This similarity will be reflected in our C++
implementation, where the common features will be encapsulated in an abstract “form factor” class.
Our first requirement is to precalculate the delta form factors and store the results in a lookup table. For
a resolution of n × n cells, we need to store a minimum of 3n 2 8 floating point values for hemi-cubes.
The equivalent cubic tetrahedron has a resolution of m × m cells, where m = 2 ∗ n . It therefore requires
m 2 4 = n 2 2 values. Assuming n = 100 and four-byte float data type as an example, this translates to 15
These are minimum values, however. For the hemi-cube, we need a square array of n 2 4 cells to store
the delta form factors for the side faces. Unfortunately, the n 2 8 delta form factors for the top face of the
hemi-cube form a triangular array. We will want to access this array using an cell’s integer u-v co-ordinates
as quickly as possible. Rather than perform a complex mapping between these co-ordinates and offsets into
some sort of compacted array, it is usually better to allocate memory for two quadrants of delta form
2
factors (one for the top face and another for the side faces). This requires n 2 floating point values, or 20
Kbytes for the above example. This is a fairly insignificant amount of memory, at least for a radiosity
rendering program. We can allocate a static array in memory and initialize it at program startup.
The cubic tetrahedron is more problematic. We only need to store delta form factors for one half of one
face, but this again leads to a triangular array. Storing these values in a static array implies that we must
allocate 40 Kbytes for the above example. If we increased the resolution to n = 400 (that is, 566 × 566
cells), we would be wasting 313 Kbytes of memory. (In fact, we need to store slightly more than m 2 4
values. Figure 5.22 demonstrates that for m = 8 , we need to allocate space for m 2 4 + m 2 = 20 unique
Figure 5.22 - Unique delta form factor values for a cubic tetrahedron face
Fortunately, one of the more subtle features of the C++ programming language comes to our rescue.
We can easily allocate a static (or, if we prefer, dynamic) triangular array with no wasted memory and
relatively little overhead. All we have to do is to allocate a one-dimensional array for each row and an
298 Form Factor Determination
________________________________________________________________________
array of pointers to the rows. C++ (and its progenitor, C) allow us to access this construct exactly as if it
were a two-dimensional array. The details are described in a text file on the accompanying diskette.
#ifndef _FF_DELTA_H
#define _FF_DELTA_H
#endif
Listing 5.1 - FF_DELTA.H
A resolution of 100 × 100 cells for hemi-cubes provides a reasonable tradeoff between execution speed
and minimization of aliasing artifacts. (A resolution of 142 × 142 cells is required for an equivalent cubic
tetrahedron.) You can experiment with different resolutions (such as 50 × 50 or 200 × 200 cells) by
redefining FF_ArrayRes and recompiling. The only restriction is that FF_ArrayRes must be an even
number. (A further restriction applies to MS-Windows 3.1 in that the allocated array size cannot exceed 64
Kbytes unless the arrays are declared as _huge–something that should only be done as a last resort.)
FF_DELTA.H simply specifies the delta form factor resolution. We can use the following C++ class to
precalculate and store the delta form factors for our hemi-cube:
#ifndef _HC_DELTA_H
#define _HC_DELTA_H
#include "general.h"
#include "ff_delta.h"
public:
Form Factor Determination 299
________________________________________________________________________
HemiDelta();
return top_array[row][col];
}
#endif
Listing 5.2 - HC_DELTA.H
GetTopFactor and GetSideFactor map a cell’s integer co-ordinates to indices for the static delta form
factor arrays before returning the appropriate value. The arrays are initialized at program startup by:
#include "hc_delta.h"
Only one global instance of HemiDelta is required in a radiosity rendering program. If you want to
experiment with different hemi-cube resolutions without recompiling, HemiDelta should be modified such
that it dynamically allocates and initializes its delta form factor arrays.
Our C++ code for precalculating and later accessing delta form factor values for cubic tetrahedrons is
based on a C implementation presented in Beran-Koehn and Pavicic [1992]. Translated into C++, it
becomes:
#ifndef _CT_DELTA_H
#define _CT_DELTA_H
#include "general.h"
#include "ff_delta.h"
public:
CubicDelta();
#endif
Listing 5.4- CT_DELTA.H
and:
#include "ct_delta.h"
y -= delta;
}
left++;
right--;
y = z -= delta;
}
}
Listing 5.5- CT_DELTA.CPP
Unlike HemiDelta, CubicDelta dynamically allocates a two-dimensional triangular array for its delta
form factor values. The details of this technique are discussed in a text file on the accompanying diskette.
Like our previous HemiDelta class, only one global instance of CubicDelta is required in a radiosity
rendering program. Moreover, we should choose between the two at some point, since only one is required
for form factor determination. Right now, we have some more work to do.
Form Factor Determination 303
________________________________________________________________________
In an ideal world with truly intelligent optimizing compilers, we could simply derive an implementation
of the hemi-cube algorithm from our previous implementation of the Sutherland-Hodgman algorithm in
PolyClip4 (Section 4.8.6). The C++ compiler would then rewrite our code to remove the extraneous
components, reorder our mathematical calculations for improved efficiency, and so forth. In more realistic
terms, the two applications are sufficiently different that we are better off rewriting PolyClip4 expressly for
Following the development of PolyClip4, we first need a polygon vertex array class that is very similar
#ifndef _FF_POLY_H
#define _FF_POLY_H
#include "patch3.h"
#include "vector4.h"
public:
FormPoly()
{
num_vert = 0;
ident = 0;
}
#endif
Listing 5.6 - FF_POLY.H
The ident member holds the identifier of the polygon currently being projected onto the hemi-cube.
Unlike our OutPolygon class, we only need to store the position for each polygon vertex. This considerably
We will need five instances of FormPoly, one for each hemi-cube face. Thus:
#ifndef _HC_POLY_H
#define _HC_POLY_H
#include "ff_poly.h"
#endif
Listing 5.7 - HC_POLY.H
HC_POLY.H defines the enumerated HC_Face data type. Its values are used to arbitrarily but
consistently label the hemi-cube faces according to their orientation with respect to the hemi-cube’s view
n
Top
u
Back Right
Front
Left
We will similarly need three instances of FormPoly for our cubic tetrahedron. This becomes:
#ifndef _CT_POLY_H
#define _CT_POLY_H
#include "ff_poly.h"
#endif
Listing 5.8 - CT_POLY.H
where the cubic tetrahedron faces are labeled according to the conventions shown in Figure 5.24.
Top
u
Right
Left
We saw in Section 5.9 that the hemi-cube should be randomly oriented (or jittered) about its n-axis
when it is placed over the center of a polygon in order to minimize aliasing artifacts. We can do this by
first generating a random vector r using C++’s rand function for each co-ordinate. From this, we derive a
u HC = n P × r (5.26)
306 Form Factor Determination
________________________________________________________________________
where n P = n HC is the polygon normal. (We may have to generate another random vector and repeat this
calculation if the length of u HC is zero.) After normalizing u HC , the v-axis vector v HC is calculated
from:
v HC = u HC × n HC (5.27)
This gives us the hemi-cube’s view space in world co-ordinates. We will need to reorient this system to
align it with each face before we can project polygons against them. Fortunately, the hemi-cube’s
symmetry makes this particularly easy to do. Following a suggestion by Vilaplana and Pueyo [1992], we
can simply swap co-ordinates and change signs as required for our viewing axes; no other floating point
operations are necessary. Given a hemi-cube’s view space axes u HC , v HC and n HC expressed in world
co-ordinates (Fig. 5.23), the hemi-cube face view spaces can be determined from:
Top: u T = u HC , v T = v HC , n T = n HC
Front: u F = −u HC , v F = n HC , n F = v HC
Right: u R = v HC , v R = n HC , n R = u HC (5.28)
Back: u B = u HC , v B = n HC , n B = − v HC
Left: u L = − v HC , v L = n HC , n L = −u HC
Positioning and orienting the cubic tetrahedron’s viewing system is a more involved procedure than it
is for the hemi-cube. We can use Equations 5.26 and 5.27 to generate a randomly oriented viewing system
whose normal is collinear with the polygon normal and whose origin coincides with the polygon center.
We can think of this as the polygon’s view space, with its axes expressed in world co-ordinates as the unit
vectors u P , v P and n P .
From here, we need to align the cubic tetrahedron’s view space such that the polygon normal has the
1 1 1
view space co-ordinates , , . In terms of the polygon’s view space, the tetrahedron’s view
3 3 3
1 1 1 1 1
u CT = + , − ,
2 3 2 2 3 2 3
1 1 1 1 1
v CT = − , + , (5.29)
2 3 2 2 3 2 3
−1 −1 1
n CT = , ,
3 3 3
Form Factor Determination 307
________________________________________________________________________
u CT = a ∗ u P + b ∗ v P − c ∗ n P
v CT = b ∗ u P + a ∗ v P − c ∗ n P (5.30)
n CT = c ∗ u P + c ∗ v P − c ∗ n P
1 1
a= +
2 3 2
1 1
b= − (5.31)
2 3 2
−1
c=
3
This gives us the cubic tetrahedron’s view space in world co-ordinates. Looking out from the polygon
center through each face, we see a triangular view plane window (Fig. 5.25a). It will be convenient when
we later come to polygon scan conversion to have this window oriented as shown in Figure 5.25b. This can
v {-1,2,1} v
{-2,1,1} {1,1,1} n n
u u
{0,0,1} {0,0,1}
{-1,-1,1} {2,-1,1}
{1,-2,1}
Figure 5.25a - Top view window Figure 5.25b - Rotated top view window
Combining this with our earlier approach for hemi-cubes, we can reorient the cubic tetrahedron’s view
Top: u T = −u CT , v T = − v CT , n T = n CT
Left: u L = −u CT , v L = −n CT , n L = v CT (5.32)
Right: u R = − v CT , v R = −n CT , n R = u CT
308 Form Factor Determination
________________________________________________________________________
We now have a hemi-cube or cubic tetrahedron face view space expressed as vectors u, v and n in
world co-ordinates. With these, we can use Equations 4.8 and 4.9 to determine the view transformation
matrix M needed to transform a polygon vertex’s world co-ordinates to this view space. To repeat those
equations here:
u x uy uz tx
v vy vz t y
M= x (5.33)
n x ny nz tz
0 0 0 1
where:
t x = −o x ∗ u x − o y ∗ u y − o z ∗ u z
t y = −o x ∗ v x − o y ∗ v y − o z ∗ v z (5.34)
t z = −o x ∗ n x − o y ∗ n y − o z ∗ n z
and where the bound vector o (expressed in world co-ordinates) represents the view space origin (i.e., the
polygon center).
Recalling that the origin lies at the eye position (Fig. 5.20), we need to translate the view space one unit
along the n-axis to place the origin in the center of the face. From Equation 4.4, the necessary translation
matrix is:
1 0 0 0
0 1 0 0
T= (5.35)
0 0 1 − 1
0 0 0 1
We also need to perform the usual perspective and normalization transformations. The perspective
transformation matrix is given by Equation 4.14. Since the view distance is exactly minus one, we have:
1 0 0 0
0 1 0 0
P= (5.36)
0 0 1 0
0 0 1 1
The normalization matrix is given by Equations 4.16 and 4.17. However, we have to be careful here,
since the hemi-cube and cubic tetrahedron faces will require different normalization transformations.
Form Factor Determination 309
________________________________________________________________________
Consider the hemi-cube faces: our view plane window is a square, even for the side faces–we are
simply choosing to ignore the bottom half of the view from these windows. Therefore, the aspect ratio is
1 2 0 0 1 2
0 1 2 0 1 2
N HC = (5.37)
0 0 s n rn
0 0 0 1
where s n and rn are determined by our choices for the front and back clipping planes distances F and B.
Unlike our viewing system in Chapter Four, there is no reason to clip against a front and back plane. If
we set the back clipping plane distance to plus infinity (represented in our code as MAX_VALUE), we can
The front clipping plane distance is more problematic. Ideally, we should locate it as close to the eye
position as possible in order to include in the view volume everything above the polygon surface. This
suggests a value of MIN _ VALUE − 1 to ensure that we will not have a divide-by-zero error for a point
exactly on or behind the polygon surface. Recalling Section 4.3, however, we are reminded that
perspective projection distorts the n-axis values. In particular, placing the front plane distance too close to
the eye position degrades the Z-buffer pseudodepth resolution (Section 4.14). A more reasonable value is -
0.99 units, assuming that no two polygons in our environment will be closer together than this. (This is
These arguments for the front and back clipping planes also apply to the cubic tetrahedron faces.
1 3 0 0 1 3
0 1 3 0 1 3
N CT = (5.38)
0 0 s n rn
0 0 0 1
where s n and rn are as given before (Eqn. 4.17). Referring to Figure 5.25b, this transformation translates
the view plane window one unit along the u-axis and v-axis and scales it in these directions by one-third.
The view volume is scaled along the n-axis as before, resulting in the canonical parallel view volume
+1
n
+1
+1
u
Figure 5.26 - Canonical parallel view volume for cubic tetrahedrons
We can concatenate these transformation matrices to obtain the 3-D projective transformation matrix
for our hemi-cube or cubic tetrahedron faces. That is, similar to Equation 4.19, we have:
Pu px
P
v = NPTM p y (5.39)
Pn pz
w 1
{ }
where p x , p y , p z are the world co-ordinates of a polygon vertex p. This provides us with the 4-D
homogeneous co-ordinates we need for polygon clipping. All we need now is a framework in which to
It is clear that we shall need separate polygon clipping strategies for our hemi-cube and cubic
tetrahedron view volumes, if only because of their different clipping planes. At the same time, these
strategies will have much in common. It makes sense then to develop an abstract polygon clipper class and
Much of the following code is an adaptation of PolyClip4, with the addition of components from our
#ifndef _FF_CLIP_H
#define _FF_CLIP_H
#include "ff_poly.h"
Form Factor Determination 311
________________________________________________________________________
public:
FormClipEdge() { first_flag = FALSE; }
return temp;
}
public:
BOOL BackFaceCull( Patch3 *ppatch )
{
Vector3 view; // View vector
312 Form Factor Determination
________________________________________________________________________
#endif
Listing 5.9 - FF_CLIP.H
FF_CLIP.H is very similar to P_CLIP4.H (Listing 4.6). The only major changes are in the derivation of
• the polygon center (center), the view system axis co-ordinates (u, v and n) and a view transformation
matrix (vtm) have been added to assist in reorienting the view system for each hemi-cube or cubic
tetrahedron face.
adaptation of ViewSys::BackFaceCull from Listing 4.2. (If a planar surface patch faces away from the
eye position, then logically all of its elements will do the same.)
Since the view distance, front and back clipping planes distances are now constant, EYE, FPD and BPD
are provided to compute SN and RN in accordance with Equation 4.17. These constants will be used later to
The remainder of our abstract polygon clipper class is adapted from P_CLIP4.CPP (Listing 4.7):
#include "ff_clip.h"
// Clip element
int FormClip::Clip( Element3 *pelem, FormPoly &out, WORD
poly_id )
{
int i; // Loop index
int num_vert; // Number of vertices
Vertex3 *pvert; // 3-D world space vertex pointer
Vector4 hv; // 4-D homogeneous co-ord vertex
return out.GetNumVert();
}
// Calculate parameter
r = (e - s);
d = Dot(normal, r);
return (s + r);
}
if (curr_inside == TRUE)
Output(current, out);
start = current;
start_inside = curr_inside;
}
// Close polygon
void FormClipEdge::Close( FormPoly &out )
{
Vector4 isect; // Intersection vertex
if (first_flag == TRUE)
{
// Does edge intersect plane ?
if (start_inside ^ first_inside)
{
isect = Intersect(start, first);
Output(isect, out);
}
The changes here are relatively minor. The class constructor PolyClip4::PolyClip4 has been removed,
since it depends on the number and orientation of the clipping planes. Also, FormClip::Intersect has been
simplified by removing the vertex color interpolation that was performed by PolyClip4::Intersect.
We can now derive a polygon clipping class expressly for hemi-cubes from FormClip as follows:
#ifndef _HC_CLIP_H
#define _HC_CLIP_H
#include "hc_poly.h"
Form Factor Determination 315
________________________________________________________________________
#include "ff_clip.h"
public:
HemiClip();
#endif
Listing 5.11 - HC_CLIP.H
and:
#include "hc_clip.h"
u = Cross(n, rv);
}
while (u.Length() < MIN_VALUE);
origin = Vector3(center);
vtm[1][0] = nv.GetX();
vtm[1][1] = nv.GetY();
vtm[1][2] = nv.GetZ();
vtm[1][3] = -(Dot(origin, nv));
vtm[2][0] = nn.GetX();
vtm[2][1] = nn.GetY();
vtm[2][2] = nn.GetZ();
vtm[2][3] = -(Dot(origin, nn));
vtm[3][0] = 0.0;
vtm[3][1] = 0.0;
vtm[3][2] = 0.0;
vtm[3][3] = 1.0;
The derivation of HemiClip from our abstract FormClip class completes the adaptation of PolyClip4.
The class constructor is identical to PolyClip4::PolyClip4, except that the back clipping plane has been
removed.
In addition to the functionality provided by its progenitor, HemiClip provides several functions specific
to hemi-cubes. SetView positions the hemi-cube over the polygon center and chooses a random orientation
318 Form Factor Determination
________________________________________________________________________
about the polygon normal, then stores the hemi-cube view system axis world co-ordinates in the protected
members u, v and n. UpdateView reorients these axes to the current face before calling BuildTransform,
BuildTransform is an adaptation of ViewSys::BuildTransform. (Listing 4.2). The only changes are the
addition of a translation transformation (Eqn. 5.35) to shift the origin from the polygon center to the hemi-
cube face and the replacement of the front and back clipping plane distance variables with the constants SN
and RN.
In terms of production-quality code, BuildTransform should really be rewritten to concatenate the view,
translation, perspective and normalization transformations into one matrix. On the other hand, the function
is not called all that often, and its present form is more amenable to debugging.
Our polygon clipping class for cubic tetrahedrons will be almost–but not quite–like HemiClip. The
most notable difference is the canonical view volume shown in Figure 5.26. We need to know the normal
co-ordinates of the diagonal clipping plane, but what does it look like in four homogeneous dimensions?
The answer comes from realizing that this plane is parallel to the n-axis. This means that the third co-
ordinate of the plane normal must be zero. It also means that we can plot the plane in three dimensions as
shown in Figure 5.27. It has the plane equation u + v = w , and we can see by inspection that the plane
v
u+ v= w
1
w
1
0 u
1
Figure 5.27 - Diagonal clipping plane for cubic tetrahedron face
Form Factor Determination 319
________________________________________________________________________
#ifndef _CT_CLIP_H
#define _CT_CLIP_H
#include "ct_poly.h"
#include "ff_clip.h"
public:
CubicClip();
#endif
Listing 5.13 - CT_CLIP.H
and:
#include "ct_clip.h"
c = -1.0 / sqrt(3.0);
a = (c * -0.5) + 0.5;
b = (c * -0.5) - 0.5;
origin = Vector3(center);
vtm[1][0] = nv.GetX();
vtm[1][1] = nv.GetY();
vtm[1][2] = nv.GetZ();
vtm[1][3] = -(Dot(origin, nv));
vtm[2][0] = nn.GetX();
vtm[2][1] = nn.GetY();
vtm[2][2] = nn.GetZ();
vtm[2][3] = -(Dot(origin, nn));
vtm[3][0] = 0.0;
vtm[3][1] = 0.0;
vtm[3][2] = 0.0;
vtm[3][3] = 1.0;
CubicClip::SetView differs from its HemiClip equivalent in that it aligns the cubic tetrahedron view
space with respect to the polygon view space as discussed in Section 5.14 (Equations 5.30 and 5.31).
Similarly, UpdateView is based on Equation 5.32, and BuildTransform uses Equation 5.38 for its
normalization transformation.
and normalization transformations into one matrix. Make sure, however, that you understand how it works
first!
We can derive polygon scan conversion classes for hemi-cubes and cubic tetrahedrons from our
previous PolyRender class. Unlike PolyClip4 and its associated classes, PolyRender requires relatively few
modifications. In fact, all we need to do is to combine the pseudodepth and frame buffers into one “cell
information” buffer that holds the polygon depth and identifier for each hemi-cube face cell, eliminate the
We also need to consider triangular frame buffers for our cubic tetrahedron faces. While this is not as
difficult as it might first appear, it does require an abstract class that we can derive our two polygon scan
conversion classes from. Starting from P_RENDER.H (Listing 4.12) then, we have:
#ifndef _FF_SCAN_H
#define _FF_SCAN_H
#include "ff_poly.h"
public:
virtual ~FormScan() { };
#endif
Listing 5.15 - FF_SCAN.H
The cell information buffer pointed to by elem_buffer replaces the Z-buffer and bitmap object pointers
maintained by PolyRender. The buffer itself will be allocated and initialized by one of the derived classes.
324 Form Factor Determination
________________________________________________________________________
Since the buffer size is fixed at compile time by the delta form factor resolution, FormScan dispenses with
Note that DrawEdgeList has been made a pure virtual function in FormScan. This is what makes
FormScan an abstract class; there is no function body defined for DrawEdgeList. Instead, it must be
One of the problems with virtual functions in C++ is that they are accessed at run-time through a virtual
function table pointer. While this may require only two to four additional machine instructions per function
call, these additional instructions may slow an otherwise small and fast function that could otherwise be
placed inline by the compiler. A second problem is that every object derived from a virtual class has a
hidden pointer to the virtual function table. As a rule of thumb, virtual functions should be used sparingly
DrawEdgeList is an example where a virtual function is required. It is called by Scan, which does not
know what type of frame buffer it should draw to. The code could be rewritten to avoid this situation, but it
On the other hand, the function is virtual only because we are implementing two separate form factor
determination algorithms. In its completed form, our radiosity renderer will only use one of these. In terms
of production-quality code, it would then make sense to merge FormScan with its derived class and
Incidentally, any base class with virtual functions should have a virtual destructor declared for it. This
explains the pure virtual class destructor ~FormScan. It ensures that the appropriate destructor will be
#include "ff_delta.h"
#include "ff_scan.h"
if (psv->face.y == pev->face.y)
{
continue; // Ignore horizontal edges
}
Once you remove the polygon color components from GetVertexInfo and ScanEdges, there is very little
Deriving a polygon scan conversion class for hemi-cubes from FormScan completes our adaptation of
PolyRender. In addition to implementing the minimal changes required, we need to examine the cell
information buffer after scan conversion and sum the delta form factors. This results in the following C++
class:
#ifndef _HC_SCAN_H
#define _HC_SCAN_H
#include "ff_scan.h"
#include "hc_delta.h"
public:
HemiScan();
~HemiScan();
void InitBuffer();
void DrawEdgeList();
void SumDeltas( float *, int );
};
#endif
Listing 5.17 - HC_SCAN.H
and:
#include "hc_poly.h"
#include "hc_scan.h"
status = FALSE;
break;
}
}
}
}
else
{
delete [] edge_list; // Release edge list memory
status = FALSE;
}
}
pedge = &(edge_list[ymin]);
for (y = ymin; y < ymax; y++)
{
// Get scan line info pointers
pss = &(pedge->isect[0]);
pse = &(pedge->isect[1]);
if (face_id == HC_TopFace)
{
// Scan entire face buffer
330 Form Factor Determination
________________________________________________________________________
for (row = 0; row < FF_ArrayRes; row++)
for (col = 0; col < FF_ArrayRes; col++)
{
if ((poly_id = cell_buffer[row][col].id) !=
FF_None)
ff_array[poly_id - 1] +=
dff.GetTopFactor(row, col);
}
}
else
{
// Scan upper half of face buffer only
for (row = HC_ArrayDim; row < FF_ArrayRes; row++)
for (col = 0; col < FF_ArrayRes; col++)
{
if ((poly_id = cell_buffer[row][col].id) != FF_None)
ff_array[poly_id - 1] +=
dff.GetSideFactor(row, col);
}
}
}
Listing 5.18- HC_SCAN.CPP
The cell information buffer is the equivalent of the Z-buffer and bitmap (frame buffer) used by
PolyRender. PolyRender::Open is responsible for allocating and initializing a Z-buffer whose dimensions
are determined by the bitmap being written to. The size of the cell information buffer, on the other hand, is
determined by the hemi-cube resolution. This being a constant, we can allocate the buffer once at program
startup through the class constructor. This replaces PolyRender::Open; the class destructor replaces
PolyRender::Close.
HemiScan::HemiScan uses two arrays to allocate the cell information buffer one row at a time. This
allows us to minimize the possibility of running out of memory due to memory fragmentation. It also
allows us to specify hemi-cube resolutions in excess of 128 × 128 cells under MS-Windows 3.1. If there is
InitBuffer is responsible for initializing the cell information buffer. It must be called before each
the vertex color has been replaced with the polygon identifier.
Finally, SumDeltas does precisely what its name suggests. It scans the cell information buffer looking
for covered face cells. When it finds one, it looks up the associated delta form factor and increments the
Form Factor Determination 331
________________________________________________________________________
indicated polygon’s form factor by that amount. It must be called after each pass through the environment,
since the cell information buffer is reused for the five hemi-cube faces.
Deriving a polygon scan conversion class for cubic tetrahedrons from FormScan results in code that is
a near clone of HemiScan. The only difference is that we now have to allocate and access a triangular cell
#ifndef _CT_SCAN_H
#define _CT_SCAN_H
#include "ff_scan.h"
#include "ct_delta.h"
public:
CubicScan();
~CubicScan();
void InitBuffer();
void DrawEdgeList();
void SumDeltas( float * );
};
#endif
Listing 5.19- CT_SCAN.H
and:
#include "ff_delta.h"
#include "ff_scan.h"
#include "ct_scan.h"
status = FALSE;
break;
}
width--; // Decrement scan line width
}
}
}
else
{
delete [] edge_list; // Release edge list memory
status = FALSE;
}
}
width = FF_ArrayRes;
for (row = 0; row < FF_ArrayRes; row++)
{
for (col = 0; col < width; col++)
{
cell_buffer[row][col].depth = FF_Infinity;
cell_buffer[row][col].id = FF_None;
}
width--; // Decrement scan line width
Form Factor Determination 333
________________________________________________________________________
}
}
pedge = &(edge_list[ymin]);
for (y = ymin; y < ymax; y++)
{
// Get scan line info pointers
pss = &(pedge->isect[0]);
pse = &(pedge->isect[1]);
width = FF_ArrayRes;
for (row = 0; row < FF_ArrayRes; row++)
{
for (col = 0; col < width; col++)
{
if ((poly_id = cell_buffer[row][col].id) !=
FF_None)
ff_array[poly_id - 1] += dff.GetFactor(row, col);
}
width--; // Decrement scan line width
}
}
Listing 5.20- CT_SCAN.CPP
You have to look closely to see the differences between CubicScan and HemiScan. The class
constructor CubicScan::CubicScan allocates the cell information buffer one row at a time as before.
However, the row length is decremented with each succeeding row to allocate the necessary triangular
buffer. Similarly, CubicScan::DrawEdgeList uses the row index when calculating the scan line x-axis co-
ordinates. This ensures that there is no possibility of the column index exceeding the current row length.
The only other difference is CubicScan::SumDeltas, which only needs to access one face type. As such,
We now have the necessary components to implement the hemi-cube algorithm as a C++ class.
Following the algorithm pseudocode presented in Figure 5.21, the implementation becomes almost trivial:
#ifndef _HEMICUBE_H
#define _HEMICUBE_H
#include "parse.h"
#include "hc_clip.h"
#include "hc_scan.h"
public:
BOOL GetStatus() { return scan.GetStatus(); }
void CalcFormFactors( Patch3 *, Instance *, float *,
WORD );
};
#endif
Listing 5.21 - HEMICUBE.H
The function GetStatus should be called once to ensure that the HemiScan object was able to obtain
enough memory for its cell information buffer. Assuming it was successful, CalcFormFactors can then be
called to determine the form factors from a selected polygon to all other polygons in its environment. This
#include "hemicube.h"
Another 1,200 or so lines of source code for our growing library of C++ classes–it is time for another
#include <stdio.h>
#include <stdlib.h>
Form Factor Determination 337
________________________________________________________________________
#include <iostream.h>
#include <time.h>
#include "error.h"
#include "parse.h"
#include "hemicube.h"
return 0;
}
if (ff_flag == FALSE)
{
start = clock(); // Start the program timer
}
if (ff_flag == TRUE)
{
// Report form factors
cout << "Patch " << src_id << endl;
for (rcv_id = 0; rcv_id < num_elem; rcv_id++)
cout << " FF(" << src_id << "," << (rcv_id + 1)
<< ") = " << ff_array[rcv_id] << endl;
}
src_id++;
ppatch = ppatch->GetNext();
}
psurf = psurf->GetNext();
}
pinst = pinst->GetNext();
}
if (ff_flag == FALSE)
{
end = clock(); // Stop the program timer
Form Factor Determination 339
________________________________________________________________________
// Return form factor calculation time
return (double) (end - start) / CLOCKS_PER_SEC;
}
else
return 0.0;
}
Listing 5.23 - TEST_2.CPP
Like TEST_1, this program is a character-mode application that sends its output to the user console.
Once again, _NOT_WIN_APP must be globally defined in order to correctly compile ERROR.CPP
TEST_2 will accept any valid environment file as its input. For example, you could enter:
TEST_2 COL_CUBE.WLD
to calculate the form factors between the faces of the two cubes in the COL_CUBE.WLD environment
(Listing 3.17). A more useful approach, however, is to develop a simple test environment (Fig. 5.28) for
which the form factors can be solved analytically as a comparison. From Siegel and Howell [1992], the
4H R2 − H 2
FdEi − Ej = arctan (5.40)
π 1+ H 2 1+ H 2
where:
W
H=
2d
(5.41)
W
R=
d 2
W Ej
dEi
Figure 5.28 - Test environment
340 Form Factor Determination
________________________________________________________________________
Suppose we choose W = d = 1.0 . Substituting these values into the above equations, we find the
analytic form factor FdEi − Ej to be approximately 0.2395. We can compare this with the estimated form
factor values calculated by HemiCube by first specifying a unit area polygon, as in SQUARE.ENT (Listing
5.24).
With this, we can arrange two instances of the square to be parallel to and face one another at a distance
HemiCube::CalcFormFactors will calculate the form factor from the center of each of these polygons
to the opposing polygon (It will also calculate the form factor to itself, which of course is always zero.) If
you enter:
TEST_2 SQUARE.WLD
when both SQUARE.ENT and SQUARE.WLD are in the current directory, your output should look
the polygon normal. The projection of the opposing polygon onto the hemi-cube depends on this
orientation. Thus, your particular output may also vary from that shown, depending on the random
numbers produced by your program’s rand function and its seed value.
(Your timing results will also depend on how busy your machine is. The above results were obtained
using an Intel ‘486 66 MHz machine running MS-DOS. If you run TEST_2 in a multitasking environment
(which includes MS-Windows 3.1), the results will indicate in part what percentage of the CPU’s time your
#ifndef _CUBIC_T_H
#define _CUBIC_T_H
#include "parse.h"
#include "ct_clip.h"
#include "ct_scan.h"
public:
BOOL GetStatus() { return scan.GetStatus(); }
void CalcFormFactors( Patch3 *, Instance *, float *,
WORD );
};
#endif
342 Form Factor Determination
________________________________________________________________________
and:
#include "cubic_t.h"
essentially identical.
We can test our cubic tetrahedral algorithm code with the following test program. More importantly, we
can compare its form factor estimates with those produced by our hemi-cube implementation in TEST_2.
#include <stdio.h>
#include <stdlib.h>
#include <iostream.h>
#include <time.h>
#include "error.h"
#include "parse.h"
#include "cubic_t.h"
return 0;
}
if (ff_flag == FALSE)
{
start = clock(); // Start the program timer
}
if (ff_flag == TRUE)
{
// Report form factors
cout << "Patch " << src_id << endl;
for (rcv_id = 0; rcv_id < num_elem; rcv_id++)
cout << " FF(" << src_id << "," << (rcv_id + 1)
<< ") = " << ff_array[rcv_id] << endl;
}
src_id++;
ppatch = ppatch->GetNext();
}
psurf = psurf->GetNext();
}
pinst = pinst->GetNext();
}
if (ff_flag == FALSE)
{
end = clock(); // Stop the program timer
TEST_3 SQUARE.WLD
when both SQUARE.ENT and SQUARE.WLD are in the current directory, your output should look
something like:
346 Form Factor Determination
________________________________________________________________________
Polygon 1
FF(1,1) = 0
FF(1,2) = 0.23486
Polygon 2
FF(2,1) = 0.23518
FF(2,2) = 0
produced by our HemiCube class. The HemiCube estimates were off by an average 0.33 percent; these are
off by 1.04 percent. Remember, however, that these are random values. Also, the accuracy of both
algorithms will vary depending on the specific polygon-to-polygon geometry and hemi-cube resolution.
The more important issue is the variance in their estimates for many thousands of polygons in a complex
environment.
The second point is that CubicTetra appears to be faster than HemiCube in determining form factors. It
was–for this particular geometry and resolution. The question is whether this will remain true when the to
The cubic tetrahedral algorithm should in theory be the faster of the two. Pavicic [1994] noted that it
needs to perform an average of 2.75 clipping operations for small polygons, while the hemi-cube algorithm
must perform 3.83 such operations on average. However, there are various programming tricks that can
skew the results markedly. Suppose for example that we tag a polygon when we clip it against a face and
find that it is a) entirely within the view volume, b) backface culled or c) behind the “eye position” defined
by the view space origin and the receiving polygon’s normal. (The flags member of Element3 (Listing
3.11) has some spare bits that can be used for this purpose.) We could then trivially reject the polygon
Another possibility is to tag the faces themselves if a polygon is clipped against the boundary of an
adjoining face. In this case, we then know that the polygon should be clipped against the tagged face as
well. These tricks may provide marked increases in execution time for complex environments, perhaps as
much as 100 percent or more. Which algorithm is then the better one? That depends on your programming
ingenuity.
Form Factor Determination 347
________________________________________________________________________
This, however, misses the point. We examined the cubic tetrahedral algorithm as an interesting
alternative to the hemi-cube. Certainly, we can profile their performances and implement various speed-up
techniques. However, our primary objective is to explore the radiosity approach. Implementing both
algorithms is an ideal way of doing so. Besides, we now have two form factor determination classes to play
with.
While the cubic tetrahedral algorithm may be faster, the hemi-cube offers an advantage for those with
computer graphics workstations: hardware acceleration. Many of these high-end machines implement 3-D
graphics primitives using specialized hardware graphics accelerators. Supported operations usually include
backface culling, 3-D polygon clipping, scan conversion, Z-buffering and Gouraud shading. A library of
callable low-level graphics functions enables users to directly access this hardware.
Rushmeier et al. [1991] discussed several techniques for accelerating the hemi-cube algorithm. For
graphics workstations they proposed the following: first, allocate a screen window to represent a hemi-
cube face and initialize the view transformation matrix. The vertices of each polygon in the environment
are then sent to the graphics coprocessor for display, with the polygon identifier representing its “color”.
Once the environment has been processed, the color is read for each pixel in the window and a polygon
ENDFOR
Figure 5.29 - Hardware-assisted hemi-cube algorithm
Comparing this to our software implementation, it is clear that we have done it the hard way!
Hardware-assisted hemi-cube algorithms have been implemented by Cohen et al. [1988], Baum et al.
[1989] and others. Rushmeier et al. [1991] reported that execution times for backface culling, polygon
clipping and Z-buffering were improved by a factor of 100 or more. On the other hand, the remaining
operations of issuing vertex lists to the graphics processor and summing the delta form factors still has to
be implemented in software. As a result, the overall acceleration of the hemi-cube algorithm over an
equivalent software implementation ranged from 160 percent for a resolution of 50 × 50 cells to 350
Special purpose graphics processors dedicated solely to form factor determination have been developed
(e.g., Bu and Deprettere [1987a,b] and Bu and Deprettere [1989]). However, these are so far experimental
devices. Until we have commercially available graphics coprocessors designed specifically for radiosity
rendering (or at least ones that can be microprogrammed to implement the necessary algorithms), we shall
have to rely upon our programming skills to maximize the performance of our algorithms.
We can simplify the hemi-cube algorithm even further by replacing the hemi-cube with a single
projection plane placed directly above and parallel to the differential polygon element dEi (Fig. 5.30). At
first, this appears to offer at least one advantage: there is only one plane to clip against. It is definitely
faster–Recker et al. [1990] reported a speedup of approximately 100 percent over the hemi-cube algorithm.
However, there are hidden costs to this approach that diminish its usefulness.
2S
2S
dEi
Figure 5.30 - Single plane algorithm
Form Factor Determination 349
________________________________________________________________________
The first problem is that the plane does not cover the entire hemisphere above the element. This means
that polygons in the environment near the horizon will be missed. In physical terms, this means that we
may underestimate the radiant flux that is either received or emitted by dEi when we perform our radiosity
calculations. However, this may not be significant in practice. Sources near the horizon typically contribute
very little to the overall flux received by a surface due to the cosine factor. Similarly, Sillion and Puech
[1989] demonstrated that if dE i is a Lambertian emitter, the amount of flux “escaping” from beneath the
plane is approximately 2(H S )2 . If we are willing to accept an error of one percent, then an S H ratio of
14:1 is appropriate.
The second problem is that the delta form factors now vary widely. If we are to avoid objectionable
aliasing artifacts, the largest delta form factors should be comparable to those of the hemi-cube. These
occur for cells directly over dE i , and so the cell sizes should be comparable. Unfortunately, this means
that the single plane, with its area of 4S 2 = 784 square units (for a S H ratio of 14:1) versus the hemi-
cube’s 12 square units, will have approximately 65 times as many cells as the hemi-cube!
Sillion and Puech [1989] solved this problem by using variable-size cells (which they called “proxels”).
They subdivided the plane such that each cell would have approximately the same form factor.
Unfortunately, this precludes the use of the Z-buffering algorithm for scan conversion, which requires
equal-size cells. Sillion and Puech used Warnock’s Algorithm (e.g., Sutherland et al. [1974]) to subdivide
the projected polygons until each one was either fully visible or fully hidden. While this is a more
complicated approach than the Z-buffer algorithm, it does have the advantage of having a time complexity
that is linear with the number of polygons in the scene being viewed. Sillion and Puech compared the
execution times of their single plane algorithm versus the hemi-cube algorithm for an environment of 1,152
Recker et al. [1990] proposed an alternative solution that does not require an area subdivision
algorithm. First, a second plane with a higher cell resolution is centered within the first plane (Fig. 5.31). A
polygon is then transformed and clipped to the view volume of the outer plane, with the clipped polygon
vertices being saved for later use. The polygon is scan converted over the outer plane, ignoring the region
350 Form Factor Determination
________________________________________________________________________
occupied by the inner plane, and then summed the delta form factors for the covered cells. The saved
polygon vertices are then clipped again to the inner plane’s view volume and scan converted. The delta
form factors are summed and added to those summed during the first pass.
The lower resolution of the outer plane speeds the scan conversion process, but this is mostly negated
by having to clip and scan the polygon twice. In practice, this modified single plane algorithm reduces the
number of cells and delta form factors required by some 80 percent while offering approximately the same
2S
2S
dEi
Figure 5.31 - Modified single plane algorithm (Recker et al. [1990])
The third problem is not so easily overcome. The single plane’s field of view is much larger than the
hemi-cube’s top face, and so the view distance is much closer to the view plane window. Recalling
Equation 4.13, we can see that this will severely affect our pseudodepth scale for Z-buffering. That is, our
3-D projective transformation scales the depth pn of a vertex from view plane according to
p n ' = p n (1 − p n d ) , where d is the view distance and pn ' is the pseudodepth. Given, for example, two
points with true depths 10 and 11 units from the view plane, decreasing the view distance by a factor of 14
All we can do to counteract this problem is to increase the precision of our Z-buffer. In C++, this means
going from a float to a double, doubling the size of the buffer. On the other hand, this may not be
necessary. The changes to the pseudodepth scale may not pose a problem for typical environments of
interest.
Interested readers might consider implementing the modified single plane algorithm for themselves, if
only to compare its performance with the hemi-cube and cubic tetrahedral algorithms. It should be possible
Form Factor Determination 351
________________________________________________________________________
to derive a single plane class from FormClip and FormScan with relatively little effort, using HemiClip and
HemiScan as prototypes.
Ray casting techniques offer yet another approach to form factor determination. Maxwell et al. [1986]
and Malley [1988] used stochastic (Monte Carlo) techniques to shoot randomly distributed rays into the
environment from the surface of a polygon. Malley’s approach was to reverse Nusselt’s Analogy (Fig.
5.32). A hemisphere is placed over the center of a polygon, following which random points on the base are
chosen and rays shot straight up. When they intersect the surface of the hemisphere, they are redirected
along the surface normal at that point (i.e., radially from the hemisphere’s center). Each ray is then tested
for intersections with other polygons in the environment using conventional ray tracing techniques. A
polygon’s form factor is given by the number of rays it intercepts divided by the total number of rays shot.
This is a valuable technique in that it can be applied to both planar and curved surfaces. It can also
accommodate transparent objects and non-diffuse surfaces. The random distribution of points ensures that
aliasing artifacts are minimized, and no 3-D projective transformation, polygon clipping or scan conversion
operations are required. Moreover, there are many ray tracing techniques (e.g., Glassner [1990]) that can be
used to accelerate the ray-polygon intersection calculations. The only disadvantage is that a large number
of rays must be shot in order to approach the accuracy provided by the hemi-cube algorithm and its
variants.
352 Form Factor Determination
________________________________________________________________________
Many of the problems associated with the hemi-cube and cubic tetrahedral algorithms can be avoided
by taking a different appraoch to form factor determination. Wallace et al. [1989] proposed that we instead
model the emitting polygon as a finite area source and determine its form factor as seen from each
receiving polygon’s vertex in the environment (Fig. 5.33). The source is subdivided such that its size is
much smaller than the distance to the vertex. The delta form factor is then calculated for each one; the
Source
Receiver
We could use contour integration (Eqn. 5.6) to solve the individual delta form factors. However, this
can be very time consuming, and it does not address the polygon occlusion problem. Wallace et a. [1989]
instead proposed approximating each small polygon as an arbitrarily oriented disk (Fig. 5.34).
Ei
θ a
i
r
θj
dEj
Figure 5.34 - Form factor geometry between differential area dE j and finite disk Ei
Form Factor Determination 353
________________________________________________________________________
From Siegel and Howell [1992], the analytic form factor from a differential area dE j parallel to and at
(
FdEj − Ei = a 2 r 2 + a 2 ) (5.42)
This is the geometry shown in Figure 5.34, where θ i = θ j = 0 . Using the reciprocity relation from Section
where dA j is the area of a differential element dE j surrounding the vertex and Ai is the area of the
We can generalize this result by including the cosines of the angles between the surface normals and
If we divide the source polygon finely enough, we can model each Ei as a differential area and shoot a
single ray from the receiver vertex dE j . If the ray intersects any intervening polygons, then that portion of
the source is hidden from the vertex. Assuming that the source polygon is planar and has been evenly
subdivided, its total form factor as seen from the vertex is:
dA j n cosθ jk cosθ ik
Fij ≈
n
∑ HIDk πrk 2 + Ai n
(5.45)
k =1
where n is the number of subdivided source polygons and HIDk is one if the kth source polygon is visible
We will later be interested in the reciprocal form factor F ji . Using the reciprocity relation, this is:
Ai A n cosθ jk cosθ ik
F ji =
dA j
Fij ≈ i
n
∑ HIDk πrk 2 + Ai n
(5.46)
k =1
One comment before we continue. Equation 5.44 assumes that the source polygon can be modeled as a
circular disk. This approximation holds true for equilateral triangles and square quadrilaterals. However, it
354 Form Factor Determination
________________________________________________________________________
does not accurately model long, thin polygons. This is not a serious problem. As we shall see in Chapter
Seven, the polygonal elements in our environment should not be long and thin to begin with.
The efficiency of the ray casting approach depends on how quickly we can perform ray-polygon
intersection calculations for possibly occluding polygons. Fortunately, there is a particularly elegant
algorithm for convex polygons due to Badouel [1990] that is fast and efficient.
The first step is to define the ray (Fig. 5.35). Its origin is the receiver vertex S, while its direction is the
r E
P
S
p(t ) = S + t ∗ r (5.47)
where t ≥ 0 . That is, for any positive value of t, p(t ) describes a point in the direction of r. Furthermore, a
Now, given an arbitrary polygon, we need to determine whether it intersects the ray between S and E.
The polygon vertices define a plane, so we can first ask whether the ray intersects this plane. This problem
is equivalent to that discussed in Section 4.8.2, where the line between S and E represented a polygon edge.
d − n ⋅S
t= (5.48)
n ⋅r
where n is the polygon normal, S is the bound vector from the world space origin to the receiver vertex S
and d is the distance from the world space origin to the nearest point on the plane. From Equation 4.27, this
is:
d = n ⋅p (5.49)
Form Factor Determination 355
________________________________________________________________________
where p is the bound vector from the world space origin to any point on the plane. For convenience, this
The denominator of Equation 5.48 should be evaluated first to avoid a division-by-zero error. If it is
equal to zero, then the ray is parallel to the polygon and so does not intersect the polygon.
Equation 5.48 is then evaluated to find t. If it is less than zero, then the plane is behind the receiver
vertex S. If it is greater than one, then the plane is behind the source point E. In either case, the ray does not
intersect the polygon between S and E, and so we are done. Otherwise, we now have to determine whether
the ray intersects the polygon itself and not just its plane. This is where it gets interesting.
Assume that the polygon is a triangle with vertices p 0 , p1 and p 2 , and that Q represents the ray-
polygon intersection point (Fig. 5.36). If we define Q as the bound vector from p 0 to Q, v 1 as the bound
vector from p 0 to p1 and v 2 as the bound vector from p 0 to p 2 , vector addition shows us that:
Q = α ∗ v1 + β ∗ v 2 (5.50)
where α and β are constants. The intersection point Q will be inside the polygon if and only if α ≥ 0 ,
β ≥ 0 and α + β ≤ 1 .
p1
v1
α v1
Q βv2 p0
v2
p2
Figure 5.36 - Vector representation of ray-triangle intersection point Q
Separating Equation 5.50 into its world space axis components, we have:
xQ − x0 = α (x1 − x0 ) + β (x 2 − x 0 )
y Q − y 0 = α ( y1 − y 0 ) + β ( y 2 − y 0 ) (5.51)
z Q − z 0 = α (z1 − z 0 ) + β (z 2 − z 0 )
356 Form Factor Determination
________________________________________________________________________
We want to solve for α and β. Suppose we project the triangle and vectors shown in Figure 5.36 onto the
x-y, x-z or y-z plane. That is, we only consider two of the three equations in the above equation. We must
ensure that the polygon is not perpendicular to the plane; otherwise, the projection will be a straight line.
We therefore need to find the dominant axis of the polygon normal (i.e., the component with the largest
{ }
magnitude) and choose the plane perpendicular to it. Given the polygon normal n = n x , n y , n z , we
x if
n x = max n x ,( ny , nz )
q = y if ny = max ( n , x ny , nz ) (5.52)
= max ( n , )
z if nz x ny , nz
We then project onto the plane perpendicular to this axis. If we define its axes as s and t, then we have:
s o = Qs − p 0 s , t 0 = Qt − p 0t
s1 = p 2 s − p 0 s , t1 = p1t − p 0t (5.53)
s 2 = p 2 s − p 0 s , t 2 = p 2t − p 0t
s 0 = α ∗ s1 + β ∗ s 2
(5.54)
t 0 = α ∗ t1 + β ∗ t 2
s1 s 2 α s 0
t = (5.55)
1 t 2 β t 0
Using Cramer’s Rule (see any text on elementary matrix theory), the solutions to this equation are:
s s2
det 0
t0 t 2 s0 t 2 − s 2 t 0
α= = (5.56)
s s2 s1t 2 − s 2 t1
det 1
t1 t 2
and:
s s0
det 1
t1 t 0 s1t 0 − s 0 t1
β= = (5.57)
s s2 s1t 2 − s 2 t1
det 1
t1 t 2
Form Factor Determination 357
________________________________________________________________________
Solving for α and β allows to us to determine whether a given ray intersects a triangular polygon. We
can clearly extend this result to any convex polygon by dividing it into triangles.
Two other algorithms of interest are presented by Haines [1991] and Voorhies and Kirk [1991]. Also, Woo
[1990] offers an acceleration technique using bounding boxes to quickly cull non-occluding polygons
One simple acceleration technique we can employ is called shadow caching (Haines and Greenberg
[1986]). The likelihood is that if a ray shot from the vertex to the source is occluded by a given polygon,
then other rays shot to the source will also be occluded by the same polygon. When a shot ray is occluded
then, a pointer to the occluding polygon is cached. When the next ray from the vertex is shot, this polygon
is tested first. If it occludes the ray, then there is no need to step through the rest of the environment.
The accuracy of the ray casting approach depends on the number of rays we shoot from a vertex to the
source. The question is, how should we choose points on the source such that we adequately sample the
One approach is to use the element vertices that define the source patch. Depending on the distance of
the source from the receiver, this may or may not provide adequate sampling resolution. In either case, the
uniform spacing of the element vertices may cause form factor aliasing problems. Wallace et al. [1989]
show that any aliasing artifacts will be particularly noticeable at shadow edges. What should be soft-edged
shadows will have a jagged staircase appearance. The effect is similar to that of hemi-cube aliasing, except
A second approach is to calculate the vertex radiant exitances and then average each one according to
its nearest neighbors. Our Vertex3 class allows us to do this, since each vertex has a pointer to a linked list
of shared polygons.
The best approach, however, is to choose a set of uniformly random points on the source polygon. The
more rays we shoot from the receiver, the better the form factor estimate will be. The resultant random ray
358 Form Factor Determination
________________________________________________________________________
directions will tend to minimize any form factor aliasing, much as jittering the orientation did for the hemi-
cube algorithm.
This requires yet another algorithm. Turk [1990] describes a simple technique for triangles and convex
polygons. Given a triangle with vertices p 0 , p1 and p 2 (Fig. 5.37) and two random numbers s and t
IF s + t > 1
s =1− s
t =1− t
ENDIF
a = 1− s − t
b=s
c=t
Q = a ∗ p 0 + b ∗ p1 + c ∗ p 2
where the vertices p and the intersection point Q are expressed as bound vectors from vertex p 0 .
p2
t Q
p0
s
p1
s + t <= 1
p2 1-s
t
Q
p0 1-t
s p1
s+t>1
Figure 5.37 - Generating a random point inside a triangle
Form Factor Determination 359
________________________________________________________________________
We can extend this algorithm to convex polygons by dividing them into triangles and using a third
random number to choose which triangle should be considered. To maintain a uniform distribution, the
probability of choosing a given triangle should be determined by its area relative to that of the polygon.
There is one final consideration: what is an appropriate number of rays to shoot? With each successive
ray, the form factor estimate determined by Equation 5.46 becomes more accurate. We could continue to
shoot rays until the difference between successive estimates is less than some predetermined criterion.
(This being a random process, several more rays should be shot to ensure that the difference is not a
statistical fluke.) Since the total number of rays appears in Equation 5.46, it would have to be recalculated
The problem with this approach is that it becomes increasingly inefficient as the distance between the
source and the receiver vertex decreases. When they are very close and the true form factor approaches
unity, rays shot towards the horizon of the receiver vertex’s hemispherical field of view will have very
little effect.
Wallace et al. [1989] solved this problem by adaptively subdividing the source polygon such that each
subdivided area had approximately the same analytic form factor when seen from the receiver vertex. In
this sense, it is similar to Sillion and Puech’s single plane algorithm (Sillion and Puech [1989]), except that
the plane is overlaid on the source polygon. Wallace et al. then shot a ray to the center of each subdivided
polygon. Excellent results were obtained using as few as sixteen rays per receiver vertex. Unfortunately,
there is a considerable amount of overhead involved in subdividing arbitrary polygons in this manner.
Wallace et al. used uniform subdivision for the more complex images in their paper.
Another possible solution is to estimate the unoccluded form factor of the source patch and scale the
number of rays to be shot according to this estimate. A small or distant source patch will require relatively
few rays, say a minimum of four. A large or very close patch will require a large number of rays, perhaps
as many as several thousand for a patch that nearly fills the hemispherical field of view of the receiver
vertex.
Suppose we enclose the source patch in a bounding sphere that is centered on the patch’s center and
whose radius r is equal to the distance to the furthest vertex (Fig. 5.38).
360 Form Factor Determination
________________________________________________________________________
Bounding sphere
r
Source patch
n φ
d
θ
Receiver vertex
Knowing the distance d of the patch center from the receiver vertex, we can calculate the half-angle φ
φ = arctan(r d ) (5.58)
ω = 2π (1 − cos φ ) (5.59)
(e.g., Hall [1989]). From this, the form factor of the bounding sphere is approximated by (Cohen and
Wallace [1993]):
cos θ
Fvertex− source ≈ ω (5.60)
π
We should be careful when implementing this solution. Solving the radiosity equation involves more
than simply obtaining reasonable form factor estimates. A small but highly luminous light source located
near the vertex’s horizon may provide most of the incident flux at the vertex. In this case, we shall want to
determine whether another patch occludes even a small portion of the source patch. We need to shoot some
minimum number of rays–say four–in order to ensure accurate form factor estimates for all sources,
A second consideration is that we will likely be subdividing our surfaces into patches and elements
such that the Five-Times Rule (Section 5.5) is satisfied. There will be occasions where this assumption
must fail–surfaces that join at right angles, for example–but then there will likely be no intervening
patches. Given this, it is reasonable to use a constant number of rays that adequately sample source patches
Form Factor Determination 361
________________________________________________________________________
with a maximum half-angle φ of 0.1 radians (5.7 degrees). Again, four rays will usually provide adequate
results.
Before implementing a C++ class for our ray casting algorithm, we should review the advantages
offered by the ray casting approach. First and foremost, it efficiently samples the environment. Rays are
cast only in the precise direction of the source for each vertex.
Second, ray casting mostly avoids the aliasing problems caused by a uniform sampling of the
environment. In particular, the plaid-like shading artifacts that are sometimes evident when the hemi-cube
Third, the ray casting approach ensures that all sources are considered, regardless of their size. Unlike
the hemi-cube algorithm and its derivatives, there is no possibility that a small and distant light source will
be missed. This allows the user to include point light sources in the description of the environment.
Related to this advantage is the ability to include physically realistic light sources in the environment
description. Most light sources have non-Lambertian flux distributions (e.g., Warn [1983], Verbeck and
Greenberg [1984], Ashdown [1993]). A theater spotlight is an extreme but still common example–its flux
is emitted primarily in one direction. Most light fixture manufacturers provide goniophotometric diagrams
that represent the fixture as a point source and show or tabulate its luminous intensity for various vertical
Ray casting allows us to readily incorporate these sources in our radiosity solutions. This includes not
only theoretical point sources (Warn [1983], but also physically accurate area sources (Verbeck and
Greenberg [1984]) and complex volume sources (Ashdown [1993]). All that is required is a C++ object for
the light source that encapsulates its three-dimensional flux distribution and returns the luminance of a ray
Fourth, we need to know the vertex exitances in order to perform Gouraud shading of the visible
elements in a scene. We shall see in the next chapter that the hemi-cube algorithm only provides exitances
for the element centers; the vertex exitances must be obtained through interpolation. In contrast, the ray
A fifth advantage comes from our ability to model complex surfaces as a mesh of polygon patches and
elements. Wallace et al. [1991] used a quadratic spline to model a complex curved surface. This was then
represented by a mesh of 1176 elements for radiosity and rendering purposes. However, the ray occlusion
tests were performed using the implicit quadratic spline equation for the surface. Rather than testing for
occlusion against each element for each vertex and each ray (five rays per vertex were used), the test
A final advantage is that ray casting determines one form factor at a time. Unlike the hemi-cube
algorithm, there is no need to provide storage for the form factors of every element in the environment.
Compared to these advantages, the two disadvantages of ray casting are minor but still noteworthy.
First, the hemi-cube algorithm processes each element in the environment once for each patch. Given m
patches and n elements, this results in an algorithmic time complexity of O(mn ) . (See Section 2.6 for an
overview of the meaning of time complexity.) A naive implementation of the ray casting algorithm, on the
other hand, processes each patch in the environment once for each vertex for the ray occlusion tests.
However, it must also process every element in the environment for each source patch to test for possible
occlusion. This gives a time complexity of O(mn 2 ) . Thus, ray casting becomes increasingly more
expensive relative to the hemi-cube approach as the complexity of the environment grows. Fortunately, this
situation improves dramatically when ray tracing acceleration techniques (e.g., Arvo and Kirk [1989]) or
The second disadvantage is that the ray casting algorithm requires the vertex normal for its ray
occlusion test calculations. This adds an additional 12 bytes to every Vertex3 object. Without it (and the
hemi-cube algorithm does not need it), the size of Vertex3 could be reduced by over 25 percent. This can
Vilaplana and Pueyo [1992] noted a corollary to these disadvantages. An extremely complex
environment can in theory be stored in virtual memory. However, we shall see in the next chapter that both
the hemi-cube and ray casting algorithms continually cycle through the entire environment as the radiosity
equation is being solved. This means that portions of the environment will be repeatedly paged from virtual
memory. In practical terms, this means a nearly continuous stream of data will occur to and from the hard
Form Factor Determination 363
________________________________________________________________________
disk or network server. The polite term for this behavior is “thrashing”; network system administrators and
This is where the inner loop of the ray occlusion test becomes important. Accessing every patch for
every vertex may greatly increase the amount of virtual memory paging. In situations where virtual
memory usage is unavoidable, ray casting may not be the algorithm of choice.
We can assemble the above algorithms into a class that, stated in pseudocode, performs the following:
Given a source patch s, this algorithm is repeated for every vertex in the environment. Unlike the hemi-
#ifndef _RAY_CAST_H
#define _RAY_CAST_H
#include "parse.h"
public:
void Init( Patch3 * );
double CalcFormFactor( Vertex3 *, Instance * );
};
#endif
Listing 5.29 - RAY_CAST.H
Init is called once for each source patch to initialize the RayCast private members with several of its
attributes. The environment is then processed one vertex at a time. Recalling that each Instance3 object has
a pointer to its linked list of vertices, we can access each vertex exactly once. CalcFormFactor is then
Note that RC_NumRays is set to 4. This will produce satisfactory results for most environments.
However, it should be increased for environments where the vertex-to-source distance is expected to be
#include "ray_cast.h"
start = Vector3(pvertex->GetPosn());
nv = pvertex->GetNormal();
view = start - src_center;
ff = 0.0;
for (i = 0; i < RC_NumRays; i++)
{
// Select random point on source patch
Select(&end);
return ff;
}
psrc = ppatch;
pcache = NULL;
src_area = psrc->GetArea();
src_norm = psrc->GetNormal();
src_center = Vector3(psrc->GetCenter());
ray_area = src_area / RC_NumRays;
if (ppatch->IsQuad() == TRUE)
{
// Calculate patch edge vector
e2 = Vector3(v3 - v0);
return TRUE;
}
}
ppatch = ppatch->GetNext();
}
psurf = psurf->GetNext();
}
pinst = pinst->GetNext();
}
return FALSE;
}
// Calculate divisor
d = Dot(normal, ray_dir);
s2 = vert[i][i1] - vert[0][i1];
t2 = vert[i][i2] - vert[0][i2];
return i_flag;
}
Listing 5.30 - RAY_CAST.CPP
While somewhat lengthy, the above code is mostly a straightforward rendition of the preceding
algorithms. You might compare it against the total amount of C++ code needed to implement the hemi-
The only implementation issue of note is TestPatch, where a small value (MIN_VALUE) is added to the
tests that determine whether the patch intersects the ray between the receiver vertex and the source.
370 Form Factor Determination
________________________________________________________________________
Remember that adjoining surfaces do not share vertices, since they will likely have different Spectra
exitance values. The offsets are necessary to prevent these vertices from being seen as occluding the ray.
Note also that RayCast does not implement the bounding sphere heuristic. Instead, it always shoot
RC_NumRays rays (defined in RAY_CAST.H above). Implementation of Equations 5.58 through 5.60 is
#include <stdio.h>
#include <stdlib.h>
#include <iostream.h>
#include <time.h>
#include "error.h"
#include "parse.h"
#include "ray_cast.h"
return 0;
}
Listing 5.31 - TEST_4.CPP
TEST_4 can be used with any environment (*.WLD) file. To verify the results, however, we can use:
This is essentially the same geometric arrangement as that shown in Figure 5.28, where W = d = 1 . The
differential element is approximated by a square measuring 0.0001 units across. From Equations 5.40 and
Since the vertices are relatively close to the source patch (more so than they would likely be in a typical
environment, RC_NumRays (Listing 5.29) should be defined as 16 for the purposes of this test program. A
Patch 1
FF(1,1) = 0
FF(2,1) = 0
FF(3,1) = 0
FF(4,1) = 0
FF(5,1) = 0.243623
FF(6,1) = 0.232016
FF(7,1) = 0.230337
FF(8,1) = 0.222784
Patch 2
FF(1,2) = 1.4147e-009
FF(2,2) = 1.41473e-009
FF(3,2) = 1.4147e-009
FF(4,2) = 1.41466e-009
FF(5,2) = 0
FF(6,2) = 0
FF(7,2) = 0
FF(8,2) = 0
Number of rays = 16
Again, remember that these values were produced by a random process. This explains why the four
largest form factors differ slightly. On the other hand, note that the form factors to the differential patch #2
are calculated. If you run TEST_2 and TEST_3 on RAY_TEST.WLD, you will see that the hemi-cube and
We have so far used backface culling to eliminate those polygons that face away from the source patch
(hemi-cube algorithm) or receiver vertex (ray casting algorithm). This still leaves us with the task of
examining each and every polygon in the environment for each source patch or receiver vertex. Since the
Form Factor Determination 373
________________________________________________________________________
underlying patch effectively divides the environment into two half-spaces, we should consider possible
techniques for eliminating those polygons (and portions thereof for boundary cases) in the half-space we
cannot “see” from the hemi-cube or vertex as quickly and efficiently as possible.
We need not look far; the ray tracing literature is replete with visibility preprocessing algorithms. The
basic principle is to divide the environment into a hierarchy of nested subspaces. One example is octree
encoding, where the volume of space enclosing the environment is recursively divided into eight subspaces
struct OctreeNode
{
Element3 *pelem; // Element pointer
OctreeNode *pchild[8]; // Child node pointers
};
is then used to link these subspaces into a octree. Each leaf node of the tree points to exactly one patch
element; the subspace representing the node forms a spatial bounding box around the element. Traversing
the tree from root to leaf allows us to determine the position of element to within the limits of the bounding
box. It also allows us to cull large portions of the tree without having to examine each element.
A more efficient technique for representing the hierarchy of octants is binary space partitioning. The
environment is recursively divided into half-spaces by planes, where three perpendicular planes form eight
octants. Each node requires less memory, and the depth of the tree is typically smaller than the octree.
Wang and Davis [1990] present a visibility preprocessing algorithm based on a binary space
partitioning (BSP) tree that specifically addresses hemi-cube requirements. They used a priority list
374 Form Factor Determination
________________________________________________________________________
structure to order the partitioning planes in front to back order as seen from the hemi-cube center. By
traversing this list, they managed to avoid having to perform Z-buffering for the elements.
BSP trees are also very useful for ray casting vertex-to-source form factors. Sung and Shirley [1992]
examined a variety of spatial subdivision algorithms and concluded that the BSP offers the best
performance for ray tracing applications. Included with their presentation is an extensive and well
Finally, Ng and Slater [1993] provide a wealth of information on BSP trees and bounding boxes
relating to their study of a multiprocessor-based radiosity renderer. By enclosing the source and receiver
patches in an axis-aligned bounding box (Fig. 5.40), they were able to cull most non-occluding polygons
by checking whether any of their vertices were inside the box. Constructing the box for each pair of
polygons and checking vertices against it can proceed very quickly, since the bounding planes of the box
The advantage of the bounding box approach is that it eliminates the need to build, store and
manipulate a BSP tree or other auxiliary data structure. Ng and Slater [1993] found that using bounding
boxes alone resulted in execution speeds nearly twice that of implementations based on BSP trees for small
More information on bounding boxes and related techniques can be found in Marks et al. [1990],
Haines and Wallace [1991] and Zhang [1991]. In addition, an excellent source of ray tracing acceleration
5.26 Conclusions
Form factor determination is a major component of any radiosity rendering program, and so it is
entirely appropriate that we have devoted so much space to the topic. It is also frustrating not to have the
space to address the topic in even greater depth. Interested readers are strongly encouraged to investigate
the following references: Baum et al. [1989], Cohen and Wallace [1993], Max and Troutman [1993], Max
and Allison [1992], Pietrek [1993], Recker et al. [1990], Rushmeier et al. [1991], Sbert [1993], Sillion and
Puech [1989], Spencer [1992], Sun et al. [1993], Tampieri [1992], Vilaplana and Pueyo [1992], Wallace
[1989], Wang et al. [1992], Wang and Davis [1990], Emery et al. [1991] and Zhou and Peng [1992].
A visibility preprocessing algorithm should be included in any production quality radiosity renderer.
The bounding box approach is almost trivial to implement. Readers interested in the BSP tree approach
will find a excellent example and implementation in Sung and Shirley [1992] that can adapted with
relatively little effort to vertex-to-source ray casting. It can also be used for the hemi-cube algorithm,
It should also be noted that the code presented in this chapter was written with the reader, not execution
time, in mind. Despite our concern for a “carefully crafted C++ implementation”, no attempt has been
Optimizing compilers will improve matters to some extent by assigning register variables, unrolling
loops, inlining functions and so forth. However, obtaining the best performance often requires hand
optimization and even assembly language programming for the most time-critical functions. This comes at
a considerable cost: highly optimized code is difficult to document clearly and even more difficult to
understand.
Nevertheless, the performance-minded reader is encouraged to consider hand optimization of the source
code. Following standard software engineering practices, you should: a) fully understand the underlying
algorithms before you begin, b) perform a careful analysis with a source code profiler to pinpoint execution
This, however, should be a project for the future. We have no less than three form factor determination
methods in hand, and a fourth that can be implemented with a few hours of work. Still to come is the final
References
Airey, J.M. and M. Ouh-Young [1989]. Two Adaptive Techniques Let Progressive Radiosity Outperform
the Traditional Radiosity Algorithm, Dept. of Computer Science Technical Report TR89-020, U. of North
Carolina.
Arvo, J., Ed. [1991]. Graphic Gems II, Academic Press, San Diego, CA.
Arvo, J. and D. Kirk [1989]. “A Survey of Ray Tracing Acceleration Techniques”, in Glassner [1989], 201
- 262.
Ashdown, I. [1988]. "Dynamic Multidimensional Arrays in C", Computer Language 5:6 (June), 83 - 88.
Ashdown, I. [1993]. “Modeling Complex 3-D Light Sources”, ACM SIGGRAPH ‘93 Course 22 (Making
Badouel, D. [1990]. “An Efficient Ray-Polygon Intersection”, in Glassner [1990], 390 - 393, 735.
Baum, D.R., H.E. Rushmeier and J.M. Winget [1989]. “Improving Radiosity Solutions Through the Use of
Analytically Determined Form Factors”, Computer Graphics 23:3, (Proc. ACM SIGGRAPH ‘89), 325 -
334.
Beran-Koehn, J.C. and M.J. Pavicic [1991]. “A Cubic Tetrahedral Adaptation of the Hemi-Cube
Beran-Koehn, J.C. and M.J. Pavicic [1992]. “Delta Form Factor Calculation for the Cubic Tetrahedral
Bian, B. [1992]. “Hemispherical Projection of a Triangle”, in Kirk [1992], 314 - 317, 569 - 574.
Bian, B., N. Wittels and D.S. Fussell [1992]. “Non-Uniform Patch Luminance for Global Illumination”,
Bouatouch, K. and C. Bouville, Eds. [1992]. Photorealism in Computer Graphics, Springer-Verlag, Berlin.
Form Factor Determination 377
________________________________________________________________________
Bu, J. and E.F. Deprettere [1987a]. “A VLSI System Architecture for High-Speed Radiative Transfer 3D
Image Synthesis”, Eurographics ‘87 (Proc. European Computer Graphics Conference and Exhibition), G.
Marechal, Ed., Elsevier Science Publishers B.V. (North-Holland), Amsterdam, 221 - 235.
Bu, J. and E.F. Deprettere [1987b]. “A VLSI Algorithm for Computing Form-Factors in Radiative Transfer
Computer Image Synthesis”, Computer Graphics 1987 (Proc. CG International ‘87), T.L. Kunii, Ed.,
Bu, J. and E.F. Deprettere [1989]. “A VLSI System Architecture for High-speed Radiative Transfer 3D
Cherry, V.H., D.D. Davis and M.K. Boelter [1939]. “A Mechanical Integrator for the Determination of the
Illumination from Diffuse Surface Sources”, Trans. Illuminating Engineering Society 34:11, 1085 - 1094.
Cohen, M.F. and D.P. Greenberg [1985]. “The Hemi-Cube: A Radiosity Solution for Complex
Cohen, M.F., D.P. Greenberg, D.S. Immel and P.J. Brock [1986]. “An Efficient Radiosity Approach for
Realistic Image Synthesis”, IEEE Computer Graphics and Applications 6:3, 26 - 35.
Cohen, M.F., C. Puech and F. Sillion, Eds. [1993]. Proc. Fourth Eurographics Workshop on Rendering,
Cohen, M.F. and J.R. Wallace [1993]. Radiosity and Realistic Image Synthesis, Academic Press, San
Diego, CA.
Emery, A.F., O. Johansson, M. Lobo and A. Abrous [1991]. “A Comparative Study of Methods for
Computing the Diffuse Radiation Viewfactors for Complex Structures”, J. Heat Transfer 113, 413 - 422.
Glassner, A.S., Ed. [1989]. An Introduction to Ray Tracing, Academic Press, San Diego, CA.
Glassner, A.S., Ed. [1990]. Graphic Gems, Academic Press, San Diego, CA.
Goral, C.M., K.E. Torrance, D.P. Greenberg and B. Battaile [1984]. “Modelling the Interaction of Light
Between Diffuse Surfaces”, Computer Graphics 18:3 (Proc. ACM SIGGRAPH ‘84), 212 - 222.
Haines, E. [1991]. “Fast Ray-Convex Polyhedron Intersection”, in Arvo [1991], 247 - 250.
Haines, E. and D.P. Greenberg [1986]. “The Light Buffer: A Ray Tracer Shadow Testing Accelerator”,
Haines, E. and J. Wallace [1991]. “Shaft Culling for Efficient Ray-Traced Radiosity”, Proc. Second
Hall, R. [1989]. Illumination and Color in Computer Generated Imagery, Springer-Verlag, New York,
NY.
Howell, J.R. [1982]. A Catalog of Radiation Configuration Factors, McGraw-Hill, New York, NY.
IESNA [1993]. IESNA Lighting Handbook, Eighth Edition, Illuminating Engineering Society of North
Kirk, D., Ed. [1992]. Graphic Gems III, Academic Press, San Diego, CA.
Kokcsis, F. and J.F. Böhme [1992]. “Fast Algorithms and Parallel Structures for Form Factor Evaluation”,
Lambert, J.H. [1760]. Photometria sive de mensura et gradibus luminus, colorum et umbrae. German
translation with annotations by E. Anding [1892], Ostwald’s Klassiker der Exakten Wissenschaften Nos.
31 - 33, Leipzig.
Malley, T.J. [1988]. A Shading Method for Computer Generated Images, Master’s Thesis, Dept. of
Marks, J., R. Walsh, J. Christensen and M. Freidell [1990]. “Image and Intervisibility Coherence in
Max, N. [1992]. Optimal Sampling for Global Illumination, Lawrence Livermore National Laboratory
UCRL-JC-112598.
Max, N. and R. Troutman [1993]. “Optimal Hemicube Sampling”, in Cohen et al. [1993], 185 - 200 and
Addendum.
Max, N.L. and M.J. Allison [1992]. “Linear Radiosity Approximation Using Vertex-To-Vertex Form
Maxwell, G.M. M.J. Bailey and V.W. Goldschmidt [1986]. “Calculations of the Radiation Configuration
Meyer, G.W., H.E. Rushmeier, M.F. Cohen, D.P. Greenberg and K.E. Torrance [1986]. “An Experimental
Evaluation of Computer Graphics Imagery”, ACM Trans. Computer Graphics 5:1, 30 - 50.
Form Factor Determination 379
________________________________________________________________________
Murdoch, J.B. [1981]. “Inverse Square Law Approximation of Illuminance”, J. Illuminating Engineering
Ng, A. and M. Slater [1993]. “A Multiprocessor Implementation of Radiosity”, Computer Graphics Forum
Taking Account of Shadows and Interreflections”, Computer Graphics 20:4 (Proc. ACM SIGGRAPH
Nusselt, W. [1928]. “Grapische Bestimmung des Winkelverhältnisses bei der Wärmestrahlung”, Zeitschrift
O’Brien, P.F. [1963]. “Pleijel’s Globoscope for Lighting Design”, Illuminating Engineering 58:3, 131 -
138.
Pietrek, G. [1993]. “Fast Calculation of Accurate Formfactors”, in Cohen et al. [1993], 201 - 220.
Pueyo, X. [1991]. “Diffuse Interreflections. Techniques for Form Factor Computation: A Survey”, The
Recker, R.J., D.W. George and D.P. Greenberg [1990]. “Acceleration Techniques for Progressive
Refinement Radiosity”, Computer Graphics 24:2 (1990 Symposium on Interactive 3D Graphics), 59 - 66.
Rogers, D.F. [1985]. Procedural Elements for Computer Graphics, McGraw-Hill, New York, NY.
Rushmeier, H., D.R. Baum and D.E. Hall [1991]. “Accelerating the Hemi-Cube Algorithm for Calculating
Saraiji, R.M.N. and R.G. Mistrick [1992]. “Calculation Methods, Error Tendencies, and Guidelines for
Sbert, M. [1993]. “An Integral Geometry Based Method for Fast Form-Factor Computation”, Computer
Schröder, P. and P. Hanrahan [1993]. “On the Form Factor Between Two Polygons”, Computer Graphics
Shirley, P. [1991]. “Radiosity Via Ray Tracing”, in Arvo [191], 306 - 310.
380 Form Factor Determination
________________________________________________________________________
Siegel, R. and J.R. Howell [1992]. Thermal Radiation Heat Transfer, Third Edition, Hemisphere
Sillion, F. and C. Puech [1989]. “A General Two-Pass Method Integrating Specular and Diffuse
Reflection”, Computer Graphics 23:3 (Proc. ACM SIGGRAPH ‘89), 335 - 344.
Sparrow, E. [1963]. “A New and Simpler Formulation for Radiative Angle Factors”, J. Heat Transfer 85:2,
81 - 88.
Sparrow, E. and R. Cess [1978]. Radiation Heat Transfer, Hemisphere Publishing Corporation,
Washington, DC.
Spencer, S.N. [1992]. “The Hemisphere Radiosity Method: A Tale of Two Algorithms”, in Bouatouch and
Sun, J., L.Q. Zou and R.L. Grimsdale [1993]. “The Determination of Form-Factors by Lookup Table”,
Sung, K. and P. Shirley [1992]. “Ray Tracing with the BSP Tree”, in Kirk [1992], 271 - 274, 538 - 546.
Sutherland, I.E. and G.W. Hodgman [1974]. “Reentrant Polygon Clipping”, Comm. ACM 17:1, 32 - 42.
Sutherland, I.E., R.F. Sproull and R. Schumacker [1974]. “A Characterization of Ten Hidden-Surface
Tampieri, F. [1992]. “Accurate Form Factor Calculation”, in Kirk [1992], 329 - 333.
Tellier, P., E. Maisel, K. Bouatouch and E. Languénou [1993]. “Exploiting Spatial Coherence to
Verbeck, C.P. and D.P. Greenberg [1984]. “A Comprehensive Light-Source Description for Computer
Vilaplana, J. and X. Pueyo [1992]. “Exploiting Coherence for Clipping and View Transformations in
Voorhies, D. and D. Kirk [1991]. “Ray-Triangle Intersection Using Binary Recursive Subdivision”, in
Wallace, J.R., K.A. Elmquist and E.A. Haines [1989]. “A Ray Tracing Algorithm for Progressive
Radiosity”, Computer Graphics 23:3 (Proc. ACM SIGGRAPH ‘89), 315 - 324.
Form Factor Determination 381
________________________________________________________________________
Wang, M., H. Bao and Q. Peng [1992]. “A New Progressive Radiosity Algorithm Through the Use of
Wang, Y. and W.A. Davis [1990]. “Octant Priority for Radiosity Image Rendering”, Proc. Graphics
Warn, D.R. [1983]. “Lighting Controls for Synthetic Images”, Computer Graphics 17:3 (Proc. ACM
Zhang, N. [1991]. “Two Methods for Speeding Up Form-Factor Calculations”, Proc. Second Eurographics
Zhou, Y. and Q. Peng [1992]. “The Super-Plane Buffer: An Efficient Form-Factor Evaluation Algorithm
We have one last major … and surprisingly easy … task before us: solving the radiosity equation. Once
we have the tools to accomplish this, we will finally be able to render photorealistic images of our
environments.
This is the central component of the radiosity approach. Having suffered through photometric and
radiometric theory, radiosity theory, 3-D projective transformations, polygon clipping in four dimensions,
polygon scan conversion and form factor determination mathematics as a prelude, you might expect this to
be the most difficult chapter in the book. If so, you will be pleased to learn that it is exactly the opposite.
Again and again: do not let the mathematics deter you! The following two sections are dense reading,
but none of the equations require more than a basic understanding of matrix theory and high school
algebra. Moreover, you can ignore the details if you so choose. The equations are necessary only to lay a
We saw in Chapter Two that the radiosity equation is a system of n linear equations of the form:
where n is the number of elements in the environment. We know the initial exitance vector; its entries M oi
will be mostly zeroes. The only non-zero entries are for those elements representing light sources. We also
know the reflectivity ρi of each element, and we can estimate the form factor Fij between any two
elements i and j. All we have to do to obtain the final exitances M i is to solve these equations.
Most environments result in linear systems that are far too large to solve using direct methods such as
Gaussian elimination. The classic alternative is to use iterative techniques such as the Gauss-Seidel
method. This was the original approach taken by Goral et al. [1984], Cohen and Greenberg [1985] and
Cohen et al. [1986]. Baum et al. [1989] referred to it as the full radiosity algorithm.
We also saw in Chapter Two, however, that this gives us a radiosity algorithm with O(n 2 ) time and
space complexity. A large and complicated environment with 50,000 elements can easily consume one to
ten gigabytes of memory for its form factors and take days of CPU time to compute a single image. We
What we really want is an algorithm that consumes a minimal amount of memory and that generates a
reasonable approximation of the final image almost immediately. More generally, we need to maintain a
careful balance between the requirement for photorealistic images and the demands of interactive
computing. Waiting a day or more to see whether we chose the right balance of light sources for an image
In a perfect world, our algorithm would generate a reasonable first approximation and then
progressively and gracefully refine the image until it reaches its final form. This essentially describes how
iterative techniques work, except that we need a much more effective algorithm than the Gauss-Seidel
method.
Solving the Radiosity Equation 385
________________________________________________________________________
The great surprise is that such an algorithm actually exists. Before examining it, however, we should
Expanding on Equation 2.25, we can express Equation 6.1 more succinctly in matrix notation as:
M o = (I − T)M (6.2)
ρ1 0 0 F11
L F12 L F1n
0 ρ 2 L 0 F2 n F22 L L
= = RF
L L L L L L L L
0 0 L ρ n Fn1 Fn 2 L Fnn
where R is the (diagonal) reflectance matrix and F is the form factor matrix.
form:
M o = KM (6.4)
A quick review of iterative techniques for solving linear systems may be in order. Suppose we are
b = Ax
where x is the unknown n × 1 vector, A is a square n × n matrix and b is a known n × 1 vector. Most
iterative techniques convert this system into an equivalent system with the form:
x = Qx + c
where the n × n matrix Q and the n × 1 vector c are derived from A and b. The details of the derivation
To solve for x, we start with an initial n × 1 vector x (0 ) that hopefully approximates the final solution.
At worst, it can have entirely random values for its elements. With it, we can generate a sequence of
x (k ) = Qx (k −1) + c, k = 1, K
This is the iterative component of the technique. The sequence of vectors x (k ) will be such that the
elements of the vector either converge to those of the unknown vector x, or else diverge into some random
vector, as k increases.
While it is unlikely that x (k ) will exactly equal x for any finite value of k, the error between them will
tend to grow progressively smaller as k increases (and if the sequence converges). This means that we can
stop when:
for some “threshold” value. At this point, the approximate solution vector x (k ) is such that the fractional
error between it and the unknown vector x is guaranteed to be equal to or less than this value for each of its
elements. The iterative method is then said to have converged to an acceptable solution.
Of critical importance to the user is the convergence rate. That is, what value of k is needed in order to
attain an acceptable solution? This is determined by the characteristics of the chosen iterative method, the
There are two issues of concern here. First, there are linear systems where the solution vector diverges
rather than converges to a solution. Fortunately, the radiosity equation is guaranteed to converge to a
(For those familiar with advanced matrix mathematics: the sum of any row of form factors is equal to or
less than unity by virtue of the summation relation (Eqn. 2.18), and each form factor is multiplied by a
reflectance value ρ that is less than unity. Also, the main diagonal term of K in Equation 6.4 is always
Solving the Radiosity Equation 387
________________________________________________________________________
unity, since Fii = 0 for all planar or convex elements. Thus, K is strictly diagonally dominant, which
guarantees convergence for any choice of M (0 ) using either Jacobi or Gauss-Seidel iteration.)
Second, we need to consider what our choice of M (0 ) should be. The closer it is to the unknown final
exitance vector M, the more quickly our chosen iterative method will converge. Of course, the only a
priori information we have concerns the initial exitances of the elements representing light sources. In
other words, our best choice is to assign the initial exitance vector M o to M (0 ) . Interestingly enough, this
Returning to Equation 6.2, suppose we rearrange it slightly to solve for M. We then have:
M = (I − T )−1 M o (6.5)
Again, we cannot solve this equation directly, since calculating the inverse of a matrix is rarely an easy
task. However, we can approximate it with a MacLaurin power series expansion. It can be shown that:
∞
1
=∑
(1 − x ) n=0
xn = 1 + x + x 2 + x3 + K (6.6)
which converges for −1 < x < 1 . There is a similar series expansion for matrices (e.g., Golub and Van Loan
[1983]):
(I − T)−1 = I + T + T 2 + T 3 + K (6.7)
M = M o + TM o + T 2 M o + T 3 M o + K (6.8)
that converges if the spectral radius of T (i.e., the absolute value of its largest eigenvalue) is less than one.
Fortunately, this condition is true for any physically possible radiosity equation (e.g., Heckbert [1991]).
This means that we can safely ignore the somewhat abstruse mathematics behind the spectral radius and
eigenvalues of a matrix.
There is an important physical significance to Equation 6.8 (e.g., Kajiya [1986]). Each successive term
T k M represents the kth bounce of the initially emitted light. The term M o represents the initial flux (i.e.,
the direct illumination), TM o represents the first bounce component, T 2 M o the second bounce and so
388 Solving the Radiosity Equation
________________________________________________________________________
on. We can intuitively see this by observing that the element reflectances ρ are multiplied with each
successive bounce. This represents the accumulating light losses due to absorption.
In other words, the behavior of light flowing through an environment is itself an iterative method!
Moreover, the initial exitance vector M o serves as its initial “guess” to the final exitance vector M.
Comparing Equation 6.9 to iterative techniques for solving linear systems, it becomes clear why the
radiosity equation always converges to a solution when we apply these techniques. To do otherwise–that is,
for the approximate solution vector M (k ) to diverge with increasing values of k–would require the total
quantity of light in an environment to increase with each successive bounce. This would in turn contravene
There is in fact only one iterative technique that faithfully models the physical reality of light’s
behavior as expressed by Equation 6.9. It is the Jacobi iterative method, the simplest iterative technique for
solving systems of linear equations. While it may not be necessary for our development of a practical
algorithm for solving the radiosity equation, we should ask how the Jacobi method works for two reasons..
First, it will provide us with a better understanding of how and why iterative techniques work. More
importantly, however, the Jacobi method offers an fascinating and instructive insight into the physical
The Jacobi method splits (or decomposes) an n × n matrix A into a diagonal matrix D, a strictly lower
diagonal matrix −L and a strictly upper diagonal matrix −U . Written in matrix form, this becomes:
Ax = (D − L − U )x = b (6.11)
which becomes:
Dx = (L + U )x + b (6.12)
and so:
x=
(L + U ) x + b (6.13)
D D
x (k ) =
(L + U ) x (k −1) + b (6.14)
D D
xi(k ) =
j =1, j ≠i
, i = 1,K, n (6.15)
aii
In plain English, this equation states that we can solve each element x i(k ) of our approximate solution
vector x (k ) by using the values of all the other elements x (jk −1) of our previously calculated solution vector.
The Jacobi iterative method models the flow of light in an environment. We can confirm this by
deriving Equation 6.9 in terms of the Jacobi iteration. Following the development of the Jacobi method
above, we start with Equation 6.2 and decompose T into a diagonal matrix TD , a strictly lower diagonal
(I − T) = I − TD + TL + TU (6.16)
and thus:
M 0 = (I − TD + TL + TU )M (6.17)
This becomes:
(I − TD )M = −(TL + TU )M + M o (6.18)
and:
390 Solving the Radiosity Equation
________________________________________________________________________
− (TL + TU ) Mo
M= M+ (6.19)
(I − TD ) (I − TD )
This is equivalent to the Jacobi iterative method presented in Equation 6.14. However, the form factor
Fii for planar or convex patches is always zero, which means each diagonal element of T equals zero and
M = −(TL + TU )M + M o = TM + M o (6.20)
for solving the radiosity equation. This is identical to Equation 6.9. Referring to Equation 6.3, this
becomes:
n
M i(k ) = M oi + ρ i ∑ Fij M (jk −1) , i = 1, K, n (6.23)
j =1
This is the radiosity equation that we saw in Chapter Two (Eqn. 2.21), expressed as an iterative
method.
The problem with Jacobi iteration is that it is often slow to converge to a solution. The Gauss-Seidel
iterative method takes a simple but effective approach to improving this situation. We saw in Equation 6.15
that the Jacobi method calculates the value of each element x i(k ) in sequence by using the values of the
other elements from x (k −1) . Since the elements x (jk ) (where j < i ) have already been calculated and are
presumably closer approximations to the final solution vector elements than their x (jk −1) counterparts, why
This is exactly what the Gauss-Seidel method does. Its iterative equation is:
U b
x (k ) = x (k −1) + , k >0 (6.24)
(D − L ) (D − L )
Solving the Radiosity Equation 391
________________________________________________________________________
or, expressed in its more familiar form:
i −1 n
∑ − aij x (jk ) + ∑ − aij x (jk −1) + bi
xi(k ) =
j =1 j =i
, i = 1,K , n (6.25)
aii
A derivation of Equation 6.24 can be found in most elementary linear algebra and numerical analysis texts
The Jacobi method can be seen in terms of modeling light bouncing from surface to surface in an
environment. This is not the case for the Gauss-Seidel method. In a sense, it tries to anticipate the light
each surface will receive from the next iteration of reflections. There is no physical analogue to this
process, but it does work in that the Gauss-Seidel method usually converges more quickly than the Jacobi
method does. Cohen and Greenberg [1985] found that the Gauss-Seidel method solved the radiosity
When it was first presented by Goral et al. [1984] and Nishita and Nakamae [1985], radiosity rendering
was for the most part viewed as an interesting mathematical curiosity. The Jacobi and Gauss-Seidel
methods have a time complexity of O(n 2 ) for each iteration. That is, doubling the number of elements in
an environment quadruples the CPU time required to solve its particular radiosity equation. Given the
available computer technology at the time, this made the full radiosity algorithm an impractical rendering
Another disadvantage of full radiosity is that it requires storage for n 2 2 form factors. This means that
the memory space complexity of the full radiosity algorithm is O(n 2 ) as well. We could possibly avoid
this requirement by recomputing form factors “on the fly” for each element during each iteration. However,
the high cost of form factor determination means that we would have to wait much longer between each
iteration. This is exactly what we are trying to avoid. We need to obtain an initial image as quickly as
possible.
392 Solving the Radiosity Equation
________________________________________________________________________
We can gain some relief by substructuring the environment into patches and elements (Cohen et al.
[1986]). This brings both the time and space complexities down to O(nm ) for n patches and m elements.
There is an interesting and instructive physical interpretation of the Jacobi and Gauss-Seidel methods.
We can think of each execution of Equation 6.15 (Jacobi) or 6.25 (Gauss-Seidel) as being one step; it takes
n steps to complete one iteration of the method. At each step, we are updating the estimated exitance of
one element by processing one row of the radiosity equation. For the Jacobi method, this is Equation 6.23,
n
M i(k ) = M oi + ρ i ∑ Fij M (jk −1) , i = 1, K, n (6.26)
j =1
. . . . . . x
x x x x x x x
= + (6.27)
. . . . . . x
. . . . . . x
The physical interpretation of this process is straightforward: we are simply summing the contribution of
flux from all the other elements in the environment to the exitance of the current element. Looking at
Figure 6.2 and referring to Equation 6.26, each element E j has an exitance M j and an area A j .
Referring to Equation 6.26, the portion of the flux Φ j emitted by E j that is received by Ei is:
Φ ij = M j A j F ji (6.28)
The amount of exitance ∆M i of Ei that is due to this flux subsequently being reflected by Ei is thus:
∆M i = ρ i Φ ji Ai = ρ i M j A j F ji Ai (6.29)
However, we can apply the reciprocity relation Ai Fij = A j F ji (Section 2.5.1) to obtain:
∆M i = ρ i M j Fij (6.30)
More colloquially, this can be seen as the current element Ei gathering exitance from all of the
elements E j in the environment in order to determine its exitance due to these elements. The term M oi in
Solving the Radiosity Equation 393
________________________________________________________________________
Equation 6.26 simply accounts for any initial exitance of Ei . This will be non-zero only if Ei is a light
source.
It may be somewhat difficult to visualize exitance being transferred between elements. It becomes
∆Φ i = ∆M i Ai = ρ i M j Fij Ai (6.31)
∆Φ i = ρ i M j F ji A j = ρ i F ji Φ j (6.32)
which shows that we are in fact gathering and subsequently reflecting radiant flux. Equation 6.30 is more
useful in terms of Equation 6.26, however, and so we “gather” exitance to Ei . The difference is solely
semantic.
A number of authors have loosely referred to this process as gathering “energy”. However, the physical
quantity being discussed is radiant exitance (i.e., watts per unit area) times area. This is power, or radiant
flux. Energy is “gathered” only in the sense that solving the radiosity equation balances the flow of energy
Ej
Ei
The problem with this approach is that it can be excruciatingly slow. Consider a complex environment
with perhaps 50,000 elements. Using the Jacobi or Gauss-Seidel method, we must perform one complete
iteration before we have an image of the first bounce of light from the environment. That means we must
execute Equation 6.26 50,000 times! This clearly does not satisfy our requirement for an “immediate but
approximate” image.
This is where the physical interpretation becomes useful. If we think for a moment about how light
flows in an environment, it becomes evident that we should be interested in those elements that emit or
394 Solving the Radiosity Equation
________________________________________________________________________
reflect the most light. It logically does not matter in what order we consider the distribution of light from
This leads to an entirely different paradigm. Given an environment with one or more light sources, we
can think of them shooting flux to the other elements (Fig. 6.3). These elements then become in effect
secondary light sources, shooting some of the flux they receive back into the environment. By always
selecting the element that has the greatest amount of flux to “shoot”, we will drastically improve our
convergence rate. Again, it makes intuitive sense that the more quickly the light is absorbed, the more
Ej
Ei
It also becomes evident that this idea answers our need for both an immediate image and progressive
convergence to the final solution. By shooting flux from one element to all other elements in the
environment, we immediately obtain an initial estimate for all element exitances. This occurs in one step
rather than a complete iteration. In fact, the concept of an iteration no longer applies, for we may end up
choosing one element several times before we cycle through the entire set. It all depends on which element
Of course, we also obtain improved estimates for all the element exitances at each step. This means that
the rendered image will continuously and gracefully converge to the final photorealistic image.
Now, all we have to do is to express this idea in the form of a practical algorithm.
What we are looking for is the progressive refinement radiosity algorithm (Cohen et al. [1988]). Based
on the concept of shooting flux, it offers not only an immediate image with continuous and graceful
convergence, but also O(n ) time and space complexity. Given an environment with n elements, it requires
Solving the Radiosity Equation 395
________________________________________________________________________
memory space for only n form factors. Even better, it can generate an initial image almost immediately, and
can generate if necessary updated images after each step (as opposed to each iteration).
So how does it work? To shoot flux or exitance back into the environment, we simply reverse the
Ai
∆M j = ρ j M i Fij = ρ j M i F ji (6.33)
Aj
Multiplying both sides of this equation by the area of element E j gives us the equation for shooting flux.
Unlike the full radiosity algorithm (i.e., Equation 6.26), this equation acts on one column of the
x x . . x . .
x x x . x . .
= + for all elements E j (6.34)
x x . . x . .
x x . . x . .
This means we can now display an image of the environment whenever one column of the radiosity
equation has been processed. This has a time complexity of O(n) as opposed to O(n 2 ) for the basic
radiosity algorithm.
The progressive refinement radiosity algorithm proceeds as follows. First, we assign an “unsent
exitance” value ∆M iunsent to each element in the environment. This is in addition to its final exitance M i ,
which we are trying to determine. The amount of flux each element has to shoot is ∆M iunsent times its area,
Ai . Initially, only the elements representing light sources will have non-zero values of flux, and so
Choosing the element Ei with the greatest amount of flux (not exitance) to shoot, we execute Equation
6.33 for every other element E j in the environment. Each of these elements “receives” a delta exitance
After the flux has been shot to every element E j , ∆M iunsent is reset to zero. This element can only
shoot again after receiving more flux from other elements during subsequent steps.
396 Solving the Radiosity Equation
________________________________________________________________________
This process continues until the total amount of flux remaining in the environment is less than some
n
∑ ∆M iunsent Ai ≤ ε (6.35)
i =1
Progressive refinement radiosity does not–repeat, does not– require any less time to completely solve
the radiosity equation to some vanishingly small margin of error. It is an iterative approach that, like full
radiosity, progressively refines the element exitances as it converges to a solution. However, its
overwhelming advantage is that usable images can be displayed almost immediately, and that each
We still have the form factors to contend with. However, we only need to calculate the n form factors
Fij from the current element E i to all other elements E j between displaying images. This is exactly what
our hemi-cubes and cubic tetrahedrons provide when centered over a given element. Yes, we have to
recompute these form factors on the fly for each step of the progressive radiosity algorithm. However, the
convergence rate is much faster than it is for full radiosity. Cohen et al. [1988] compared progressive
refinement and full radiosity algorithms using an environment consisting of 500 patches and 7,000
Solving the Radiosity Equation 397
________________________________________________________________________
elements. The progressive radiosity implementation converged to a visually acceptable image after
approximately 100 steps. At this point, the full radiosity implementation was only 20 percent of its way
Incidentally, Gortler and Cohen [1993a] established that the progressive refinement radiosity algorithm
is a variant of the Southwell iteration method (e.g., Gastinel [1970]). Like the Jacobi and Gauss-Seidel
methods, Southwell iteration will always converge to a solution for any radiosity equation.
The progressive refinement radiosity algorithm described above has one minor problem. When the flux
is first shot from the light sources, only those elements visible to them are illuminated. The rest of the
environment will be in shadow. This will quickly change as the flux bounces from surface to surface
during subsequent steps. Nevertheless, it may be somewhat disconcerting to have the first few images
appear relatively dark as the light sources are shot one by one.
Cohen et al. [1988] resolved this problem by introducing an ambient term that simulates the effect of a
completely diffuse light source evenly illuminating every surface of the environment. The contribution of
this term to the exitance of each element is gradually diminished as the radiosity algorithm converges to its
final solution, thereby maintaining a reasonably constant average exitance for the environment. This term
is added for display purposes only; it does not participate in solving the radiosity equation. With the term
added, the visual differences between successive images can become almost unnoticeable.
To calculate the ambient exitance, we first need to define the average reflectance of the environment.
This is the area-weighted average of the individual element reflectances, given as:
n n
ρ avg = ∑ ρ i Ai ∑ Ai (6.36)
i =1 i =1
If we think of the environment as being an empty room with no obstructions and whose surfaces have a
reflectance of ρ avg , then we can see that the light will bounce back and forth within this room until it is
completely absorbed. From this, we can derive the following interreflection factor:
398 Solving the Radiosity Equation
________________________________________________________________________
2 3 1
R = 1 + ρ avg + ρ avg + ρ avg +K = (6.37)
1 − ρ avg
We also need to estimate the area-weighted average amount of unsent exitance. This is simply:
n n
unsent
M avg = ∑ M iunsent Ai ∑ Ai (6.38)
i =1 i =1
Of course, this will decrease whenever flux is shot from an element into the environment. This ensures that
the ambient term decreases to zero as the radiosity algorithm converges to a solution.
unsent
M ambient = RM avg (6.39)
M i′ = M i + ρ i M ambient (6.40)
Cohen et al. [1988] demonstrated that the ambient term improves the initial convergence rate as well as
the visual appearance of the image. Using the area-averaged error metric:
∑ (M i(∞ ) − M i(k ) )
n n
2
errorrms = Ai ∑ Ai (6.41)
i =1 i =1
where M i(∞ ) is the converged (i.e., final) exitance of each element E i after an infinite number of steps and
k is the number of steps actually performed, they found that adding the ambient term decreases the error
from 40 to 30 percent after 15 steps for a typical environment of 500 patches and 7,000 elements. After 70
steps, the ambient term became negligible, leaving the progressive refinement radiosity algorithm to
converge to a solution on its own after some 100 steps. At the same time, the error for the full radiosity
algorithm using the Gauss-Seidel method after 100 steps was approximately 98 percent.
We can combine the ambient exitance with our previous progressive refinement radiosity algorithm. At
the same time, we can take advantage of the hierarchical arrangement of patches and elements in our
Shao and Badler [1993b] presented a detailed and informative discussion of the convergence behavior
of the progressive refinement radiosity algorithm. They observed that while the algorithm may quickly
converge to a visually appealing image, many more steps are often required to capture the nuances of color
bleeding and soft shadows. They demonstrated that it took 2,000 or more steps to achieve full convergence
in a complex environment of some 1,000 patches and 25,000 elements. Many of the radiosity-based
renderings published to date were completed using far fewer steps, implying that their apparent realism
Much of the problem lies in how progressive refinement works. By always selecting the patch with the
most flux to shoot, it concentrates first on the light sources. Most of their flux will be shot to what Shao
and Badler [1993b] called global patches–those patches which are relatively large and can be seen from
much of the environment. For an architectural interior, these are typically the walls, floor and ceiling of a
400 Solving the Radiosity Equation
________________________________________________________________________
room. Their elements receive most of the flux from the light sources and consequently shoot it to the other
The local patches are those patches which are small, possibly reflective in only one color band, and are
usually hidden from much of the environment. Their flux will not be shot until that of the global patches
has been exhausted. This is undesirable for two reasons. First, their small areas means that they will receive
relatively little flux in comparison to the global patches. It may take several hundred steps before they
The second reason is that when these local patches do shoot, much of their flux often goes no further
than their immediate neighbors. While this does not affect the global environment to any great extent (and
so does not appear in the error metric defined in Equation 6.41), it does account for the color bleeding and
soft shadow effects we are trying to achieve. In this sense, a better error metric is the worst-case difference
between the estimated and converged element exitances. In their experiments, Shao and Badler [1993b]
observed that it took twice as many iterations as there were patches (not elements) in the environment.
One strategy to overcome this problem involves de-emphasizing the contributions due to the global
patches, ensuring that all patches shoot their flux in a reasonable number of steps. This requires a
Convergence of the Gauss-Seidel algorithm can often be accelerated by using one of several techniques
known as successive overrelaxation (e.g., Noble [1969]). Applied to the radiosity equation, these
techniques can be interpreted as “overshooting” the amount of flux from a patch into the environment. That
is, the amount of flux shot from the patch is more than the amount of unsent flux the patch actually has.
The flux shot in subsequent steps by the receiving patches will tend to cancel this overshooting. In the
meantime, the total amount of unsent flux in the environment is shot and absorbed more quickly. This
Shao and Badler [1993b] presented a modified version of the progressive refinement radiosity
algorithm that incorporates positive overshooting to accelerate the convergence rate by a factor of two or
more. At the same time, it tends to prioritize the ordering of patches being shot such that the local patches
Solving the Radiosity Equation 401
________________________________________________________________________
are shot sooner, thereby enhancing the rendering of subtle lighting effects such color bleeding and soft
shadows.
The modification to the radiosity algorithm (Fig. 6.4), based on an earlier proposal by Feda and
…
Select element i with greatest positive unsent flux ∆M iunsent Ai
Estimate overshooting parameter ∆M iovershoot
Calculate all form factors Fik
FOR each patch j
FOR each element k
// Determine increase in exitance of element k due to patch exitance ∆M iunsent
// and area-weighted positive overshoot
(
∆M = ρ k Fik ∆M iunsent + ∆M iovershoot )
Ai
Ak
M k = M k + ∆M
// Add area-weighted increase in element k exitance to parent patch j
A
∆M unsent
j = ∆M unsent
j + ∆M k
Aj
ENDFOR
ENDFOR
∆M iunsent = −∆M iovershoot
…
Figure 6.6 - Progressive refinement radiosity algorithm with positive overshooting
As with ambient exitance, the amount of positive overshooting and its contribution to the shooting
patch’s unsent exitance must be determined independently for each color band.
Feda and Purgathofer [1992] based their calculation of the overshooting parameter ∆M iovershoot on the
ambient exitance of the environment. However, Shao and Badler [1993b] noted several problems with this
n
∆M iovershoot = ρ i ∑ ∆M ′junsent Fij (6.42)
j =1
where:
∆M unsent
j if ∆M unsent
j >0
∆M ′junsent = (6.43)
0 otherwise
402 Solving the Radiosity Equation
________________________________________________________________________
This essentially sums the amount of unsent flux the patch will later receive from the elements in the
environment and multiplies it by the reflectance of the patch. The patch effectively gathers the unsent flux
it would otherwise receive in later steps and shoots it along with its own unsent flux.
Equation 6.43 ensures that the patch will never receive a negative amount of flux from any element.
Thus, only positive overshooting can occur. On the other hand, the patch may shoot a negative amount of
Since we can now have both positive and negative unsent flux, we need to modify our convergence
n
∑ ∆M iunsent Ai ≤ε (6.44)
i =1
Experiments performed by Shao and Badler [1993b] on two complex environments demonstrated that
the convergence rate with positive overshooting can be accelerated by a factor of two or more over that of
conventional progressive radiosity. There was also strong evidence that the appearance of subtle color
bleeding and soft shadow effects may appear as much as three to five times more quickly. Positive
Other overrelaxation techniques for solving the radiosity equation are described by Gortler and Cohen
Having explored the mathematical techniques needed to solve the radiosity equation, we can
encapsulate these ideas in a C++ class. First, however, we need to complete our RadEqnSolve class that we
began in Chapter Four. We defined a number of several “stub” functions in RAD_TMP.CPP (Listing 4.19).
Following the above discussions on progressive refinement radiosity and ambient exitance, we can replace
them with:
#include "rad_eqn.h"
total_flux = 0.0;
num_vert = pelem->GetNumVert();
for (i = 0; i < num_vert; i++)
{
// Get element vertex pointer
pvert = pelem->GetVertexPtr(i);
irf.Reset();
sum.Reset();
total_area = 0.0;
Solving the Radiosity Equation 405
________________________________________________________________________
// Walk the instance list
pinst = penv->GetInstPtr();
while (pinst != NULL)
{
// Walk the surface list
psurf = pinst->GetSurfPtr();
while (psurf != NULL)
{
// Walk the patch list
ppatch = psurf->GetPatchPtr();
while (ppatch != NULL)
{
// Update sum of patch areas times reflectances
sr = ppatch->GetParentPtr()->GetReflectance();
sr.Scale(ppatch->GetArea());
sum.Add(sr);
ppatch = ppatch->GetNext();
}
psurf = psurf->GetNext();
}
pinst = pinst->GetNext();
}
sum.Reset();
ppatch = ppatch->GetNext();
}
psurf = psurf->GetNext();
}
pinst = pinst->GetNext();
}
These four functions do more or less what their names suggest. InitExitance initializes the patch unsent
exitances with that of their parent surfaces and resets the element and vertex exitances to zero.
UpdateUnsentStats finds the patch with the maximum unsent flux, and also calculates the convergence
value as a fraction of the total unsent flux to the total environment flux. CalcInterReflect calculates the
environment interreflection factors (one for each color band), while CalcAmbient calculates the ambient
exitance terms.
With this, we can derive a progressive refinement radiosity class from RadEqnSolve as follows:
#ifndef _PROG_RAD_H
#define _PROG_RAD_H
#include "environ.h"
#include "rad_eqn.h"
#if defined(_HEMI_CUBE)
#include "hemicube.h"
#elif defined(_CUBIC_TETRA)
Solving the Radiosity Equation 407
________________________________________________________________________
#include "cubic_t.h"
#else
#error Either _HEMI_CUBE or _CUBIC_TETRA must be defined
#endif
void AddAmbient();
void CalcOverShoot();
public:
ProgRad() : RadEqnSolve() { over_flag = TRUE; }
~ProgRad() { Close(); }
BOOL Calculate();
BOOL OverShootFlag() { return over_flag; }
BOOL GetStatus() { return ffd.GetStatus(); }
BOOL Open( Environ * );
void Close();
void DisableOverShoot() { over_flag = FALSE; }
void EnableOverShoot() { over_flag = TRUE; }
};
#endif
Listing 6.2 - PROG_RAD.H
Note that ProgRad can use either the HemiCube or CubicTetra class for form factor determination. If
you forget to define either _HEMI_CUBE or _CUBIC_TETRA at compile time, your compiler will issue an
Since ProgRad is derived from RadEqnSolve (Listing 4.18), we already have a mechanism for toggling
functionality for positive overshooting. Our HELIOS program provides the necessary user interface for
both these features through its Convergence Parameters dialog box. This allows you to experiment with
various environments to see exactly how the ambient exitance affects the image quality and how much
faster the radiosity algorithm (usually) converges with positive overshooting enabled.
#include "prog_rad.h"
return TRUE;
}
if (penv != NULL)
{
// Interpolate vertex exitances
tone.Interpolate(penv->GetInstPtr());
if (over_flag == TRUE)
{
CalcOverShoot(); // Calculate overshooting parameters
}
if (over_flag == TRUE)
{
// Add overshoot exitance
shoot.Add(overshoot);
}
if (over_flag == TRUE)
{
// Subtract overshoot exitance
pmax->GetExitance().Subtract(overshoot);
}
if (amb_flag == TRUE)
{
CalcAmbient(); // Recalculate ambient exitance
}
pelem = pelem->GetNext();
}
ppatch = ppatch->GetNext();
}
psurf = psurf->GetNext();
}
pinst = pinst->GetNext();
}
}
Most of the above is a straightforward implementation of the preceding algorithms. The only item not
discussed so far is the calculation of the reciprocal form factor in Calculate. If this value is greater than
unity, it indicates that hemi-cube (or cubic tetrahedron) aliasing has occurred. When this happens, we
should in theory subdivide the shooting patch and shoot the exitance again. Here, we take the simpler
approach of silently clipping the reciprocal form factor to unity. (See Section 7.5.2 for further details.)
With ProgRad, we have all the code we need to render photorealistic images. Before doing so,
however, we should look at how easily we can accommodate vertex-to-source form factors within the
Recalling Section 5.23, ray casting allows us to determine the form factor from an element vertex v to a
source patch i. Repeating Equation 5.46 here (with a change of subscripts to avoid confusion), we have:
Ai n
cos θ vt cos θ it
Fvi =
n
∑ HIDt πrt 2 + Ai n
(6.45)
t =1
We want to shoot exitance from each vertex to the source patch. Repeating Equation 6.33 with another
With this, our progressive refinement radiosity algorithm (Figure 6.4) becomes:
Note that we no longer have to calculate and store the form factors for each selected shooting element.
This makes the ray casting radiosity algorithm more efficient with respect to memory usage. On the other
hand, Equation 6.42 requires the shooting patch-to-receiving element form factors before the exitance is
shot into the environment. This means that we can no longer calculate the amount of positive overshooting
We can, however, take advantage of our patch-element hierarchy and ambient exitance enhancements.
Once again using RadEqnSolve as the base class, we can derive the following:
#ifndef _RAY_RAD_H
#define _RAY_RAD_H
#include "environ.h"
#include "rad_eqn.h"
#include "ray_cast.h"
void AddAmbient();
public:
RayRad() : RadEqnSolve() { }
~RayRad() { }
BOOL Calculate();
BOOL Open( Environ * );
void Close() { tone.Normalize(penv->GetInstPtr()); }
};
#endif
Listing 6.4 - RAY_RAD.H
and:
#include "ray_rad.h"
num_vert = pelem->GetNumVert();
for (i = 0; i < num_vert; i++)
{
// Get element vertex pointer
pvert = pelem->GetVertexPtr(i);
if (amb_flag == TRUE)
{
418 Solving the Radiosity Equation
________________________________________________________________________
CalcAmbient(); // Recalculate ambient exitance
}
num_vert = pelem->GetNumVert();
for (i = 0; i < num_vert; i++)
{
// Get element vertex pointer
pvert = pelem->GetVertexPtr(i);
As you can see, the differences between RayRad and ProgRad are minimal. Apart from their form
factor determination requirements, the two Calculate functions differ only in their innermost loops. The
same holds true for UpdateUnsentStats and AddAmbient. For the effort of developing a few dozen
additional lines of code, we now have two radiosity algorithms to play with. Each has its advantages and
C’est fini! After nearly 7,000 lines of source code and fifty C++ classes, we are done. All we need to do
now is to compile and link a new version of HELIOS. With it, we can then render photorealistic images of
an environment.
HELIOS is designed for Microsoft Windows 3.1 and Windows NT (see Chapter Four). If you are
developing for another target environment, you will need to port the user interface portion of HELIOS to
The first step is build a make file or a project file from within an integrated development environment
(IDE). This leads to a minor complication: we must choose between one of three versions of HELIOS to
compile and link. There is a different list of source code files and conditional compilation directives
required, depending on whether we want to use the progressive refinement or ray casting radiosity
algorithms. If we choose the former, we then have to decide between hemi-cubes and cubic tetrahedrons.
Then again, there should be no choice. Having expended the effort in developing the code, we may as
well compile, link and experiment with all three versions. To avoid the otherwise inevitable confusion and
frustration, it is probably best to set up make or IDE project files in three separate subdirectories. There is
nothing more exasperating than debugging what appears to be a successfully compiled and linked program,
Note that for 16-bit Windows 3.1, the memory model must be specified as LARGE. As was explained
in Section 3.13, the WinText class assumes that its functions use _far pointers.
Also, the compilation directive _HEMI_CUBE must be globally defined. This can be usually done from
a make file or through the compiler preprocessor options. Furthermore, it must be separately defined for
Once you successfully compile and link this version, you can run it and display the About dialog box.
The version number should read “1.00A/HC”, where “HC” stands for “Hemi-Cube".
separately defined for the C++ compiler and the resource script compiler. Once you successfully compile
and link this version, its version number should read “1.00A/CT”, where “CT” stands for “Cubic
Tetrahedron".
The cubic tetrahedron and hemi-cube versions are, apart from the form factor determination methods
used, identical. There are also few if any discernable differences between the images they produce. If
anything, the cubic tetrahedron might offer a slight advantage in alleviating aliasing problems for
environments with primarily parallel and perpendicular surfaces. There may also be slight differences in
Given these minimal differences, you might ask “why bother?” The answer is that neither HemiCube or
CubicTetra have been optimized. Section 5.19.1 offers several suggestions for improving the performance
of both algorithms, and the references cited in Chapter Five offer a variety of acceleration techniques.
Since form factor determination consumes most of the CPU time needed to generate a radiosity rendering,
these two classes and their associated classes (HemiClip and so on) should be prime candidates for
optimization efforts. Having two separate algorithms to work with can only improve the chances for
success.
On the other hand, we also have our ray casting approach to consider:
for the C++ compiler and the resource script compiler. The program’s version number should read
With three successfully compiled and linked versions of HELIOS in hand, all we need now is an
environment to view … and therein lies a problem. Describing a complex environment requires many lines
In a few years’ time, books like this will likely be published on CD-ROM. It would be wonderful to
have megabytes of space available to include a collection of complex and interesting environments to play
with. Until then, we have the printed page and the diskette accompanying this book.
The diskette includes several moderately complex environments that demonstrate the capabilities of
HELIOS. The best that can be done in print is to present a very simple environment–a bench and two
suspended lights in an otherwise empty room. While this may seem rather mundane, the color plates
ENTITY bench
VERTEX
< 0.0 0.0 2.5 >
< 2.5 0.0 2.5 >
< 2.5 2.5 2.5 >
< 0.0 2.5 2.5 >
< 5.0 0.0 2.5 >
< 5.0 2.5 2.5 >
< 5.0 0.0 0.0 >
< 5.0 2.5 0.0 >
< 5.0 2.5 2.5 >
< 5.0 0.0 2.5 >
< 0.0 0.0 0.0 >
< 0.0 0.0 2.5 >
< 0.0 2.5 2.5 >
< 0.0 2.5 0.0 >
< 4.8 0.0 0.0 >
< 4.8 0.0 2.3 >
< 4.8 2.5 2.3 >
< 4.8 2.5 0.0 >
< 0.2 0.0 0.0 >
< 0.2 2.5 0.0 >
< 0.2 2.5 2.3 >
< 0.2 0.0 2.3 >
< 5.0 0.0 0.0 >
< 5.0 2.5 0.0 >
< 5.0 2.5 2.5 >
Solving the Radiosity Equation 423
________________________________________________________________________
< 5.0 0.0 2.5 >
< 0.0 0.0 0.0 >
< 0.0 2.5 0.0 >
< 0.0 2.5 2.5 >
< 0.0 0.0 2.5 >
END_VERT
SURFACE
[ 0.5 0.2 0.7 ] [ 0.0 0.0 0.0 ]
[ 0.0 0.8 0.3 ] [ 0.0 0.0 0.0 ]
[ 0.0 0.8 0.3 ] [ 0.0 0.0 0.0 ]
[ 0.0 0.3 0.0 ] [ 0.0 0.0 0.0 ]
END_SURF
PATCH
0 { 0 4 5 3 }
1 { 6 7 8 9 }
2 { 10 11 12 13 }
3 { 14 15 16 17 }
3 { 18 19 20 21 }
3 { 21 20 16 15 }
3 { 17 16 24 23 }
3 { 16 20 28 24 }
3 { 19 27 28 20 }
3 { 14 17 23 22 }
3 { 10 27 19 18 }
3 { 14 22 25 15 }
3 { 21 15 25 29 }
3 { 26 18 21 29 }
END_PATCH
ELEMENT
0 { 0 1 2 2 }
0 { 0 2 3 3 }
0 { 4 2 1 1 }
0 { 4 5 2 2 }
1 { 6 7 8 8 }
1 { 6 8 9 9 }
2 { 10 11 12 12 }
2 { 10 12 13 13 }
3 { 14 15 16 17 }
4 { 18 19 20 21 }
5 { 21 20 16 15 }
6 { 17 16 24 23 }
7 { 16 20 28 24 }
8 { 19 27 28 20 }
9 { 14 17 23 22 }
10 { 26 27 19 18 }
11 { 14 22 25 15 }
12 { 21 15 25 29 }
13 { 26 18 21 29 }
END_ELEM
END_ENTITY
Listing 6.6 - BENCH.ENT
The color scheme is a bit garish–a mauve top, sea green sides and dark green edges. If you prefer
something more contemporary, you can always change the surface reflectance values in the SURFACE
section.
424 Solving the Radiosity Equation
________________________________________________________________________
The top surface is divided into two square patches, and each patch is divided into two equal triangles
(Fig. 6.13). A finer mesh of patches and elements would allow us to display more shading details in the
rendered image. (Adding the necessary patch, element and especially vertex description lines to
There are two identical light fixtures, so we only need one common entity file to describe them:
ENTITY light
VERTEX
< 0.0 0.0 0.02 >
< 0.2 0.0 0.02 >
< 0.4 0.0 0.02 >
< 0.6 0.0 0.02 >
< 0.8 0.0 0.02 >
< 1.0 0.0 0.02 >
< 1.0 1.0 0.02 >
< 0.8 1.0 0.02 >
< 0.6 1.0 0.02 >
< 0.4 1.0 0.02 >
< 0.2 1.0 0.02 >
< 0.0 1.0 0.02 >
< 0.0 0.0 0.0 >
< 1.0 0.0 0.0 >
< 1.0 0.0 0.02 >
< 0.0 0.0 0.02 >
< 1.0 0.0 0.0 >
< 1.0 1.0 0.0 >
< 1.0 1.0 0.02 >
< 1.0 0.0 0.02 >
< 1.0 1.0 0.0 >
< 0.0 1.0 0.0 >
< 0.0 1.0 0.02 >
< 1.0 1.0 0.02 >
< 0.0 1.0 0.0 >
< 0.0 0.0 0.0 >
< 0.0 0.0 0.02 >
< 0.0 1.0 0.02 >
< 0.0 0.0 0.0 >
< 0.2 0.0 0.0 >
< 0.4 0.0 0.0 >
< 0.6 0.0 0.0 >
< 0.8 0.0 0.0 >
< 1.0 0.0 0.0 >
< 1.0 1.0 0.0 >
< 0.8 1.0 0.0 >
< 0.6 1.0 0.0 >
< 0.4 1.0 0.0 >
< 0.2 1.0 0.0 >
< 0.0 1.0 0.0 >
END_VERT
SURFACE
[ 0.0 0.0 0.0 ] [ 1.0 1.0 1.0 ]
[ 0.0 0.0 0.5 ] [ 0.0 0.0 0.0 ]
[ 0.0 0.0 0.5 ] [ 0.0 0.0 0.0 ]
[ 0.0 0.0 0.5 ] [ 0.0 0.0 0.0 ]
[ 0.0 0.0 0.5 ] [ 0.0 0.0 0.0 ]
Solving the Radiosity Equation 425
________________________________________________________________________
[ 0.0 0.0 0.0 ] [ 0.5 0.5 0.5 ]
END_SURF
PATCH
0 { 0 1 10 11 }
0 ( 1 2 9 10 }
0 { 2 3 8 9 }
0 { 3 4 7 8 }
0 ( 4 5 6 7 }
1 { 12 13 14 15 }
2 { 16 17 18 19 }
3 { 20 21 22 23 }
4 { 24 25 26 27 }
5 { 28 39 38 29 }
5 { 29 38 37 30 }
5 { 30 37 36 31 }
5 { 31 36 35 32 }
5 { 32 35 34 33 }
END_PATCH
ELEMENT
0 { 0 1 10 11 }
1 ( 1 2 9 10 }
2 { 2 3 8 9 }
3 { 3 4 7 8 }
4 ( 4 5 6 7 }
5 { 12 13 14 15 }
6 { 16 17 18 19 }
7 { 20 21 22 23 }
8 { 24 25 26 27 }
9 { 28 39 38 29 }
10 { 29 38 37 30 }
11 { 30 37 36 31 }
12 { 31 36 35 32 }
13 { 32 35 34 33 }
END_ELEM
END_ENTITY
Listing 6.7 - LIGHT.ENT
LIGHT.ENT describes the light fixture as a unit square, which is definitely not what is shown in Figure
6.13 and the color plates. Remember, however, that we can scale, rotate and translate an entity as required,
depending on the parameters we specify in the environment file. In this case, we can stretch LIGHT.ENT
into a semblance of a linear fluorescent lighting fixture that emits light from both its top and bottom faces.
Figure 6.13 shows the light fixtures suspended below the ceiling plane. Accordingly, the top and
bottom faces of LIGHT.ENT consist of five patches. This is an attempt to comply with the Five-Times
Rule (Section 5.5), again within the limits of the size of text file that can be reproduced here. LIGHT.ENT
will be rotated 180 degrees on its horizontal axis to properly orient it in the environment.
Finally, we need to define the floor, ceiling and walls of our room. Each of these surfaces consists of
one patch and a square grid of 25 elements. This is far from optimal with respect to the Five-Times Rule,
426 Solving the Radiosity Equation
________________________________________________________________________
especially where the surfaces meet at the corners. On the other hand, it will serve to demonstrate both the
We can use the following entity file as a template to define these surfaces:
W_WALL.ENT describes the three white walls of our room. The surface reflectance is described by
…
SURFACE
[ 0.8 0.8 0.8 ] [ 0.0 0.0 0.0 ]
END_SURF
…
(This actually describes a light gray surface that reflects 80 percent in each of the three color bands.
To create the red wall, we only need to change the above to:
and name the modified file R_WALL.ENT. Similarly, the floor becomes:
which we name FLOOR.ENT. (This will look like a rather pleasant gray carpet with a blue-green tinge.
which we name CEILING.ENT. That done, we can arrange our room and its furnishings with:
WORLD room
COMMENT floor
floor.ent
428 Solving the Radiosity Equation
________________________________________________________________________
< 1.0 1.6 1.0 >
< 0.0 0.0 0.0 >
< 0.0 0.0 0.0 >
COMMENT ceiling
ceiling.ent
< 1.0 1.6 1.0 >
< 180.0 0.0 0.0 >
< 0.0 1.6 1.0 >
COMMENT red wall
r_wall.ent
< 1.0 1.0 1.0 >
< 270.0 0.0 0.0 >
< 0.0 0.0 1.0 >
COMMENT white wall
w_wall.ent
< 1.0 1.6 1.0 >
< 0.0 90.0 0.0 >
< 0.0 0.0 1.0 >
COMMENT white wall
w_wall.ent
< 1.0 1.0 1.0 >
< 90.0 0.0 0.0 >
< 0.0 1.6 0.0 >
COMMENT white wall
w_wall.ent
< 1.0 1.6 1.0 >
< 0.0 270.0 0.0 >
< 1.0 0.0 0.0 >
COMMENT light #1
light.ent
< 0.8 0.05 1.0 >
< 180.0 0.0 0.0 >
< 0.1 0.2 0.8 >
COMMENT light #2
light.ent
< 0.8 0.05 1.0 >
< 180.0 0.0 0.0 >
< 0.1 1.4 0.8 >
COMMENT bench
bench.ent
< 0.16 0.16 0.08 >
< 0.0 0.0 0.0 >
< 0.1 0.2 0.0 >
END_FILE
Listing 6.9 - ROOM.WLD
This gives us an environment with 9 instances, 22 surfaces, 48 patches, 197 elements and 326 vertices.
We have an environment and three versions of HELIOS to examine it with. Their user interfaces are
almost identical, so we can choose whichever one we please for a test drive.
To display a view of the room, we first need to ensure that the following files are in the same directory:
and run HELIOS as a MS-Windows program. Once its main window is displayed, we can:
2, Choose the Open… menu item to display the Open common dialog box.
An Environment Statistics dialog box will appear with an enumeration of the instances, surfaces, patches,
If the entity files are not in the same directory as ROOM.WLD, an error message will appear in a dialog
2. Choose the Directories… menu item to display the Directories dialog box.
3. Enter the correct file path in the Entities File Path edit control.
and repeat the previous three steps to select the ROOM.WLD file again.
With the environment file parsed and loaded into memory, we can now:
2. Choose the Set Parameters menu item to display the Camera Parameters dialog box.
This sets the camera view distance at 2.0 units, giving a field of view roughly equivalent to a 35 mm lens
on a 35 mm camera. The default Window Dimensions values tell HELIOS to display the image as a
horizontally-oriented bitmap of 640 × 480 pixels. We can change this to whatever size we want, from a
2. Choose the Specify View… menu item to display the View Parameters dialog box.
3. Enter “-1.5” (note the minus sign) in the Eye Position X-Axis edit control.
6. Enter “-30” (note the minus sign) in the View Direction Horizontal Degrees edit control.
The View Direction Vertical Degrees and View-Up Vector edit controls remain unchanged.
A wireframe image of the room will be displayed (Fig. 6.13). Recalling Chapter Four, this image will
automatically resize itself whenever the display window size is changed. We can also go back and change
any of the previous entries to change the view or camera parameters; the wireframe image will update itself
accordingly.
It may take a few seconds or more to display the image, depending on the CPU speed and whether a math
coprocessor is present. Increasing the bitmap size in either direction increases display calculation time
accordingly. Remember that we are using floating point operations here; an integer-only version (Section
We can use a computer with a 256-color display, but the images as displayed by HELIOS will appear
posterized. The diskette accompanying this book includes C++ source code and an executable file for a
color quantization utility (Section 3.5.2) that converts 24-bit color bitmaps to 8-bit (256 color) bitmaps.
As an aside, it is worth noting that an MS-Windows program operating in 256-color mode does not
automatically map 24-bit RGB colors to the current palette of 256 colors when the MS-Windows API
function SetPixel is called. Unless specifically programmed to do otherwise, the Windows GDI (Graphical
Device Interface) merrily maps the color to one of 20 default system colors that have been specified via the
Control Panel for the window borders, title bars, menu bars, background and so forth. This explains why
24-bit color images displayed using Microsoft Paintbrush and similar programs usually appear so garish
Remember also that even though our computer may be capable of displaying 32,768 or more colors, the
Microsoft Windows environment may be set up to use an 8-bit (256-color) display driver for speed
reasons. You may have to use the Windows Setup program to change to the appropriate display driver (see
and … wait … and there you have it: a photorealistic rendering of the room. The Convergence Statistics
dialog box will tell us how many steps were required to achieve the default stopping criterion of 0.001.
How long do we have to wait? On a typical 66-Mhz 486 machine, execution times were as follows:
HELIOS/CT: 35 seconds
HELIOS/HC: 44 seconds
will obviously vary, depending on the CPU speed of our machine and whether it has a numeric coprocessor
(which is highly recommended). Radiosity rendering is almost entirely concerned with floating point
calculations. As such, it will not matter much whether we are running under 16-bit MS-Windows 3.1 or
32-bit Windows NT. The execution times will be roughly comparable for the same CPU clock speed.
As promised, there are no discernable differences between the images produced by the hemi-cube and
cubic tetrahedral algorithms. On the other hand, there are marked differences between these images and the
ray cast image. The former clearly shows the effects of nodal averaging (Section 4.16) in smoothing out
differences between element exitances, while the ray cast image shows some rather obvious Mach bands.
Despite these problems, you have to admit that the images show none of the plastic surfaces we so
often see in ray traced images. Achieving similar results with an unoptimized ray tracing programs would
consume hours to days of CPU time. As the color plates show, HELIOS is quite capable of rendering more
There are two other points to be made here concerning the relative execution times. First, the cubic
tetrahedron algorithm appears to offer approximately 25 percent better execution times than the hemi-cube
algorithm. Remember, however, that this only applies for the particular implementations of these
algorithms we have developed. The discussion at the end of Section 5.19.1 presented a number of possible
acceleration techniques that may skew the performance results in either direction.
Second, the ray casting algorithm is nearly six times slower than the cubic tetrahedron algorithm–but
only for this particular environment. Section 5.23.3 noted that a naive implementation of the ray casting
algorithm has a time complexity of O(mn 2 ) for m patches and n elements, whereas the hemi-cube and
cubic tetrahedron algorithms have a time complexity of O(mn ) . This means that the difference in
execution times will increase with increasing environment complexity. This clearly indicates the need for
implementing one or more ray tracing acceleration techniques within the RayCast class, again as discussed
in Section 5.23.3. Remember that HELIOS is a testbed for experimentation; it is not a production-quality
radiosity renderer!
Solving the Radiosity Equation 433
________________________________________________________________________
Having performed the radiosity calculations for the environment, we do not need to choose Rendering
again until we load in a new environment data file. That is, we can change the camera and view parameters
to look at the environment from whatever direction we choose, using the Wireframe display to provide a
2. Choose the Set Display… menu item to display the Display Parameters dialog box.
The Display Parameters dialog box also allows us to specify the gamma correction value (Section
3.5.1). The default value is 2.2; increasing it has the effect of increasing the image contrast and lightening
the image. We can disable gamma correction by unchecking the Enable checkbox.
If the display is only capable of 32,768 or 65,536 colors, there will be some noticeable color banding in
the image. This is not an aliasing artifact, but a slight posterization of the image. This is also where color
reduction comes in (Section 3.5.2). It is disabled by default, but we can enable it by checking the Enable
checkbox and redisplaying the image. The default Noise Level value is 1, but we can set it to any integer
2. Choose the Set Convergence… menu item to display the Convergence Parameters dialog box.
3. Enter an integer value between 1 and 2000 in the Maximum Steps edit control. (The default value is
100).
434 Solving the Radiosity Equation
________________________________________________________________________
4. Enter a floating point value between 0.0 and 1.0 in the Stopping Criterion edit control. (The default
value is 0.001).
5. Check or uncheck the Ambient Exitance checkbox as desired. (Ambient exitance is disabled by default).
6. Check or uncheck the Positive Overshoot checkbox (positive overshooting is enabled by default. It also
ROOM.WLD takes between 40 and 50 steps to converge to the default stopping citerion of 0.001 with
positive overshooting enabled. As an experiment, we might try setting the maximum steps to 1 and
enabling or disabling ambient exitance. We can select Rendering again and see what the difference is
between the images. We might also disable positive overshooting to see how long ROOM.WLD takes to
2. Choose the Save As… menu item to display the Save As common dialog box.
and specify an appropriate directory and file name. The file can later be viewed using Microsoft Paintbrush
or any other BMP-compatible graphics program capable of displaying at least 32,768 colors.
Finally, we can:
2. Choose the About Helios… menu item to display the About HELIOS dialog box.
The preface promised that radiosity is “… fascinating to experiment with.” This demonstration of
6.13 Conclusions
We began this chapter with a promise that solving the radiosity equation would be easy in comparison
to the material presented in the preceding chapters. Looking back, you may be inclined to disagree.
However, look again at the progressive refinement radiosity algorithm outlined in Figure 6.4. This is the
radiosity approach in its entirety! Everything else can be considered bothersome implementation details.
Solving the Radiosity Equation 435
________________________________________________________________________
More to the point, we can take some pride in having developed three functional versions of HELIOS.
At some 7,000 lines of C++ source code, it represents a medium-sized software engineering project for one
person. Seen from a different perspective, it offers a surprising amount of functionality for its size. This is
due in no small part to the underlying graphical user interface provided by MS-Windows … can you
So, we finally have our radiosity-based rendering program. True, we have to create our environment
and entity data files by hand, which can be a nuisance. Do this enough times and you will be ready and
willing to write your own AutoCAD DXF translator. (See the accompanying diskette for a simple
example.) Before then, however, we need to determine how an environment should be meshed to produce
References
Baum, D.R., H.E. Rushmeier and J.M. Winget [1989]. “Improving Radiosity Solutions Through the Use of
Analytically Determined Form Factors”, Computer Graphics 23:3 (Proc. ACM SIGGRAPH ‘89), 325 -
334.
Burden, R.L. and J.D. Faires [1985]. Numerical Analysis, Prindle, Weber & Schmidt, Boston MA.
Cohen, M.F. and D.P. Greenberg [1985]. “The Hemi-Cube: A Radiosity Solution for Complex
Cohen, M.F., D.P. Greenberg, D.S. Immel and P.J. Brock [1986]. “An Efficient Radiosity Approach for
Realistic Image Synthesis”, IEEE Computer Graphics and Applications 6:3, 26 - 35.
Cohen, M.F. and J.R. Wallace [1993]. Radiosity and Realistic Image Synthesis, Academic Press, San
Diego, CA.
Cohen, M.F., S.E. Chen, J.R. Wallace and D.P. Greenberg [1988]. “A Progressive Refinement Approach to
Fast Radiosity Image Generation”, Computer Graphics 22:4 (Proc. ACM SIGGRAPH ‘88), 75 - 84.
Gastinel, N. [1970]. Linear Numerical Analysis, Academic Press, San Diego, CA.
436 Solving the Radiosity Equation
________________________________________________________________________
Golub, G.H. and C.F. Van Loan [1983]. Matrix Computations, John Hopkins University Press, Baltimore,
MD.
Gortler, S. and M.F. Cohen [1993a]. Radiosity and Relaxation Methods: Progressive Refinement is
Greiner, G., W. Heidrich and P. Slusallek [1993], “Blockwise Refinement - A New Method for Solving the
Radiosity Problem”, Proc. Fourth Eurographics Workshop on Rendering, Paris, France, 233 - 245.
Heckbert, P.S. [1991]. “Simulating Global Illumination Using Adaptive Meshing”, Ph.D. Thesis, U. of
Kajiya, J.T. [1986]. “The Rendering Equation”, Computer Graphics 20:4 (Proc. ACM SIGGRAPH ‘86),
143 - 150.
Noble, B. [1969]. Applied Linear Algebra, Prentice Hall, Englewood Cliffs, NJ.
Shao, M. and N.I. Badler [1993a]. A Gathering and Shooting Progressive Refinement Radiosity Method,
Pennsylvania.
Shao, M. and N.I. Badler [1993b]. “Analysis and Acceleration of Progressive Refinement Radiosity
Wallace, J.R., K.A. Elmquist and E.A. Haines [1989]. “A Ray Tracing Algorithm for Progressive
Radiosity”, Computer Graphics 23:3 (Proc. ACM SIGGRAPH ‘89), 315 - 324.
Chapter 7
Meshing Strategies
7.0 Introduction
Looking at our first radiosity-based images, we quickly become aware that the accuracy of the radiosity
approach is very much dependent on the underlying mesh of elements used to represent each surface.
While the images may display soft shadows and subtle color bleeding effects, their details are limited by
the size and shape of the underlying elements. This is particularly evident where surfaces are close to one
We can see this problem more clearly in Figure 7.1. The continuous curve represents the “true”
exitance distribution M (x ) that we might measure across a surface in a physical environment. Looking at
this surface, we would see the steeply sloped portions of the curve as reasonably well defined shadow
edges.
M(x) M(x)
A B C
Now, suppose we model this surface as an array of elements. The vertical lines then indicate the
positions of the element vertices, while the height of each line represents the exitance at that vertex. The
shaded gray area connecting these lines represents the linearly interpolated exitance at each point on the
surface. In a 3-D environment, this interpolation would be the result of Gouraud shading (Section 4.13).
This demonstrates the need to choose an appropriately spaced mesh of elements. If the mesh is too
coarse, there may be excessive interpolation errors between the vertices (C). These become evident in the
Meshing Strategies 439
________________________________________________________________________
rendered image as missing shadow details (B) and unrealistically soft shadow edges. In some cases, the
One brute force solution to this problem is to finely mesh each surface such that individual elements are
too small to be visible in any rendered image. This works, but the cost in terms of memory requirements
and execution times quickly becomes unmanageable. It is also inefficient, since there is no reason to finely
mesh the surface where the change in exitance is relatively constant ( A).
A better approach is to employ a non-uniform element spacing such as that shown in Figure 7.2. Here,
the element vertices are placed such that the interpolation error at any point on the surface does not exceed
some predetermined maximum value. Large, smoothly shaded areas of the surface can be represented by
relatively few elements, while the shadow edges and other areas where the true surface exitance M (x )
M(x)
Of course, the problem with this scheme is that we need to know the distribution of shadows in the
environment before we begin solving the radiosity equation. Rephrasing this slightly, we need to know the
solution to the radiosity equation in order to create an appropriate mesh that allows us to solve the radiosity
equation.
There are several solutions to this circular reasoning. We can attempt to predict a priori where the
shadows will occur when we generate our initial mesh for an environment. This allows us to concentrate
elements where we suspect the exitance distribution will change rapidly across a surface. We can also
iteratively refine our mesh after each step in solving the radiosity equation. We can split or merge
radiosity renderer with a geometric description of an environment and let these meshing algorithms decide
how to mesh each surface. There may be some touch-up work required to obtain a suitable mesh, but most
Having said this, there are two disadvantages that prevent us from implementing these algorithms
within the context of HELIOS. First, they require a detailed knowledge of the geometry of each object in
the environment. This information is available from our environment data structure, but it can be difficult
The second disadvantage is more immediate. We have a limited amount of space remaining in which to
discuss both meshing techniques and other radiosity approaches. This book is about radiosity, not
automatic meshing algorithms. Moreover, a detailed discussion and implementation of these algorithms
This leaves us with one option. We will have to create our initial meshes by hand and modify them
based on our analysis of the rendered images. To this end, we need to develop a set of heuristic rules, or
meshing strategies, that will allow us to understand and predict the cause-and-effect relationship between
HELIOS is admittedly incomplete. Entering thousands of vertices by hand is obviously impractical for
truly complex environments. Also, a professional implementation should include an automatic meshing
algorithm that relieves the user of having to understand the following strategies. To this end, the following
discussions include numerous references for further study. HELIOS was designed from the beginning to be
extensible; the challenge is to use it as a testbed for your own experiments and investigations.
The easiest way to create an entity data file is to use a commercial 3-D CAD program such as
AutoDesk’s AutoCAD. As we noted in Chapter Three, these programs offer many more features than we
shall ever require. On the other hand, their ability to model complex 3-D surfaces is essential for any truly
Meshing Strategies 441
________________________________________________________________________
serious radiosity rendering efforts. While we do not have the space needed to develop a CAD file
translation utility here, we should nevertheless examine the issues involved in generating input files.
One problem common to many 3-D CAD programs is that they do not enforce the concept of a surface
having a visible side. The user is expected to specify a surface as an ordered sequence of vertices, but the
concept of a surface normal is undefined. If these vertices are imported as is into our entity files, there is no
guarantee that the surfaces will be properly oriented. This includes the popular AutoCAD DXF file format
(Autodesk [1992a-c]).
One practical solution is to display the CAD files using shaded surfaces. If a surface faces away from
the camera, it should be displayed as a wireframe. A user interface command then allows the user to
identify and interactively “flip” incorrectly oriented surfaces by reordering their vertices. Smith [1991],
Baum et al. [1991] (which is an expanded version of Smith [1991]) and Blinn [1993] offer several practical
Another problem–and this also applies to our own entity data files–is that a physical surface has two
sides. There is no problem in an exterior wall of our test environment room (Section 6.12), for example,
having only one visible side. The radiant flux in the room will never encounter the invisible side of these
surfaces. Similarly, each surface of our solid light fixtures and bench need only one visible side. However,
consider a sheet of paper suspended in mid-air. (This is, after all, virtual reality.) While we may see its
visible side from our camera position in the room, we must remember that light is flowing though the
environment in all directions. The paper may cast a shadow on the floor, which is reasonable. However, the
light subsequently reflected from within this shadow will pass right through the invisible side of the paper
if it is modeled as a single surface. To avoid this anomaly, we need to model the paper as having two
visible sides; that is, with two identical and coplanar surfaces facing in opposite directions.
This highlights an important point: the radiosity approach interacts with solid objects in an
environment. This implies that the environment data file should be created with a solid modeling program
442 Meshing Strategies
________________________________________________________________________
that intrinsically enforces this concept. Until such programs become widely available, however, we shall
have to expect data input from less capable 3-D CAD programs.
Coplanar surfaces present yet another problem. Suppose we have a (single-sided) sheet of paper lying
on a desktop surface. This appears reasonable until we remember that our vertex co-ordinates and Z-
buffering algorithm have a finite depth precision. It may well be that the two surfaces are no longer exactly
coplanar after their vertex co-ordinates have been independently scaled, translated, rotated and interpolated
during perspective projection and clipping. At worst, the paper may appear to be partially embedded in the
It is not always evident which of two coplanar surfaces should be visible. Baum et al. [1991] adopted
the heuristic that the smaller of the two surfaces should remain visible. The larger, underlying surface is
A CAD user will often build a complex surface piece by piece. While the final result may look correct
when rendered as a shaded image, it may be that adjoining vertices are almost but not quite coincident
(e.g., Segal [1990]). Baum et al. [1991] simplified these surfaces by first determining whether adjoining
surfaces consisted of the same material (i.e., they had the same reflectance properties). If so, then any
vertices whose 3-D co-ordinates were less than some minimum distance apart are merged. (Vertex co-
ordinates were stored in an octree data structure to simplify their comparison.) Once this was done, the
edges were then merged as well to create a contiguous set of surfaces (e.g., Fig. 7.3).
topologically complex) surfaces (e.g., Fig. 7.4). This made subsequent division of these maximally
connected surfaces into a mesh of elements a more controllable process with fewer geometric constraints.
A second reason to merge complex sets of common surfaces is that it eliminates T-vertices (Fig. 7.5).
As Baum et al. [1991] observed, these create several problems. For example, the additional vertex along a
common edge between two elements can create discontinuities when they are Gouraud-shaded. In Figure
7.5, the calculated exitance at vertex C will likely differ from the exitance interpolated at that point from
the vertices A, D and E (see Section 4.13 for details). The resultant differences in shading may be visible as
B C E
A more serious problem may occur due to the finite precision of the floating point arithmetic used to
manipulate the vertex co-ordinates. Suppose in Figure 7.5 that vertices A, D and E represent one element.
If the T-vertex C is not exactly coincident with the edge defined by A and D, there may be a noticeable gap
D
E
T-vertices are less of a problem when they occur on the edges separating different surfaces, since each
surface is independently shaded. However, gaps between these surfaces (also referred to as “pixel
dropouts”) may still occur due to floating point roundoff. These gaps will also occur between elements of
the same surface. They are never more than a single pixel wide, which makes them easy to distinguish from
Baum et al. [1991] proposed that edges of adjoining polygons be “ziplocked” by using identical sets of
vertices for each edge. For example, if the triangle A-D-E in Figure 7.5 were a different surface from
A-B-C and B-D-C, ziplocking would change it into the quadrilateral A-C-D-E. (The addition of vertices
may require that the original elements be split into quadrilaterals and triangles to limit their number of
edges to four. Alternatively, ziplocking can be done immediately before displaying the image if the 3-D
While eliminating T-vertices from a mesh is highly recommended, it is not essential. Cohen and
Wallace [1993] describe their use as slave vertices. A mesh is developed with T-vertices and solved using
one of the radiosity algorithms presented in Chapter Six. However, the exitances of the T-vertices are not
used when it comes time to display the elements using Gouraud shading. Instead, they are linearly
interpolated from those of the edge endpoint vertices (e.g., A and D in Fig. 7.5). This may introduce some
small amount of error into the radiosity solution. However, it ensures that the Gouraud-shaded elements of
Baum et al. [1991] incorporated the above rules in a series of filter programs that preprocessed
AutoCAD DXF files for radiosity rendering applications (see also Smith [1991]). While such programs are
Meshing Strategies 445
________________________________________________________________________
undeniably useful, they represent a major software development effort that clearly extends beyond the
scope of this book. Fortunately, much of the above can be applied equally well to input files that are
generated by hand.
A much simpler but still useful approach is to use a 3-D CAD program to create initial surface meshes
for our entity files. AutoCAD, for instance, can be used to model the surfaces as polygon meshes and
generate DXF files. Creating a program that reads these files and generates an output file of surfaces,
patches and elements is straightforward. The technical details of the DXF file format are described in
Autodesk [1992a-c], and an example DXF file parser is included on the diskette accompanying this book.
This relieves much of the tedium involved in creating entity files by hand using a text editor.
One of the problems inherent in the AutoCAD DXF and similar CAD file formats is that they do not
include the geometrical information needed by automatic meshing algorithms. However, Baum et al.
[1991] found that this information can be derived from such files during the process of merging vertices,
edges and surfaces and stored in a winged edge data structure. Thus, while they are by no means ideal,
most CAD file formats can be used to represent environments for radiosity-based rendering programs.
There are many ways in which light can interact with a mesh of elements. We have already seen some
examples, including a) a non-uniform mesh is needed to capture exitance gradients efficiently, b) aliasing
effects can occur at shadow edges if the mesh is too coarse, and c) small shadow details can be missed
entirely by a coarse mesh. We need to consider these and other interactions, and from them develop more
Aliasing effects require further explanation. Consider a sharply defined shadow edge that is diagonal to
a set of elements (Fig. 7.6). There are two related problems here. First, the expanded view of one element
indicates that the surface exitance should be zero inside the shadow and 100 otherwise. However, the
screen scan line drawn across the element indicates that Gouraud shading would show a continuous
decrease in screen luminance from left to right. Looking at the set of elements in a rendered image, we
would see the shadow as having a staircase appearance that clearly indicates the underlying element mesh.
446 Meshing Strategies
________________________________________________________________________
100 0
50
This problem has an obvious but difficult solution: orient the elements such that their edges follow the
shadow boundaries. This allows Gouraud-shaded elements to accurately follow the contours of the shadow
edges. We ideally want the boundaries to follow the edges of soft shadows as well (Fig. 7.7). The trick is to
Occluding surface
Penumbra
This is where automatic meshing algorithms are useful. We can perform an a priori geometrical
analysis of the environment to determine where shadows will most likely occur. Nishita and Nakamae
[1985] and Campbell and Fussell [1990] did this by shooting “shadow rays” from the light sources to
project silhouettes of objects onto surfaces. This defines both the umbrae (shadows) and penumbrae
(literally, “almost shadows”) cast by the object onto the surfaces, much as our ray casting radiosity
algorithm determines vertex-to-source form factors. These silhouettes provide the geometrical information
Heckbert [1991] referred to these boundaries as discontinuities in the surface exitance distribution.
Efficient discontinuity meshing algorithms for determining optimal element meshes are presented in
Meshing Strategies 447
________________________________________________________________________
Heckbert [1992], Lischinski et al. [1992] and Tampieri [1993]. (See also Cohen and Wallace [1993] for a
detailed summary). Unfortunately, these algorithms are too involved to discuss or implement here.
One problem with discontinuity meshing is that it can only identify shadows due to direct illumination
from light sources. There may be circumstances where well-defined soft shadows are a result of indirect
lighting from highly reflective surfaces. These generally cannot be identified until the radiosity equation
The second aliasing problem has to do with Gouraud shading in general. Remember that this is done in
screen space. That is, we are really interpolating pixel luminances rather than surface exitances. Every time
we reorient the quadrilateral element shown in Figure 7.8, the scan line has a different pair of endpoint
pixel luminances to interpolate between. From this, we can see that the appearance of the element will
100 0
100 0 67 67 33 33
67 33
0 0 100 100
33 67
67 67 33 33
0 100
100 0
Note that this problem only applies to quadrilateral elements; it does not occur when triangular
elements are rendered. This suggests the simple solution of splitting quadrilaterals into triangles. Since this
problem only occurs during the shading process, we can perform this triangulation in screen space
Airey et al. [1990] and Haines [1991] recommended splitting quadrilaterals such that the endpoints of
the diagonal edge have the least exitance difference (averaged over all three color bands). If, for example, a
quadrilateral element has average vertex exitances values of 1.0, 2.0, 3.0 and 7.0, it would be split with a
new edge extending from the first to the third vertex. This tends to smooth out aliasing at shadow
exitances in world space directly on the surface of each element (e.g., Cohen and Wallace [1993]). This
also solves another problem with Gouraud shading. The perspective projection of an element’s co-
ordinates from world space to screen space results in the element depth co-ordinates being distorted
(Section 4.3). Thus, linear interpolation between two points of an element’s edge is not entirely correct,
since the element depth along the scan line may change in a nonlinear fashion. On the other hand, linear
interpolation is itself an approximation, and so we can generally ignore this problem. (See Blinn [1992] for
another approach.)
Mach banding is another issue that is exacerbated by Gouraud shading. The human visual system is
acutely sensitive to edges in its field of view. When we look at an edge between a dark gray and a white
surface, we often perceive the gray as being darker and the white as being whiter adjacent to the edge. This
is a purely physiological effect–measuring the surface luminance at these points would show no such
anomalies.
The problem is that Gouraud shading creates sudden changes in surface luminance at element edges
(e.g., Fig. 7.1). We perceive these changes as being edges within what should be smoothly shaded surfaces.
These become more noticeable when the surfaces are large in the rendered image. They also occur where
the slope of the exitance distribution changes rapidly across the surface, such as within soft shadows.
Mach banding problems can be minimizing by using a finer element mesh. Another approach is to
perform a higher order interpolation between vertex exitances. Referring to Figure 7.1, we can replace the
straight lines connecting the vertices with curves that are described by quadratic or cubic equations. In two
dimensions, this is equivalent to modeling a curved surface with Bézier or B-spline surfaces (e.g., Foley et
al. [1990]), except that the 2-D “surface” we are trying to model is the true exitance distribution M (x ) . A
detailed review of these interpolation techniques is presented in Cohen and Wallace [1993].
Mach banding problems can also be alleviated by ensuring that the mesh grading is relatively smooth.
That is, the difference in areas between adjacent elements should be kept as small as possible. This
Meshing Strategies 449
________________________________________________________________________
produces a mesh like that shown in Figure 7.9 (where T-vertices have been allowed for illustrational
clarity).
One consequence of a smooth mesh grading is that the individual elements tend to have a small aspect
ratio, which is defined as the ratio of the inner and outer bounding circles (Fig. 7.10) for the element
vertices (e.g., Baum et al. [1991]). Such elements are referred to as being well-shaped. This has three
advantages. First, it maximizes the element area and thereby minimizes the number of elements needed to
mesh a surface. Second, it produces elements that approximate circular disks; this is one of the assumptions
of the ray casting radiosity algorithm (Section 5.23). Third, it improves the accuracy of the form factor
determination process and through it the radiosity solution (Baum et al. [1989]).
Element
I
O
Aspect ratio - O / I
Figure 7.10 - Element aspect ratio is determined by inner and outer bounding circles
Baum et al. [1991] suggested subdividing quadrilaterals and triangles into four by placing new vertices
at the midpoint of each element edge, as shown in Figure 7.11. If the parent element is well-shaped, then
each of its child elements will also be well-shaped. This is particularly convenient when it comes to
Finally, we need to recognize the consequences of randomly placing one entity on top of another.
Consider a flat surface with a vertical partition dividing it (Fig. 7.12). The two gray elements on the flat
surface receive flux that is shot from the light source. However, these elements are divided by the partition.
When they later shoot their flux, it will be sent to both sides of the partition. In other words, there is light
leakage through the partition (Bullis [1989] and Campbell and Fussell [1990]).
Figure 7.12 - Mismatched element boundaries allow light and shadow leakage
Suppose the partition is a wall that divides two rooms. If only one of the rooms is illuminated, we will
see in the rendered image that the wall apparently has a gap between it and the floor, with light spilling
through to illuminate the darkened room. An interesting effect, but definitely not what was intended!
Similarly, this light is lost from the illuminated room. The floor elements adjacent to the wall will appear
darker than they should, so that we also have shadow leakage from the darkened room.
The solution is to ensure that element boundaries are aligned not only with the shadow boundaries (as
in discontinuity meshing), but also with the surface boundaries of other entity surfaces. Baum et al. [1991]
performed this alignment automatically using algorithms presented in Segal [1990] and Segal and Séquin
[1988].
Meshing Strategies 451
________________________________________________________________________
This is perhaps the most difficult and frustrating aspect of meshing, since one or more surfaces usually
need to be remeshed whenever an object is moved in the environment. On the other hand, it should be
recognized that remeshing is not necessary in each instance, nor will light and shadow leakage be
significant in many cases. It is largely a matter of experience, subjective judgment and most importantly,
Most of the meshing considerations discussed above can be implemented manually as a set of rules to
follow when designing an initial mesh. However, there are limits to how many patches and elements we
can expect a user to generate. A better solution is to begin with a coarse mesh and let an automatic meshing
algorithm iteratively refine it after each step in solving the radiosity equation. This allows the program to
develop a mesh that concentrates elements at shadow boundaries and other regions where the exitance
Again, we do not have the space to implement an automatic meshing algorithm within the context of
There are several possibilities for mesh refinement (e.g., Cohen and Wallace [1993] and Ho-Le [1988]).
We can, for example, reposition the element vertices to align them with the shadow boundaries (e.g.,
Águas et al. [1993]). This is useful to some extent, but it assumes that the mesh spacing is such that the
number of elements is sufficient to represent the shadow details. It can also result in thin elements that are
not well-shaped.
A second possibility is to subdivide the elements. This adaptive subdivision allows us to generate new
elements only where they are most needed. Following the heuristic rules presented above, we ideally want
to:
3. Avoid T-vertices.
subdivide only if they differ by more than some predetermined amount in any color band with respect to
the range of reflected vertex exitances in the environment. There are more involved criteria that result in
fewer elements being subdivided (e.g., Cohen and Wallace [1993]), but this criterion is usually sufficient.
We also need some sort of stopping criterion. This is relatively easy: we stop when the subdivided
element area becomes too small to be significant in a rendered image. Since each subdivision produces four
child elements that each has approximately one-quarter of the parent element’s area (Fig. 7.11), the process
If we begin with a smooth mesh grading, subdividing elements according to Figure 7.11 will ensure
that the mesh remains smoothly graded. It will also tend to minimize the subdivided element aspect ratios.
Baum et al. [1991] suggested that the initial mesh should be balanced by ensuring that each element of a
surface should be adjacent to no more than two other elements along any of its edges (Fig. 7.13a).
Figure 7.13a - A balanced mesh Figure 7.13b - A balanced and anchored mesh
Every subdivision will unavoidably generate new T-vertices. Baum et al. [1991] also suggested that
neighboring elements should be anchored to these vertices. That is, the neighboring elements are further
subdivided by connecting the T-vertex to another vertex in the same element (Fig. 7.13b). Assuming that
only triangular and quadrilateral elements are allowed and ignoring symmetry, there are only six
possibilities for anchoring (Fig. 7.14). This simplifies the development of an automatic meshing algorithm
So what is the mystique behind creating a meshing algorithm? It certainly looks simple enough: add a
few new elements and vertices to the environment data structure and the problem is mostly solved.
The real problem is in those minor implementation details. If we use one of the progressive refinement
radiosity algorithms from Chapter Six, we need to know which elements share a vertex in order to
interpolate its exitance. We also need to know this information before we can interpolate a vertex’s normal.
This is the reason why each of our Vertex3 objects maintains a linked list of pointers to the Element3
Now, suppose we want to subdivide a parent element to create four child elements. The first step is to
insert new vertices midway between each pair of existing vertices (which define the element edges). This is
easy enough, although we should check beforehand to see whether a T-vertex belonging to an adjacent
element of the same surface is already at that position. If it is, then we must use it instead.
This poses a question: which other elements of the surface share this edge of the parent element? If
T-vertices are allowed, there could be any number of elements. We would have to check every edge of
every other element in the Instance object to determine whether it is collinear with current edge and
We have to repeat this process for every vertex we consider when subdividing an element. This
includes existing T-vertices, since we have to update their element lists when we split the parent element at
that point. The process clearly becomes unmanageable for even moderately complex environments.
The proper solution to this situation is to redesign our environment data structures from Vertex3
upwards as a winged edge data structure. These are described in detail in Baumgart [1974] and Baumgart
[1975]. Further details are provided by Glassner [1991], Hanrahan [1982], Mäntlyä and Sulonen [1982],
The advantage of the winged edge data structure is that it provides a wealth of geometric connectivity
information concerning the vertices, edges and polygonal faces of a 3-D solid object. The above question
becomes trivial, since the winged edge data structure directly encodes information about which elements
share an edge.
454 Meshing Strategies
________________________________________________________________________
The disadvantage is that the winged edge data structure can be difficult to implement properly. For
example, an implementation described in part by Glassner [1991] requires nineteen algorithmic steps to
insert a new edge between two existing vertices. Glassner punctuates his description of the data structure
with such disclaimers as “you have to make sure you do things in just the right order, or disaster will
ensue” and “I have provided only some signposts around what I found to be the most twisting parts of the
road.” Comments like these indicate that designing a robust and efficient winged edge data representation
Winged edge data structures have been used in many radiosity rendering programs (e.g., Cohen et al.
[1986), Baum et al. [1991] and Lischinski et al. [1992]), and with good reason. They offer an elegant
means of accessing the geometrical information needed by both adaptive subdivision and discontinuity
meshing algorithms. It is unfortunate that their complexity precluded their description in this book.
We have so far discussed the adaptive subdivision of element meshes. Cohen et al. [1986] noted that
there are two occasions where patches may need to be subdivided as well. For example, subdivision is
required when the differences between patch vertex exitances in any color band exceed some
The second occasion is less obvious. Recalling the progressive refinement radiosity algorithm presented
in Figure 6.4, we calculate the form factor Fij from a patch Ei to all other elements E j in the
environment. This can be done using either the hemi-cube or cubic tetrahedral algorithms from Chapter
Five. However, we then calculate the delta exitance ∆M to be sent to each of these elements as:
Ai
∆M = ρ j Fij ∆M iunsent = ρ j F ji ∆M iunsent (7.1)
Aj
The problem is that we obtain an approximate value of Fij by modeling Ei as a differential element
located at the center of the patch. If the area of Ei is much larger than that of E j , the calculated value of
Meshing Strategies 455
________________________________________________________________________
the reciprocal form factor F ji can clearly exceed unity at some point. This is a serious error, since it
implies that the element E j will receive more exitance than the patch Ei has sent into the environment!
There are several possible solutions. First, we can ensure that the range of element sizes does not
become excessive. The minimum value of Fij is that of the smallest delta form factor for the hemi-cube or
cubic tetrahedron. By limiting the ratio Ai A j , we can guarantee that F ji will never exceed unity.
Subdividing the patch is a second possibility that has the same effect. Its advantage is that the process
becomes transparent to the user. On the other hand, it will require a number of modifications to both the
The third possibility was suggested by Chen [1991], and was used in our implementation of the
progressive refinement radiosity algorithm (Listing 6.3). The reciprocal form factor is simply (and silently)
clipped to unity.
7.6 Conclusions
This chapter has outlined the issues involved in developing suitable meshes for the radiosity equation.
While we did not have the space to develop an adaptive subdivision algorithm, we now have a much better
understanding of the cause-and-effect relationship between an element mesh and the rendered images. The
meshing strategies developed in this chapter should help in improving the images that HELIOS creates.
There is a deep and fundamental relationship between the radiosity approach and finite element
methods. These are extremely important tools for scientists and engineers in a number of fields ranging
from fluid mechanics and structural engineering to cosmology. The radiosity approach models the field of
light in an environment. Finite element methods have been used to model everything from stresses in steel
and concrete structures to the magnetic fields of galaxies. The literature on this topic is vast and
multidisciplinary. Nevertheless, many of the techniques developed for finite element analysis can be
applied to the automatic generation and modification of element meshes for radiosity. Recommended
reading includes Baehann et al. [1987], Bank et al. [1983], Chew [1989], Frey [1987], Heckbert and
Winget [1991], Hugues [1987], Lalonde [1993], Schuierer [1989] and Watson [1984].
There are numerous challenges here for the ambitious reader. First, HELIOS would benefit from a
utility that automatically preprocesses CAD files. This could be modeled after the filter programs described
456 Meshing Strategies
________________________________________________________________________
in Baum et al. [1991]. Full technical details for the AutoCAD DXF file format are presented in Autodesk
[1992a-c].
A more challenging project is to redesign the environment data structure presented in Chapter Three to
incorporate the winged edge data structure. Unfortunately, the few complete sources of information on this
topic (e.g., Baumgart [1974] and Baumgart [1975]) may be difficult to obtain unless you have access to a
With this in place, you could implement one or more adaptive subdivision or discontinuity meshing
algorithms (e.g., Lischinski et al. [1992]). With these, HELIOS would be well on its way to becoming a
Meshing is a difficult problem for which there are no easy solutions. While it is somewhat incidental to
the radiosity equation, a well-shaped mesh is essential to obtaining an accurate approximation to the true
radiosity solution, and from it truly photorealistic images. The best we can do for now is to develop our
initial meshes, modify them through trial and error, and in general practice what Heckbert [1991] aptly
References
Águas, M.P.N. and S. Müller [1993]. “Mesh Redistribution in Radiosity”, Proc. Fourth Eurographics
Airey, J.M., J.H. Rohlf and F.P. Brooks, Jr. [1990]. “Towards Image Realism with Interactive Update
Rates in Complex Virtual Building Environments”, Computer Graphics 24:1 (Proc. ACM Workshop on
Arvo, J., Ed. [1991]. Graphic Gems II, Academic Press, San Diego, CA.
Autodesk [1992a]. AutoCAD Release 12 Reference Manual, Autodesk Inc. Publication #100186-02.
Autodesk [1992b]. AutoCAD Render Reference Manual (Release 12), Autodesk Inc. Publication #100190-
01.
Autodesk [1992c]. AutoCAD Development System Programmer’s Reference Manual (Release 12),
Based, Automatic 2D Mesh Generation”, Int’l. J. Numerical Methods in Engineering 24, 1043 - 1078.
Bank, R.E. A.H. Sherman and A. Weiser [1983]. “Refinement Algorithms and Data Structures for Regular
Baum, D.R., S. Mann, K.P. Smith and J.M. Winget [1991]. “Making Radiosity Usable: Automatic
Preprocessing and Meshing Techniques for the Generation of Accurate Radiosity Solutions”, Computer
Baum, D.R., H.E. Rushmeier and J.M. Winget [1989]. “Improving Radiosity Solutions Through the Use of
Analytically Determined Form Factors”, Computer Graphics 23:3 (Proc. ACM SIGGRAPH ‘89), 325 -
334.
Baumgart, B.G. [1975]. “A Polyhedron Representation for Computer Vision”, Proc. National Computer
Blinn, J.F. [1992]. “Hyperbolic Interpolation”, IEEE Computer Graphics & Applications 12:4, 89 - 94.
Blinn, J. [1993]. “Jim Blinn’s Corner: Backface Culling Snags”, IEEE Computer Graphics & Applications
13:6, 94 - 97.
Bullis, J.M. [1989]. Models and Algorithms for Computing Realistic Images Containing Diffuse
Campbell, A.T. III and D.S. Fussell [1990]. “Adaptive Mesh Generation for Global Diffuse Illumination”,
Chen, S.E. [1991]. “Implementing Progressive Radiosity with User-Provided Polygon Display Routines”,
Chew, L.P. [1989]. “Guaranteed-Quality Triangular Meshes”, Tech. Report 89-893, Dept. of Computer
Cohen, M.F., D.P. Greenberg, D.S. Immel and P.J. Brock [1986]. “An Efficient Radiosity Approach for
Realistic Image Synthesis”, IEEE Computer Graphics and Applications 6:3, 26 - 35.
458 Meshing Strategies
________________________________________________________________________
Cohen, M.F., S.E. Chen, J.R. Wallace and D.P. Greenberg [1988]. “A Progressive Refinement Approach to
Fast Radiosity Image Generation”, Computer Graphics 22:4 (Proc. ACM SIGGRAPH ‘88), 75 - 84.
Cohen, M.F. and J.R. Wallace [1993]. Radiosity and Realistic Image Synthesis, Academic Press, San
Diego, CA.
Foley, J.D., A. van Dam, S.K. Feiner and J.F. Hughes [1990]. Computer Graphics: Principles and Practice
Frey, W.H. [1987]. “Selective Refinement: A New Strategy for Automatic Node Placement in Graded
Glassner, A.S. [1991]. “Maintaining Winged-Edge Models”, in Arvo [1991], 191 - 201.
Haines, E. [1991]. “Ronchamp: A Case Study for Radiosity”, ACM SIGGRAPH ‘91 Frontiers In Radiosity
Course Notes.
Hanrahan, P. [1982]. “Creating Volume Models From Edge-Vertex Graphs”, Computer Graphics 16:3
Heckbert, P.S. [1991]. “Simulating Global Illumination Using Adaptive Meshing”, Ph.D. Thesis, U. of
Heckbert, P.S. [1992]. “Discontinuity Meshing for Radiosity”, Proc. Third Eurographics Workshop on
Heckbert, P.S. and J.M. Winget [1991]. “Finite Element Methods for Global Illumination”, U. of
Ho-Le, K. [1988]. “Finite Element Mesh Generation Methods: A Review and Classification”, Computer-
Hugues, T.J.R. [1987]. The Finite Element Method, Prentice-Hall, Englewood Cliffs, NJ.
Lalonde, P. [1993]. “An Adaptive Discretization Method for Progressive Radiosity”, Graphics Interface
Languénou, E., K. Bouatouch and P. Tellier [1992]. “An Adaptive Discretization Method for Radiosity”,
Mäntylä, M. and R. Sulonen [1982]. “Gwb - A Solid Modeler with Euler Operators”, IEEE Computer
Taking Account of Shadows and Interreflection”, Computer Graphics 19:3 (Proc. ACM SIGGRAPH ‘85),
23 - 30.
Samet, H. [1989]. The Design and Analysis of Spatial Data Structures, Addison-Wesley, Reading, MA.
Schuierer, S. [1989]. “Delaunay Triangulations and the Radiosity Approach”, Eurographics ‘89 (Proc.
European Computer Graphics Conference and Exhibition), W. Hansmann, F.R.A. Hopgood and W.
Strasser, Eds., Elsevier Science Publishers B.V. (North-Holland), Amsterdam, 345 - 353.
Segal, M. [1990]. “Using Tolerances to Guarantee Valid Polyhedral Modeling Results”, Computer
Segal, M. and C.H. Séquin [1988]. “Partitioning Polyhedral Objects into Non-Intersecting Parts”, IEEE
Shephard, M.S. [1988]. “Approaches to the Automatic Generation and Control of Finite Element Meshes”,
Sillion, F. [1991b]. “Detection of Shadow Boundaries for Adaptive Meshing in Radiosity”, in Arvo [1991],
311 - 315.
Smith, K.P. [1991]. “Fast and Accurate Radiosity-Based Rendering”, Master’s Project Report, U. of
Stepleman, R.S., Ed. [1983]. Scientific Computing: Applications of Mathematics and Computing to the
Physical Sciences, IMACS Trans. Scientific Computation Vol. 1, North-Holland, New York, NY.
Tampieri, F. [1993]. Discontinuity Meshing for Radiosity Image Synthesis, Ph.D. Thesis, Cornell
Toussaint, G. [1991]. “Efficient Triangulation of Simple Polygons”, The Visual Computer 7, 280 - 295.
Watson, D.F. and G.M. Philip [1984]. “Systematic Triangulations”, Computer Vision, Graphics and Image
Wilson, P.R. [1985]. “Euler Formulas and Geometric Modeling”, IEEE Computer Graphics &
For all the effort we have put into developing HELIOS, it is only the beginning. The full scope of
radiosity extends well beyond the limits of this book. We do not have the space to implement or even
• modeling complex area and volumetric light sources (Ashdown [1993a, b], Bao and Peng [1993] and
• semispecular and specular reflections (Chen et al. [1991], Hall and Rushmeier [1993], Immel et al.
[1986], Jessel et al. [1991], Kok et al. [1990], Le Saec and Schlick [1990], Rushmeier and Torrance
[1990], Sillion and Puech [1989], Sillion et al. [1991] and Wallace et al. [1987]).
• parallel processor implementations (Airey et al. [1990], Baum and Winget [1990], Bu and Deprettere
[1987a, b], Chalmers and Paddon [1991], Chen [1991], Feda and Purgathofer [1991], Guitton et al.
[1991], Hermitage et al. [1990], Jessel et al. [1991], Ng and Slater [1993], Price [1989], Shen et al.
• higher order radiosity basis functions (Bian et al. [1992], Cohen and Wallace [1993], Gortler et al.
[1993], Lischinski et al. [1991], Schröder et al. [1993], Tampieri and Lischinski [1991], Troutman and
• other radiosity approaches and related global illumination algorithms (Aupperle and Hanrahan [1993],
Baranoski [1992], DiLaura and Franck [1993], Dretakkis and Fiume [1991], Greiner et al. [1993],
Heckbert [1990], Kawai et al. [1993], Kok [1992], Kok et al. [1993], Liere [1991], Lischinksi et al.
[1991], Neumann and Keleman [1991], Neumann and Neumann [1989], Neumann and Neumann
462 Looking to the Future
________________________________________________________________________
[1990], Rushmeier et al. [1993], Salesin et al. [1992], Shao et al. [1988a, b], Tampieri and Lischinksi
[1991], Wang et al. [1992, Xu et al. [1989] and Zhou and Peng [1992]).
Some of these are interesting from a theoretical perspective, but too demanding in terms of execution
time and memory requirements to be of practical use. Others are practical and useful, and may have
Fortunately, we do have the space to discuss, however briefly, some possible extensions to HELIOS
that you might consider. They vary from simple modifications to major programming projects.
One of the disadvantages of HELIOS and the radiosity algorithms discussed in this book is that they
can only model opaque and diffuse surfaces. Moreover, these surfaces are intrinsically featureless within
each surface. The only details we see are in their shading, due to the field of light in the environment.
This is in sharp contrast to the ray tracing paradigm, which can model specular and semispecular
reflections and transparent or semitransparent objects with relative ease. Texture mapping and Phong
illumination techniques–to name a few–offer the possibility of richly detailed images that radiosity
There is no reason, however, why we cannot borrow these techniques for our radiosity-based images.
Texture mapping is an excellent example. Suppose that we want to model an office environment as seen
from above a wooden desk. Using ray tracing, we would map an image of wood grain to the surface of the
desk. The details of this technique can be found in any book on advanced ray tracing algorithms such as
Wilt [1993]. (See also Cohen et al. [1986], who discuss it in relation to radiosity-based rendering, and
Using radiosity methods, we can model the surface by computing its average spectral reflectance ρ avg .
That is, we average the spectral reflectance of each pixel in the texture map image (for each color band)
and use this to represent the desktop as an otherwise featureless surface. Clearly, the details of the wood
grain will have a mostly insignificant effect on the global radiosity solution.
Looking to the Future 463
________________________________________________________________________
Once we have solved the radiosity equation for the room and rendered (but not displayed) a preliminary
bitmapped image, we can perform a pixel-by-pixel texture mapping of the wood grain to the desk in the
image. This requires two operations. First, we need to warp and scale the rectangular wood grain image to
the 3-D view of the desktop (e.g., Foley et al. [1990]). This can become somewhat involved, especially
where there are intervening objects between the surface and the synthetic camera position. Fortunately, we
have already implemented most of the necessary algorithms in our viewing system.
Second, we need to incorporate the shading details we obtained from our radiosity solution. This is the
easy part. Given the Gouraud-interpolated radiant exitance for each color band and visible pixel of the
ρ xy
Mˆ xy = M xy (8.1)
ρ avg
where Mxy is the Gouraud-interpolated spectral exitance for a pixel with screen co-ordinates x and y, ρ xy
is the interpolated surface reflectance as determined from the texture map, and M̂ xy is the pixel’s texture-
There is one caveat to this procedure: we cannot always assume that the effect of a texture-mapped
surface on the environment can be accurately approximated with a featureless surface having its average
spectral reflectance. A surface with large and prominent changes in texture (a black-and-white tiled floor,
for example) may locally affect the environment by reflecting patterns of light onto adjacent surfaces (such
as a wall). In cases like these, we may have to consider each textured area as a separate surface and model
Incorporating texture mapping in HELIOS is not exactly a “simple modification." Balanced against this,
however, is the marked increase in realism that the technique offers. If you do decide to attempt this
One characterization of Gouraud shading is that the surfaces it renders appear uniformly lifeless. This is
due to the lack of specular highlights that we subconsciously expect to see in photorealistic images.
464 Looking to the Future
________________________________________________________________________
In ray tracing, one popular solution to this problem is the Phong illumination model (Phong [1975]). If
we consider the reflection of a ray of light from various surfaces (Fig. 8.1), we realize that a semi-specular
surface reflects some but not all of the light in a given direction. The more specular the surface, the more
light there will be reflected in the general direction of the specularly reflected ray.
Lv = ρ s Li (u v ⋅ u r ) f (8.2)
where L i is the luminance of a ray i emitted by a white light point source, Lv is the luminance of the ray v
seen by the viewer, ρ s is the specular reflectance of the surface (which can differ from the surface
reflectance), u v is a normalized vector pointing in the direction of the viewer, u r is a normalized vector
pointing in the direction of the reflected ray r, and f is a constant that determines the degree of specularity
If the specular reflectance is equal for all three color bands, the resultant reflection will have the same
spectral distribution as the light source. This will give the surface a plastic-looking finish. Alternatively,
the specular reflectance can be made the same as the surface reflctance. The surface will then appear to
n
r
i v
θ
ϕ ϕ
Surface
solving the radiosity equation gives us the diffuse exitance component for each vertex in the environment.
Using the existing code in our RayCast class, we can determine the visibility of each light source as seen
from each vertex. By modelling each source element as a point source located at the element’s center, we
can solve Equation 8.2 for any given viewpoint within the environment. This solves for the specular
exitance component at each vertex. Combining the diffuse and specular components for each vertex, we
can then use our Z-buffer and Gouraud shading algorithms as before to render an image.
As an alternative, and assuming that we have sufficient memory, we can store a linked list of light
source visibilities for each vertex when we perform our vertex-to-source form factor calculations. We
normally do not need much precision for the visibility value, so that one byte or even one bit could be used
It is important to note that the Phong illumination model does not consider semi-specular reflections
within the environment. This means that the resultant image will be somewhat ad hoc in that the radiosity
solution does not take these reflections into account. On the other hand, the amount of radiant flux
represented by the specular highlights is minuscule compared to the total amount of flux in the
environment, and so it has little if any effect on the radiosity solution. Indeed, the only reason for
incorporating Phong illumination is to provide the specular and semi-specular highlights that add to the
Some high-end workstations support both texture mapping and Phong illumination in hardware (see
Cohen and Wallace [1993] for implementation details). For the rest of us, we must replicate these features
in software. While it may be a non-trivial programming project, the increased realism of the rendered
Given the ease and speed with which simple radiosity environments can be rendered, you might
consider something more challenging. Creating a full-color image with subtle color bleeding effects and
realistic soft shadows is impressive enough. However, think of the possibilities in creating a “walkthrough”
orientations is trivial. Once the radiosity equation has been solved for a given environment, you can
repeatedly call the various SynCamera member functions to update the camera viewpoint and shoot
images.
From here, it is mostly an issue of recording the images in some suitable form. Given the appropriate
software and hardware, they can be written to a motion-compressed digital video file or sent frame by
frame to a video recorder. Depending on the supporting software provided by the hardware manufacturers,
Of course, this assumes that the radiosity equation needs to be solved only once for a static
Suppose we want to change the lighting as our camera moves through the environment. The form factor
matrix remains unchanged, but this is little consolation where progressive refinement radiosity is
concerned. In general, we have to solve the radiosity equation, form factors and all, whenever the initial
There are some shortcuts we can consider, however. To begin with, an environment with a single light
source will require no recalculation at all–we only need to dim or brighten the entire environment
accordingly when its initial exitance is changed. Of course, this will require a minor change to
ToneRep::Normalize to ensure that the bitmap pixel luminances are properly calculated.
A complex environment will likely have more than one light source. Changing the initial exitance of
one source will require us to find a new solution to the radiosity equation. However, we already have a
good approximation with the current solution. We can model the change in initial exitance as an additional
quantity of unsent exitance. This requires a minor change to RadEqnSolve::InitExitance to prevent it from
resetting the final vertex exitances. ProgRad::Calculate or RayCast::Calculate will then simply calculate
the changes in exitance and add them to the current solution. In most situations, the radiosity algorithm will
converge to a solution much more quickly, since the stopping criterion is still based on the total quantity of
[1990]). Several minor changes to the radiosity equation solver functions will be needed to accommodate
If there are many lighting changes to be modeled–theater lighting, for example–it may be useful to
calculate separate solutions for each individual group of light sources (Airey et al. [1990]). These solutions
are independent of one another. You can scale and sum them to represent any possible combination of light
sources and their initial exitances. Dorsey et al. [1991] and Dorsey [1993] describe a similar approach,
except that images are prerendered for a fixed camera position and each group of light sources. Lighting
changes can then be represented at interactive rates by simply blending the rendered images.
A second challenge comes when the surface reflectances are changed. One typical example is in
architectural design, where the viewer may want to compare the visual appearance of different wall or floor
finishes. Again, the form factor matrix remains unchanged. However, the solution may change drastically
if the surface area is large and its spectral reflectance in one or more color bands is changed by any
significant amount.
Once again, we have to solve the radiosity equation whenever a surface reflectance is changed. Chen
[1990] noted that the current solution often provides a good starting point, particularly when the number of
surfaces that have changed are small in number. From Equation 2.21, we know that the exitance of an
n
M i = M oi + ρ i ∑ M j Fij (8.3)
j =1
If we define M oi′ as the new initial exitance and ρi′ as the new reflectance of the element, then the
n
′ − M oi + (ρ i′ − ρ i )
∆M i = M oi ∑ M j Fij (8.4)
j =1
′ − M oi +
∆M i = M oi
(ρ i′ − ρ i )(M i − M oi ) (8.5)
ρi
468 Looking to the Future
________________________________________________________________________
where the current surface reflectance ρi is assumed to be greater than zero. We can add this value (which
may be negative) to the current calculated element exitance M i and also the unsent exitance of the parent
patch. From this, we can shoot the exitance until the radiosity algorithm converges to a new solution.
This technique becomes less helpful as the number of surfaces with changed reflectances or initial
exitances increases. Another, more general approach to this problem–eigenvector radiosity–is described by
DiLaura and Franck [1993]. It has the distinct advantage that its solution to the radiosity equation is
independent of the surface reflectances. In other words, the radiosity equation for a given environment only
has to be solved once. The effects of changing the surface reflectances or initial patch exitances can be
trivially solved thereafter. Unfortunately, it is a full radiosity method in that the entire form factor matrix
must be precalculated and stored in memory while the radiosity equation is being solved.
Changes to the geometry of the environment, even something as simple as moving one small object,
can have global effects on the radiosity solution. It can be difficult to predict these effects, especially when
the objects are close to a light source. Moving an object or modifying its geometry changes the form factor
As before, there are advantages in beginning with the current solution. If the changes to the radiosity
There are other possibilities. Baum et al. [1986] present an algorithm for situations where the changes
to the geometry are known in advance and can be precomputed. More general approaches are taken by
Chen [1990] and George et al. [1990], who discuss several techniques for isolating those portions of the
environment whose form factors are affected by moving, modifying, adding or deleting objects. Positive or
negative exitance is then shot as required to account for these changes. The discussions include practical
implementation details and pseudocode for algorithms that are unfortunately beyond the scope of this
book. If you need to account for geometric changes in the environment, however, these two references are
radiosity equation. While these are certainly the two most popular algorithms, there are others. They range
from simple probabilistic ray tracing techniques to bleeding-edge research in higher mathematics.
Monte Carlo radiosity takes a brute force approach to radiosity rendering. Like progressive refinement
radiosity, it begins by dividing surfaces into arrays of elements. It then shoots rays of light in random
directions from the light sources. Each ray is followed until it intersects a surface, at which point it is
multiplied by the surface reflectance and reshot. Again, a set of random rays is used. This is continued until
Monte Carlo radiosity is essentially a variant of progressive refinement radiosity, where the form
factors are implicitly calculated using ray casting. In pseudocode, the algorithm becomes (adapted from
Shirley [1991a]):
Send ∆Φ unsent
i to other elements
∆Φ unsent
i =0
ENDWHILE
FOR each element i
M i = Φ i Ai
ENDFOR
Figure 8.3 - Monte Carlo radiosity algorithm
Recalling that Φ i = M i Ai , this can be seen to be identical in outline to our progressive refinement
radiosity algorithm pseudocode in Figure 6.4. The only difference is the line “Send ∆Φ unsent
i to other
elements." Monte Carlo radiosity does this by dividing the flux into a number r of equal “packets” and
shooting each as a ray in a random direction from the element into the environment. The origin of the ray is
The random direction of the ray is weighted by the flux distribution or reflectance characteristics of the
source or reflecting surface. A Lambertian surface, for example, reflects flux in a cosine distribution (i.e.,
Lambert’s Cosine Law, Eqn. 1.9). Thus, the probability of a ray being shot at a vertical angle θ from the
Further implementation details are presented in Shirley [1991a]. Also, Ashdown [1992] presented an
Monte Carlo radiosity offers several important advantages in comparison to progressive refinement and
ray casting radiosity. First, there is no need to calculate form factors. This is done implicitly when the rays
Second, the Monte Carlo radiosity algorithm is not limited to modeling Lambertian light sources and
surfaces. The random ray direction weighting approximates the flux distribution or reflectance
characteristics of the light source or surface. This allows us to easily model semispecular surfaces and non-
Lambertian light sources. There are a variety of illumination models (e.g., Foley et al. [1990]) that can be
directly represented within the context of the Monte Carlo radiosity algorithm. Even transparent and fully
take a very large number of rays to accurately model the lighting of a complex environment. We are trading
the simplicity of ray tracing for long (and sometimes very long) execution times.
Feda and Purgathofer [1993] present an adaptation that adds an outer loop to the pseudocode shown in
Figure 8.3. More rays are shot at each iteration, thereby incrementally increasing the overall accuracy of
the solution while generating increasingly accurate intermediate images as the algorithm progresses. This
makes Monte Carlo radiosity somewhat more competitive with progressive refinement and ray casting
Further information and discussions of Monte Carlo radiosity can be found in Kajiyama and Kodaira
[1989], Pattanaik and Mudur [1992], Rushmeier [1986], Shirley [1990a-c], Shirley [1991b], Shirley et al.
[1991], Shirley and Wang [1991], Stanger [1984], Tregenza [1983] and Ward et al. [1988].
Finally, no discussion of Monte Carlo radiosity is complete without mentioning Radiance, a superlative
ray tracing program that incorporates a wide variety of shading and illumination models aimed at
Radiance was developed by Greg Ward of Lawrence Berkeley Laboratory under the sponsorship of the
U.S. Department of Energy. Originally written for UNIX-based platforms, it has since been ported to the
80x86 and Amiga environments. It is production-quality software with features that rival those of the best
commercial products.
The source code to Radiance is freely distributed, and is currently available on the Internet via
There are several other important but mathematically complex algorithms for solving the radiosity
equation. They are at the forefront of radiosity research and well beyond the scope of this text.
Nevertheless, a few brief comments are in order regarding their advantages and significance.
Hierarchical radiosity extends the concept of patches and elements to its logical limit. Recall from
Section 5.10 that patches were divided into elements in order to limit the number of element-to-element
472 Looking to the Future
________________________________________________________________________
form factors that must be calculated while solving the radiosity equation. As long as the Five Times Rule
(Section 5.5) is satisfied, we can group elements and calculate the form factor from an element to each
Suppose, however, that elements are grouped such that each element sees a minimum number of groups
where the Five Times Rule is still satisfied for each group. The two-level hierarchy of patches and
elements is extended to whatever depth is needed to link individual elements to appropriate groups of other
At first, this suggests the need for a truly gargantuan data structure of linked lists, possibly one for each
element. It also implies that every form factor has to be precomputed in order to group the elements seen
by each element.
Hanrahan and Salzman [1990a, b] and Hanrahan et al. [1991] demonstrated that this is not the case.
(See also Cohen and Wallace [1993] for a more accessible discussion and detailed pseudocode.) An
“oracle” function can be used to quickly estimate form factors and indicate which elements should be
grouped together. Furthermore, surfaces are adaptively subdivided into a hierarchy of elements, thereby
minimizing the number of elements needed to represent an environment. (Each element is subdivided into
at most four child elements.) In a test environment consisting of 98 polygons, their hierarchical radiosity
algorithm (Hanrahan et al. [1991]) created 4,280 elements arranged in a quadtree with 5,674 nodes, and
computed 11,800 element-to-element interactions. By comparison, a naive radiosity algorithm would have
There is a deeper mathematical basis to hierarchical radiosity than that of simply minimizing the
number of element-to-element form factor calculations. It can be described in terms of hierarchical “basis
functions” (e.g., Cohen and Wallace [1993]) that have interesting parallels with the mathematics of the Fast
Fourier Transform and various lossy image compression algorithms (such as the Discrete Cosine and Haar
transforms). This has led to the development of wavelet radiosity (Gortler et al. [1993b] and Galerkin
radiosity (Zatz [1993]). These in turn are related to the independently derived eigenvector radiosity
algorithm (DiLaura and Franck [1993]). This iterative algorithm has been recently superceded by a very
efficient direct algorithm (DiLaura [1994]) and a novel technique that precalculates much of the radiosity
equation solution for dynamic environments where changes in the environment geometry are likely.
Looking to the Future 473
________________________________________________________________________
Finally, there is importance-based radiosity (Smits et al. [1992]), which borrows its inspiration from the
nuclear physicist’s neutron transport theory. This radiosity method differs from those previously described
in that it generates view-dependent solutions. While this may limit its usefulness in some applications, it
offers an important advantage when extremely complex environments must be rendered. Importance-based
radiosity identifies those components of a scene that will significantly affect the radiosity solution for a
given viewpoint. This brings the number of elements that must be considered in form factor calculations
These advanced radiosity algorithms have only been introduced within the past two years, and are for
the most part ongoing research projects. Given time, they may lead to practical and useful radiosity
8.5 Conclusions
Shenchang Eric Chen (Chen [1991]) was right: implementing a radiosity program is indeed “an
enormous task.” It has taken us more than 500 pages and over 7,000 lines of C++ source code to develop
HELIOS. Even so, there are numerous finishing touches–in particular, anti-aliasing, integer-based polygon
fill, ray casting acceleration techniques, winged-edge data structures and adaptive subdivision–that had to
Despite these shortcomings, we can be proud of HELIOS. It opens the door to new opportunities in
computer graphics. It was not designed to be a “user friendly” (whatever that means) program for the
madding crowd. Rather, it is a software development platform, a testbed for your ideas and experiments
with radiosity.
The radiosity approach has been the domain of a small coterie of academic researchers for the past ten
years. We must thank these people for their interest in what was at first a mathematical curiosity, and their
dedication to transforming it into a powerful computer graphics tool. We must also encourage them to
continue their studies, for there are undoubtedly other fascinating and useful radiosity techniques still
waiting to be discovered.
For us, however, the excitement is here and now. This book has given you a lengthy and practical
introduction to the radiosity approach. If you want to learn more, begin with Cohen and Wallace [1993]–
474 Looking to the Future
________________________________________________________________________
there is no better introduction to the intricacies of advanced radiosity methods. Beyond this, there are many
excellent academic papers that cover all aspects of radiosity. The Bibliography lists most (but certainly not
all) of those that have been published to date. While some of them may be difficult to obtain, they all have
something to offer.
More to the point, however, we have HELIOS. This program–and this book–were written to bring
radiosity into the wider world of computer science students and those who love to program. Remember:
radiosity is easy to understand and fascinating to experiment with. Try HELIOS and see for yourself.
8.6 Postscript
At the risk of communication overload, the author extends an invitation to readers interested in sending
e-mail messages regarding the contents of this book. Bug reports, comments, and questions are welcomed.
(Please recognize, however, that questions regarding porting the code to different environments and
References
Airey, J.M., J.H. Rohlf and F.P. Brooks, Jr. [1990]. “Towards Image Realism with Interactive Update
Rates in Complex Virtual Building Environments”, Computer Graphics 24:1 (Proc. ACM Workshop on
Arvo, J., Ed. [1991]. Graphic Gems II, Academic Press, San Diego, CA.
Ashdown, I. [1992]. “Radiosity and Realism”, The C Users Journal 10:8 (August), 33 - 42.
Ashdown, I. [1993a]. “Near-Field Photometry: A New Approach”, Journal of the Illuminating Engineering
Ashdown, I. [1993b]. “Modeling Complex 3-D Light Sources”, ACM SIGGRAPH ‘93 Course 22 (Making
Aupperle, L. and P. Hanrahan [1993]. “A Hierarchical Illumination Algorithm for Surfaces with Glossy
Baranoski, G.V.G. [1992]. “The Parametric Differential Method: An Alternative to the Calculation of
Form Factors”, Computer Graphics Forum 11:3 (Proc. Eurographics ’92), C193 - C-204.
Baum, D.R., J.R. Wallace, M.F. Cohen and D.P. Greenberg [1986]. “The Back-Buffer Algorithm: An
Extension of the Radiosity Method to Dynamic Environments”, The Visual Computer 2, 298 - 306.
Baum, S.E. and J.M. Winget [1990]. “Real Time Radiosity Through Parallel Processing and Hardware
Bian, B., N. Wittels and D.S. Fussell [1992]. “Non-Uniform Patch Luminance for Global Illumination”,
Bouatouch, K. and C. Bouville, Eds. [1992]. Photorealism in Computer Graphics, Springer-Verlag, Berlin.
Bu, J. and E.F. Deprettere [1987a]. “A VLSI System Architecture for High-Speed Radiative Transfer 3D
Image Synthesis”, Eurographics ‘87 (Proc. European Computer Graphics Conference and Exhibition), G.
Marechal, Ed., Elsevier Science Publishers B.V. (North-Holland), Amsterdam, 221 - 235.
Bu, J. and E.F. Deprettere [1987b]. “A VLSI Algorithm for Computing Form-Factors in Radiative Transfer
Computer Image Synthesis”, Computer Graphics 1987 (Proc. CG International ‘87), T.L. Kunii, Ed.,
Chalmers, A.G. and D.J. Paddon [1991]. “Parallel Processing of Progressive Refinement Radiosity
Chen, H. and E. Wu [1990]. “An Efficient Radiosity Solution for Bump Texture Generation”, Computer
Chen, H. and E. Wu [1991]. “Radiosity for Furry Surfaces”, Eurographics ‘91 (Proc. European Computer
Graphics Conference and Exhibition), F.H. Post and W. Barth, Eds., Elsevier Science Publishers B.V.
Chen, S.E. [1990]. “Incremental Radiosity: An Extension of Progressive Radiosity to an Interactive Image
Synthesis System”, Computer Graphics 24:4 (Proc. ACM SIGGRAPH ‘90), 135 - 144.
Chen, S.E. [1989]. A Progressive Radiosity Method and Its Implementation in a Distributed Processing
Environment, Master’s Thesis, Program of Computer Graphics, Cornell University, Ithaca, NY.
476 Looking to the Future
________________________________________________________________________
Chen, S.E. [1991]. “Implementing Progressive Radiosity with User-Provided Polygon Display Routines”,
Chen, S.E., H.E. Rushmeier, G. Miller and D. Turner [1991]. “A Progressive Multi-Pass Method for
Global Illumination”, Computer Graphics 25:4 (Proc. ACM SIGGRAPH ‘91), 165 - 174.
Cohen, M.F., D.P. Greenberg, D.S. Immel and P.J. Brock [1986]. “An Efficient Radiosity Approach for
Realistic Image Synthesis”, IEEE Computer Graphics and Applications 6:3, 26 - 35.
Cohen, M.F. and J.R. Wallace [1993]. Radiosity and Realistic Image Synthesis, Academic Press, San
Diego, CA.
DiLaura, D.L. and P.J. Franck [1993]. “On Setting Up and Solving Large Radiative Transfer Systems”, J.
Dorsey, J. O’B. [1993]. Computer Graphics Techniques for Opera Lighting Design and Simulation, Ph.D.
Dorsey, J. O’B., F.X. Sillion and D.P. Greenberg [1991]. “Design and Simulation of Opera Lighting and
Projection Effects”, Computer Graphics 25:4 (Proc. ACM SIGGRAPH ‘91), 41 - 50.
Dretakkis, G. and E. Fiume [1991]. “Structure-Directed Sampling, Reconstruction and Data Representation
for Global Illumination”, Proc. Second Eurographics Workshop on Rendering, Barcelona, Spain.
Feda, M. and W. Purgathofer [1991]. “Progressive Refinement Radiosity on a Transputer Network”, Proc.
Feda, M. and W. Purgathofer [1993]. “Progressive Ray Refinement for Monte Carlo Radiosity”, Proc.
Foley, J.D., A. van Dam, S.K. Feiner and J.F. Hughes [1990]. Computer Graphics: Principles and Practice
George, D.W. [1990]. A Radiosity Redistribution Algorithm for Dynamic Environments, Master’s thesis,
George, D.W., F. X. Sillion and D.P. Greenberg [1990]. “Radiosity Redistribution in Dynamic
Greiner, G., W. Heidrich and P. Slusallek [1993], “Blockwise Refinement - A New Method for Solving the
Radiosity Problem”, Proc. Fourth Eurographics Workshop on Rendering, Paris, France, 233 - 245.
Guitton, P., J. Roman and C. Schlick [1991]. “Two Parallel Approaches for a Progressive Radiosity”, Proc.
Hall, D.E. and H.E. Rushmeier [1993]. “Improved Explicit Radiosity Method for Calculating Non-
Hammersley, J.M. and D.C. Handscomb [1964]. Monte Carlo Methods, Methuen, London.
Hanrahan, P. and D.B. Salzman [1990a]. A Rapid Hierarchical Radiosity Algorithm for Unoccluded
Hanrahan, P. and D. Salzman [1990b]. “A Rapid Hierarchical Radiosity Algorithm for Unoccluded
Hanrahan, P., D. Salzman and L. Aupperle [1991]. “A Rapid Hierarchical Radiosity Algorithm”, Computer
Heckbert, P.S. [1986]. “Survey of Texture Mapping”, IEEE Computer Graphics & Applications 6:11, 56 -
67.
Heckbert, P.S. [1990]. “Adaptive Radiosity Textures for Bidirectional Ray Tracing”, Computer Graphics
Hermitage, S.A., T.L. Huntsberger and B.A. Huntsberger [1990]. “Hypercube Algorithm for Radiosity in a
Ray Traced Environment”, Proc. Fifth Distributed Memory Computing Conference, IEEE Society Press,
206 - 211.
Immel, D.S., M.F. Cohen and D.P. Greenberg [1986]. “A Radiosity Method for Non-Diffuse
Environments”, Computer Graphics 20:4 (Proc. ACM SIGGRAPH ‘86), 133 - 142.
Jessel, J.P., M. Paulin and R. Caubet [1991]. “An Extended Radiosity Using Parallel Ray-Traced Specular
Kajiyama, H. and S. Kodaira [1989]. “An Illuminance Analysis in Partitioned Spaces Using the Monte
Kok, A.J.F. [1992]. “Grouping of Patches in Progressive Radiosity”, Proc. Fourth Eurographics Workshop
Kok, A.J.F., F.W. Jansen and C. Woodward [1993]. “Efficient, Complete Radiosity Ray Tracing Using a
Kok, A.J.F., A.C. Yilmaz and L.H.J. Bierens [1990]. “A Two-Pass Radiosity Method for Bézier Patches”,
Languénou, E. and P. Tellier [1992]. “Including Physical Light Sources and Daylight in Global
Illumination”, Proc. Third Eurographics Workshop on Rendering, Bristol, England, 217 - 225.
Le Saec, B. and C. Schlick [1990]. “A Progressive Ray Tracing Based Radiosity with General Reflectance
Lischinski, D., F. Tampieri and D.P. Greenberg [1993]. “Combining Hierarchical Radiosity and
Discontinuity Meshing”, Computer Graphics Proceedings (ACM SIGGRAPH ‘93), 199 - 208.
Neumann, L. and A. Neumann [1990]. “Efficient Radiosity Methods for Non-Separable Reflectance
Ng, A. and M. Slater [1993]. “A Multiprocessor Implementation of Radiosity”, Computer Graphics Forum
Pattanaik, S. and S. Mudur [1992]. “Computation of Global Illumination by Monte Carlo Simulation of the
Phong, B. [1975]. “Illumination for Computer Generated Images”, Comm. ACM 18:6, 311 - 317.
Price, M. and G. Truman [1989]. “Parallelism Makes Light Work”, Computer Graphics ‘89, November,
Purgathofer, W. and M. Zeller [1990]. “Fast Radiosity by Parallelization”, in Bouatouch and Bouville
Rushmeier, H., C. Patterson and A. Veerasamy [1993]. “Geometric Simplification for Indirect Illumination
Rushmeier, H. and K. Torrance [1987]. “The Zonal Method for Calculating Light Intensities in the
Presence of a Participating Medium”, Computer Graphics 21:4 (Proc. ACM SIGGRAPH ‘87), 293 - 302.
Rushmeier, H.E. and K.E. Torrance [1990]. “Extending the Radiosity Method to Include Specularly
Reflecting and Translucent Materials”, ACM Trans. Computer Graphics 9:1, 1 - 27.
Salesin, D., D. Lischinski and T. DeRose [1992]. “Reconstructing Illumination Functions with Selected
Shao, M. and N.I. Badler [1993b]. “Analysis and Acceleration of Progressive Refinement Radiosity
Shao, M., Q. Peng and Y. Liang [1988a]. “Form Factors for General Environments”, Eurographics ‘88
(Proc. European Computer Graphics Conference and Exhibition), D.A. Duce and P. Jancene, Eds., Elsevier
Shao, M., Q. Peng and Y. Liang [1988b]. “A New Radiosity Approach by Procedural Refinements for
Realistic Image Synthesis”, Computer Graphics 22:4 (Proc. ACM SIGGRAPH ‘88), 93 - 101.
Shen, L., E. Deprettere and P. Dewilde [1992]. “A New Space Partitioning for Mapping Computations of
the Radiosity Method onto a Highly Pipelined Parallel Architecture”, Advances in Computer Graphics V,
Shirley, P. [1990a]. Physically Based Lighting Calculations for Computer Graphics, Ph.D. Thesis, Dept. of
Shirley, P. [1990b]. “Physically Based Lighting Calculations for Computer Graphics: A Modern
Shirley, P. [1990c]. “A Ray Tracing Method for Illumination Calculation in Diffuse-Specular Scenes”,
Shirley, P. [1991a]. “Radiosity Via Ray Tracing”, in Arvo [1991], 306 - 310.
480 Looking to the Future
________________________________________________________________________
Shirley, P. [1991b]. “Time Complexity of Monte Carlo Radiosity”, Eurographics ‘91 (Proc. European
Computer Graphics Conference and Exhibition), F.H. Post and W. Barth, Eds., Elsevier Science Publishers
Shirley, P., K. Sung and W. Brown [1991]. “A Ray Tracing Framework for Global Illumination Systems”,
Shirley, P. and C. Wang [1991]. “Direct Lighting Calculations by Monte Carlo Integration”, Proc. Second
Sillion, F.X. and C. Puech [1989]. “A General Two-Pass Method Integrating Specular and Diffuse
Reflection”, Computer Graphics 23:3 (Proc. ACM SIGGRAPH ‘89), 335 - 344.
Sillion, F.X., J.R. Arvo, S.H. Westin and D.P. Greenberg [1991]. “A Global Illumination Solution for
General Reflectance Distributions”, Computer Graphics 25:4 (Proc. ACM SIGGRAPH ‘91), 187 - 196.
Smits, B.E., J.R. Arvo and D.H. Salesin [1992]. “An Importance-Driven Radiosity Algorithm”, Computer
Stanger, D. [1984]. “Monte Carlo Procedures in Lighting Design”, J. Illuminating Engineering Society
Tampieri, F. and D. Lischinski [1991]. “The Constant Radiosity Assumption Syndrome”, Proc. Second
Tregenza, P.R. [1983]. “The Monte Carlo Method in Lighting Calculations”, Lighting Research &
Troutman, R. and N. Max [1993]. “Radiosity Algorithms Using Higher Order Finite Element Methods”,
van Liere, R. [1991]. “Divide and Conquer Radiosity”, Proc. Second Eurographics Workshop on
Wallace, J.R., M.F. Cohen and D.P. Greenberg [1987]. “A Two-Pass Solution to the Rendering Equation:
A Synthesis of Ray Tracing and Radiosity Methods”, Computer Graphics 21:4 (Proc. ACM SIGGRAPH
Wang, M., H. Bao and Q. Peng [1992]. “A New Progressive Radiosity Algorithm Through the Use of
Wilt, N. [1993]. Objected-Oriented Ray Tracing in C++, Wiley, New York, NY.
Xu, H., Q.S. Peng and Y.D. Liang [1989]. “Accelerated Radiosity Method for Complex Environments”,
Eurographics ‘89 (Proc. European Computer Graphics Conference and Exhibition), W. Hansmann, F.R.A.
Hopgood and W. Strasser, Eds., Elsevier Science Publishers B.V. (North-Holland), Amsterdam, 51 - 61.
Zatz, H. [1993]. “Galerkin Radiosity: A Higher Order Solution Method for Global Illumination”,
Zhou, Y. and Q. Peng [1992]. “The Super-Plane Buffer: An Efficient Form-Factor Evaluation Algorithm
The photometric and radiometric definitions presented in Chapter One are those commonly used in
illumination engineering, and are in accordance with the American National Standards Institute publication
“Nomenclature and Definitions for Illuminating Engineering” (ANSI/IES [1986]). This booklet is a
veritable encyclopedia of photometric and radiometric terminology. However, interested readers are
As noted in Chapter One, the photometric and radiometric terminology presently used by the computer
graphics community differs somewhat from that promoted by ANSI/IES [1986]. The concepts are the
same; the differences are in name only. Hopefully this situation will change in the future–ANSI/IES [1986]
offers a consistent and useful set of definitions for both the computer graphics and illumination engineering
communities.
The following definitions have been excerpted (with some minor editing) from ANSI/IES [1986] with
3. Light
3.1 Light. Radiant energy that is capable of exciting the retina and producing a visual sensation. The
visible portion of the electromagnetic spectrum extends from about 380 to 770 nanometers.
3.2 Luminous flux Φ. Radiant flux (radiant power); the time rate of flow of radiant energy, evaluated in
terms of a standardized visual response.
Φν = Km ∫ΦeλV(λ)dλ
where
Φν = lumens
Φeλ = watts per nanometer
λ = nanometers
V(λ) = spectral luminous efficiency
Km = maximum spectral luminous efficacy in lumens/watt (lm/W)
Unless otherwise indicated, the luminous flux is defined for photopic vision. For scotopic vision, the
corresponding spectral luminous efficiency V’(λ) and the corresponding maximum spectral luminous
efficacy K’m are substituted in the above equation. Km and K’m are derived from the basic SI definition of
luminous intensity and have the values 683 lm/W and 1754 lm/W respectively.
3.2.1 Lumen, lm. SI unit of luminous flux. Radiometrically, it is determined from the radiant power.
Photometrically, it is the luminous flux emitted within a unit solid angle (one steradian) by a point source
having a uniform luminous intensity of one candela.
Photometric and Radiometric Definitions 485
________________________________________________________________________
3.3 Luminous flux density at a surface, dΦ/dA. The luminous flux per unit area at a point on a surface.
Note: This need not be a physical surface; it may also be a mathematical plane.
3.3.1 Illuminance, E = dΦ/dA. The areal density of the luminous flux incident at a point on a surface.
3.3.1.1 Illumination. An alternative, but deprecated, term for illuminance.
3.3.1.2 Lux, lx. The SI unit of illuminance. One lux is one lumen per square meter (lm/m2).
3.3.1.3 Footcandle, fc. A unit of illuminance. One footcandle is one lumen per square foot (lm/ft2).
3.3.2 Luminous exitance, M = dΦ/dA. The areal density of luminous flux leaving a surface at a point.
Formerly, luminous emittance (deprecated).
3.4 Luminous intensity, I = dΦ/dω (of a point source of light in a given direction). The luminous flux
per unit solid angle in the direction in question. Hence, it is the luminous flux on a small surface centered
on and normal to that direction divided by the solid angle (in steradians) which the surface subtends at the
source. Luminous intensity may be expressed in candelas or in lumens per steradian (lm/sr).
Note: Mathematically, a solid angle must have a point at its apex; the definition of luminous intensity,
therefore, applies strictly only to a point source. In practice, however, light emanating from a source
whose dimensions are negligible in comparison with the distance from which it is observed may be
considered as coming from a point. Specifically, this implies that with change of distance (1) the
variation in solid angle subtended by the source at the receiving point approaches 1/(distance)2; and that
(2) the average luminance of the projected source area as seen from the receiving point does not vary
appreciably.
The word intensity as defined above is used to designate luminous intensity (or candlepower). It is also
widely used in other ways ... Intensity has been used to designate the level of illuminance on a surface or
the flux density in the cross section of a beam of light. In physical optics, intensity usually refers to the
square of the wave amplitude.
3.4.1 Candela, cd. The SI unit of luminous intensity. One candela is one lumen per steradian (lm/sr).
Formerly, candle.
Note: The fundamental luminous intensity definition in the SI is the candela. The candela is the luminous
intensity, in a given direction of a source that emits monochromatic radiation of frequency 540 · 1012
Hertz that has a radiant intensity inn that direction of 1/683 watt per steradian.
3.4.2 Candlepower, cp. Luminous intensity expressed in candelas.
3.5 Luminance, L = d2Φ/(dωdA · cos θ) (in a direction and at a point on a real or imaginary surface).
See Fig. A.1. The quotient of the luminous flux at an element of the surface surrounding the point, and
propagated in directions defined by an elementary cone containing the given direction, by the product of
the solid angle of the cone and the area of orthogonal projection of the element of the surface on a plane
perpendicular to the given direction. The luminous flux may be leaving, passing through, and/or arriving at
the surface. Formerly, photometric brightness.
By introducing the concept of luminous intensity, luminance may be expressed as L = dI/(dA · cos θ).
Here, luminance at a point on a surface in a given direction is interpreted as the quotient of luminous
intensity in the given direction, produced by an element of the surface surrounding the point, by the area of
the orthogonal projection of the element of surface on a plane, perpendicular to the given direction.
(Luminance may be measured at the receiving surface by using
L = dE/(dω · cos θ)
This value may be less than the luminance of the emitting surface due to attenuation of the transmitting
media.)
3.5.1 SI unit of luminance. Candela per square meter (cd/m2).
3.5.2 Inch-pound (formerly English [USA]) unit of luminance. Candela per square foot (cd/ft2).
486 Photometric and Radiometric Definitions
________________________________________________________________________
N L
dφ
θ
dω
dA
3.8 Luminous sterisent, L*(x), (at a point along a ray path). Rate of increase in luminance, per unit path
length, at the point and in the direction of the ray, due to “generated” (emitted or scattered) luminance, or
the “generated” luminous intensity per unit volume, at the point and in the direction of the ray, by which a
distributed source can be characterized. L* = dLg/dx = dIg/dV, where dx is an element of distance along the
ray path, dV is an element of volume at the point, and the subscript g denotes a “generated” quantity.
3.9 Quantity of light (Luminous energy, Q = ∫Φdt). The product of the luminous flux by the time it is
maintained. It is the time integral of luminous flux.
3.10 Spectral luminous efficacy of radiant flux, K(λ) = Φνλ/Φeλ. The quotient of the luminous flux at a
given wavelength by the radiant flux at that wavelength. It is expressed in lumens per watt.
3.10.1 Spectral luminous efficiency of radiant flux. The ratio of the luminous efficacy for a given
wavelength to the value at the wavelength of maximum efficacy. It is dimensionless.
References
ANSI/IES [1986]. American National Standard Nomenclature and Definitions for Illuminating
Engineering, ANSI/IES RP-16-1986, Illuminating Engineering Society of North America, N.Y., N.Y.
Appendix B
Memory Management Issues
B.0 Introduction
Memory, memory and more memory. It always seems that our applications require more memory than
we currently have available. This curse of the computer is nowhere more evident than in radiosity
rendering. Depending on the radiosity methods we employ, we may need to store both vertices and form
factors as floating point data types for thousands to hundreds of thousands of polygons. Tens of megabytes
can disappear in the blink of an eye as a complex environment is read into memory.
While we may not be able to avoid these requirements, we can at least curb our programs’ appetite for
memory by carefully examining how memory is allocated, used and released. Dynamic memory allocation
is an obvious and well-documented candidate; other software engineering techniques include dynamic
For whatever reason, most C and C++ programming texts dismiss multidimensional arrays and memory
management in a few paragraphs. This is unfortunate in the extreme, since dynamic multidimensional
arrays and class-specific memory management techniques are essential to many computer graphics and
scientific programming applications. Thus, while they not be directly related to radiosity rendering
methods, we are advised to examine them carefully. The effective use of memory can make the difference
Calling new in C++ or malloc in C invokes the default memory manager provided by the compiler. This
gives us convenient and nearly transparent access to dynamically allocated memory blocks of almost any
size. It also, however, brings with it some hidden costs in terms of execution time and memory
requirements.
488 Memory Management Issues
________________________________________________________________________
When your program first starts, its memory manager receives a pointer to a large block of memory
(called the heap or free store) from the operating system. The memory manager then typically initializes
struct BlockHeader
{
size_t size; // Block size (less block header)
void *pnext; // Next block pointer
};
where size is set to the size of the block in bytes (less that occupied by the BlockHeader structure) and
pnext is set to NULL. It then saves a global FreeMemoryList pointer to this header.
A call to new or malloc with a request for n bytes results in the following sequence of events:
1. The size member of the block header pointed to by the FreeMemoryList pointer is compared to the
requested size n.
2. If size greater than n, then a null pointer is returned, indicating memory allocation failure.
3. The size member is set to n ; the n bytes following the block header will become the allocated memory
block.
4. Another block header is initialized, starting at n + sizeof(BlockHeader) bytes beyond the current block
header. The current header’s pnext pointer and the FreeMemoryList pointer are both set to point to this
new header.
5. The new header’s size member is set to the size of the remaining block in bytes, less
6. If the call was to new, the class constructor (if any) is executed to initialize the allocated block.
Successive calls to new or malloc results in the same sequence being repeated until the heap is exhausted,
Calling delete or free is more interesting. The pointer received is to the allocated block, but of course
the block header immediately precedes it in memory. The memory manager sets pnext to point to the block
header currently pointed to by FreeMemoryList, then sets FreeMemoryList to point to the allocated block.
This effectively frees the block by adding it to the linked list of free memory blocks. (If the next free block
Memory Management Issues 489
________________________________________________________________________
in the list immediately follows the current block in memory, the memory manager will likely coalesce the
two blocks into one by setting the current pnext to the value of the following block’s pnext pointer.)
Further calls to new or delete will now execute the above sequence of events with the exception of the
2. If size greater than n, then check the block header pointed to by pnext; continue doing so until either
size is less than or equal to n or pnext is NULL. If pnext is NULL, return a null pointer (no suitably-
The memory manager effectively walks the linked list of free memory blocks, looking for a free
There are several problems with this scheme. First, a hidden header block is used for every successful
allocation of memory. This may be only eight bytes or so in size, but it quickly adds up when many small
Second, it takes time to scan the free memory list looking for suitably sized blocks, particularly when a
large number of blocks have already been allocated. (This is more important in real-time systems, where
some functions may have to execute within specific and guaranteed time limits.)
Third, and most importantly, randomly allocating and releasing blocks of memory of varying sizes
quickly fragments the heap. The memory manager first looks for memory on the free memory list. If it
finds one that is larger than necessary, it simply splits it into two, allocating one block and adding the
second to the free memory list. The result is that each free block tends to become smaller and smaller until
adjacent blocks are releasing, whereupon they are coalesced into a larger block.
Finally, dynamically allocating large contiguous blocks of memory creates a certain amount of havoc
for the memory manager. To begin with, it may not be able to satisfy the allocation request if the heap is
too fragmented. There may be plenty of memory available, but only in small, scattered blocks. (Some
programming languages–Lisp, for example–support “garbage collection”, where the blocks of allocated
memory in the heap are physically copied to other locations such that the resulting free blocks can be
coalesced. This is impractical in C and C++, since it means that every pointer to dynamic memory has to be
allocated, this drastically limits the ability of the memory manager to allocate other blocks without running
There are two solutions to these problems. The simpler one involves a close look at how C and C++
address multidimensional arrays; the second is to write our own memory manager.
Multidimensional arrays are often required in computer graphics and scientific programming. With
access to megabytes of RAM, it becomes possible to solve large and complex problems quickly and
efficiently. However, both C and C++ make it difficult to dynamically allocate and access
multidimensional arrays unless the array dimensions are known at compile time. The general lack of
documentation on programming in C and C++ using multidimensional arrays only exacerbates the
problem.
The solution is to understand in detail how C and C++ access multidimensional arrays at run-time.
Consider this quote from “The Annotated C++ Reference Manual” (Ellis and Stroustrup [1990]):
int x[3][5];
Here x is a 3 × 5 array of integers. When x appears in an expression, it is converted to a pointer to (the first
of three) five-membered arrays of integers. In the expression x[i ] , which is equivalent to * (x + i ) , x is first
converted to a pointer as described; then x + i is converted to the type of x, which involves multiplying i
by the length of the object to which the pointer points, namely five integer objects. The results are added
and indirection applied to yield an array (of five integers), which in turn is converted to a pointer to the
first of the integers. If there is another subscript the same argument applies again; this time the result is an
integer.
It follows from all this that arrays in C++ are stored row-wise (last subscript varies fastest) and that the
first subscript in the declaration helps determine the amount of storage consumed by an array but plays no
other part in subscript calculations.
This explanation also applies to ISO Standard C (ISO/IEC [1990]) and the original Unix C (Kernighan
“ x[i ] … is equivalent to * (x + i ) ”
Memory Management Issues 491
________________________________________________________________________
Suppose we have a one-dimensional array F of n values. The data type doesn’t matter, but let’s make it
float for convenience. It can be dynamically allocated with a call to new or malloc (followed by casting to a
pointer to float). Unfortunately, we can only access F as a one-dimensional array of float values …
Not true! Suppose we also have a one-dimensional array D of m pointers to float, and that each points
to an element in F. Given an integer index i for D, we could access the element in F that D[i ] points to as:
value = *(D[i]);
value = D[i][0];
We could also use a second index j to access the jth element in F beyond D[i ] . This can be expressed
as:
or even:
value = D[i][j];
In other words, we can use two one-dimensional arrays to simulate a two-dimensional array. Each
pointer in D points to a fixed span of values in F (Fig. B.1). Furthermore, we never have to explicitly
access the second array F. Generalizing this approach, we can use n − 1 one-dimensional arrays of pointers
and a single one-dimensional array of values to simulate an n-dimensional array (e.g., Ashdown [1988]).
D 0 1 2 3
F 0 1 2 3 4 5 6 7 8 9 10 11
True multidimensional arrays are those that are statically allocated and optionally initialized at compile
time. They fill contiguous block of memory, and form part of the executable program that must be loaded
from disk along with the program code. The arrays themselves are stored in contiguous blocks of memory.
492 Memory Management Issues
________________________________________________________________________
The compiler must be told the sizes of the first n − 1 dimensions of a static n-dimensional array. With
these, it can calculate array offsets using integer multiplication and addition. These calculations can be
performed very quickly, especially if the code ends up being cached by the CPU.
The interesting point here is that while a multidimensional array subscript expression such as D[i ][ j ]
can be interpreted in terms of pointers and pointer arithmetic, the compiler only needs to access the address
Dynamically allocated multidimensional arrays are a different story. The compiler doesn’t know the
array dimensions, and so it must generates code to physically read each pointer implied by the expression
* (* (D + i ) + j ) . This may lead to slightly slower array access times if the necessary pointers aren’t stored
in the CPU’s internal cache. Usually, however, the difference in performance will negligible.
What does make a difference–a big difference–is that there is no requirement for F to be a single
contiguous array. In other words, each pointer in D can point to a separate one-dimensional array of values.
This allows the memory manager to allocate memory in small chunks, one row at a time. It’s the perfect
solution to the problem of dynamically allocating large arrays. It’s even better for MS-Windows 3.1
applications, since it allows us to evade the 64 Kbyte maximum array size limitation without declaring the
array as a _huge data type and suffering the considerable expense of _huge pointer arithmetic.
Another advantage of dynamically allocated multidimensional arrays is that the memory manager
considers each allocated row to be an independent block of memory. This allows truly gargantuan arrays to
be stored in virtual memory while still providing reasonably fast and efficient access to their row elements.
We used these techniques without fanfare in our PolyRender, HemiClip and CubicClip classes to
dynamically allocate depth buffers and delta form factor arrays. In PolyRender, it allowed us to allocate
arrays larger than 64 Kbytes under MS Windows 3.1. CubicClip made use of yet another advantage of
A seeming disadvantage of the cubic tetrahdral algorithm (Section 5.8) is that it requires a triangular
array in which to store delta form factors. We could of course use a square array and simply not use half of
it. However, this is an unnecessary waste of memory, particularly for high cubic tetrahedron resolutions.
Memory Management Issues 493
________________________________________________________________________
Figure B.1 shows each pointer in D pointing to a fixed span of values in F. In other words, each of the
“rows” in F has the same length. Clearly, however, this does not need to be the case. Each row can be
whatever length we choose. If we decrement the row length by one for each successive pointer in D, we
can simulate a triangular array with no wasted space other than the array of pointers needed for D itself.
We need to know the length of each row in F when we access it through D, but this is no different from our
need to know the number of rows and columns in a rectangular 2-D array.
A clear understanding of pointers and pointer arithmetic allows us to effectively manage dynamic
multidimensional arrays in C and C++. It’s only unfortunate that most programming texts fail to adequately
From our perspective of writing an efficient radiosity renderer, the default memory manager underlying
the global new and malloc operators has the undesirable trait of using a block header for every object it
allocates. It would be much better if we could allocate small objects (such as polygon vertices) as arrays
Fortunately, we can, and on a per-class basis. When it comes to memory management, C++ provides
the ultimate solution: if you don’t like how the default memory manager works for a particular class,
replace it with one of your own design by overloading new and delete.
Write your own memory manager? It’s not as onerous a project as you might think. Following an
example presented in Stroustrup [1991], a user-defined class with its own built-in memory manager can be
as simple as:
#include <stdlib.h>
class MyClass
{
private:
... class-specific data
public:
494 Memory Management Issues
________________________________________________________________________
... class-specific data access functions
return pfree;
}
The basis of this class is almost self-explanatory. Each MyClass object consists of user-defined data
and a pointer to the next object. There’s also a global MyClass object pointer called FreeListPtr that is
in a block of memory called a “chunk”. The call to new is not recursive; the default (i.e., global) new
As shown, there are 128 objects in a chunk. In practice, ObjectsPerChunk would be defined such that
the chunk is reasonably sized, say 4 Kbytes. The object pointers are initialized to form a linked list of
objects within the chunk, with the last object’s pointer set to NULL. The first object in the chunk is linked
Successive calls to new simply advance the FreeListPtr pointer and return a pointer to the next object in
the list. If the free object list is exhausted (i.e., the chunk is full), another chunk is allocated and the process
started over.
Calling delete links the object to be deleted to the head of the free object list, ready for the next call to
new. This means that after a while, the linked list of free objects may span several allocated chunks in
This is a very simple memory manager. Once a chunk has been allocated, there is no mechanism to
delete it short of program termination. You also can’t derive anything from MyClass without providing a
rewritten new operator, and even then you end up with multiple free memory lists, one for each class. It
would be more useful to have a generic memory manager that allocates several sizes of chunks for various
classes, depending on the size parameter passed to new. It should also indicates memory allocation failure
More comprehensive memory manager classes that perform intelligent chunk allocation are
occasionally presented in computer programming magazines. Examples include Burk and Custer [1992],
Peterson [1992] and Weller [1990]. The discussion provided by Burk and Custer is very informative and
well worth reading. Despite its title, their generic “chunk allocator” is applicable to any environment that
Our radiosity rendering program doesn’t need a chunk allocator, but it could benefit from a class-
specific memory managers for Vertex3 and Element3. Relying on the default memory manager incurs a
memory overhead of approximately 20 percent for each allocated object. The (incomplete) code in Figure
496 Memory Management Issues
________________________________________________________________________
B.2 outlines how these classes can be extended to include built-in memory management. The
References
Ashdown, I. [1988]. "Dynamic Multidimensional Arrays in C", Computer Language 5:6 (June), 83 - 88.
Burk, R. and H. Custer [1992]. “A Reusable C++ Chunk Allocator for DOS and Windows”, Windows/DOS
Ellis, M.A. and B. Stroustrup [1990]. The Annotated C++ Reference Manual, Addison-Wesley, Reading,
MA.
Kernighan, B.W. and D.M. Ritchie [1988]. The C Programming Language, 2nd Ed., Prentice Hall,
Peterson, M.E. [1992]. “WINMEM: An Efficient Subsegment Memory Allocator for Windows 3.x”,
Stroustrup, B. [1991]. The C++ Programming Language, 2nd Ed., Addison-Wesley, Reading, MA.
Weller, S. [1990]. “Fast Memory Allocation Scheme”, The C Users Journal 8:4 (April), 103 - 107.
Bibliography
Águas, M.P.N. and S. Müller [1993]. “Mesh Redistribution in Radiosity”, Proc. Fourth Eurographics
Airey, J.M. and M. Ouh-young [1989]. “Two Adaptive Techniques Let Progressive Radiosity Outperform
the Traditional Radiosity Algorithm”, U. of North Carolina Dept. of Computer Science Technical Report
TR89-020.
Airey, J.M., J.H. Rohlf and F.P. Brooks, Jr. [1990]. “Towards Image Realism with Interactive Update
Rates in Complex Virtual Building Environments”, Computer Graphics 24:1 (Proc. ACM Workshop on
Anderson, A. and M. Grant [1991]. “VISULUX: A Radiosity Based Lighting Design Tool”, Proc. Second
Arnauldi, B., X. Pueyo and J. Vilaplana [1991]. “On the Division of Environments by Virtual Walls for
Arvo, J., Ed. [1991]. Graphic Gems II, Academic Press, San Diego, CA.
Asensio, A.F. [1992]. “A Hierarchical Ray-Casting Algorithm for Radiosity Shadows”, Proc. Third
Ashdown, I. [1992]. “Radiosity and Realism”, The C Users Journal 10:8 (August), 33 - 42.
Ashdown, I. [1993a]. “Near-Field Photometry: A New Approach”, Journal of the Illuminating Engineering
Ashdown, I. [1993b]. “Modeling Complex 3-D Light Sources”, ACM SIGGRAPH ‘93 Course 22 (Making
Aupperle, L. and P. Hanrahan [1993a]. “Importance and Discrete Three Point Transport”, Proc. Fourth
Bao, H. and Q. Peng [1993a]. “Shading Models for Linear and Area Light Sources”, Computers &
Bao, H. and Q. Peng [1993b]. “A Progressive Radiosity Algorithm for Scenes Containing Curved
Surfaces”, Computer Graphics Forum 12:3 (Proc. Eurogrpahics ‘93), C-399 - C-408.
Bastos, R.M., A.A. de Sousa and F.N. Ferreira [1993]. “Reconstruction of Illumination Functions Using
Bicbic Hermite Interpolation”, Proc. Fourth Eurographics Workshop on Rendering, Paris, France, 317 -
324.
Baranoski, G.V.G. [1992]. “The Parametric Differential Method: An Alternative to the Calculation of
Form Factors”, Computer Graphics Forum 11:3 (Proc. Eurographics ‘92), C193 - C-204.
Baum, D.R., S. Mann, K.P. Smith and J.M. Winget [1991]. “Making Radiosity Usable: Automatic
Preprocessing and Meshing Techniques for the Generation of Accurate Radiosity Solutions”, Computer
Baum, D.R., H.E. Rushmeier and J.M. Winget [1989]. “Improving Radiosity Solutions Through the Use of
Analytically Determined Form Factors”, Computer Graphics 23:3 (Proc. ACM SIGGRAPH ‘89), 325 -
334.
Baum, D.R., J.R. Wallace, M.F. Cohen and D.P. Greenberg [1986]. “The Back-Buffer Algorithm: An
Extension of the Radiosity Method to Dynamic Environments”, The Visual Computer 2:5, 298 - 306.
Baum, S.E. and J.M. Winget [1990]. “Real Time Radiosity Through Parallel Processing and Hardware
Beran-Koehn, J.C. and M.J. Pavicic [1991]. “A Cubic Tetrahedral Adaptation of the Hemi-Cube
Beran-Koehn, J.C. and M.J. Pavicic [1992], “Delta Form-Factor Calculation for the Cubic Tetrahedral
Bhate, N. and A. Tokuta [1992]. “Photorealistic Volume Rendering of Media with Directional Scattering”,
Bian, B. [1990]. Accurate Simulation of Scene Luminance, Ph.D. Thesis, Worcester Polytechnic Institute,
Worcester, MA.
Bian, B. [1992]. “Hemispherical Projection of a Triangle”, in Kirk [1992], 314 - 317, 569 - 574.
Bian, B., N. Wittels and D.S. Fussell [1991]. “Accurate Image Simulation by Hemisphere Projection”,
Bian, B., N. Wittels and D.S. Fussell [1992]. “Non-Uniform Patch Luminance for Global Illumination”,
Borel, C.C., S.A.W. Gerstl and B.J. Powers [1991]. “The Radiosity Method in Optical Remote Sensing of
Borel, C.C. and S.A.W. Gerstl [1991]. “Simulation of Partially Obscured Scenes Using the Radiosity
Method”, Proc. SPIE on Characterization, Propagation, and Simulation of Sources and Backgrounds Vol.
1486, 271-277.
Bouatouch, K. and C. Bouville, Eds. [1992]. Photorealism in Computer Graphics, Springer-Verlag, Berlin.
Bouatouch, K. and P. Tellier [1992]. “A Two-Pass Physics-Based Global Lighting Model”, Graphics
Bouville, C., K. Bouatouch, P. Tellier and X. Pueyo [1990]. “A Theoretical Analysis of Global
Bu, J. and E.F. Deprettere [1987a]. “A VLSI System Architecture for High-Speed Radiative Transfer 3D
Image Synthesis”, Eurographics ‘87 (Proc. European Computer Graphics Conference and Exhibition), G.
Marechal, Ed., Elsevier Science Publishers B.V. (North-Holland), Amsterdam, 221 - 235.
500 Bibliography
________________________________________________________________________
Bu, J. and E.F. Deprettere [1987b]. “A VLSI Algorithm for Computing Form-Factors in Radiative Transfer
Computer Image Synthesis”, Computer Graphics 1987 (Proc. CG International ‘87), T.L. Kunii, Ed.,
Bu, J. and E.F. Deprettere [1989]. “A VLSI System Architecture for High-speed Radiative Transfer 3D
Buckalew, C. [1990]. Illumination Networks, Ph.D. Thesis, U. of Texas at Austin, Austin, TX.
Buckalew, C. and D.S. Fussell [1989]. “Illumination Networks: Fast Realistic Rendering with General
Reflectance Functions”, Computers Graphics 23:3 (Proc. ACM SIGGRAPH ‘89), 89 - 98.
Buckalew, C. and D.S. Fussell [1990]. An Energy-Balance Method for Animation, Technical Report TR-
Bullis, J.M. [1989]. Models and Algorithms for Computing Realistic Images Containing Diffuse
Campbell, A.T. III [1991a]. Modeling Global Diffuse Illumination for Image Synthesis, Ph.D. Thesis, U. of
Campbell, A.T., III and D.S. Fussell [1990]. “Adaptive Mesh Generation for Global Diffuse Illumination”,
Carter, M.B. and J.L. Gustafson [1993a]. The Symmetric Radiosity Formulation, Technical Report IS-J
Carter, M.B. and J.L. Gustafson [1993b]. An Improved Hierarchical Radiosity Method, Technical Report
Chalmers, A.G. and D.J. Paddon [1991]. “Parallel Processing of Progressive Refinement Radiosity
Chen, H. and E. Wu [1990a]. “An Efficient Radiosity Solution for Bump Texture Generation”, Computer
Chen, H. and E. Wu [1991]. “Radiosity for Furry Surfaces”, Eurographics ‘91 (Proc. European Computer
Graphics Conference and Exhibition), F.H. Post and W. Barth, Eds., Elsevier Science Publishers B.V.
Chen, S.E. [1989]. A Progressive Radiosity Method and Its Implementation in a Distributed Processing
Environment, Master’s Thesis, Program of Computer Graphics, Cornell University, Ithaca, NY.
Chen, S.E. [1990]. “Incremental Radiosity: An Extension of Progressive Radiosity to an Interactive Image
Synthesis System”, Computer Graphics 24:4 (Proc. ACM SIGGRAPH ‘90), 135 - 144.
Chen, S.E. [1991]. “Implementing Progressive Radiosity with User-Provided Polygon Display Routines”,
Chen, S.E., H.E. Rushmeier, G. Miller and D. Turner [1991]. “A Progressive Multi-Pass Method for
Global Illumination”, Computer Graphics 25:4 (Proc. ACM SIGGRAPH ‘91), 165 - 174.
Christensen, P.H., D.H. Salesin and T.D. DeRose [1993]. “A Continuous Adjoint Formulation for
Radiance Transport”, Proc. Fourth Eurographics Workshop on Rendering, Paris, France, 95 - 104.
Chua, T.S. and T.L. Kunii [1990]. CG International ‘90: Computer Graphics Around the World, Springer-
Cohen, M.F. [1985]. A Radiosity Method for the Realistic Image Synthesis of Complex Environments,
Cohen, M.F. and D.P. Greenberg [1985]. “The Hemi-Cube: A Radiosity Solution for Complex
Cohen, M.F., D.P. Greenberg, D.S. Immel and P.J. Brock [1986]. “An Efficient Radiosity Approach for
Realistic Image Synthesis”, IEEE Computer Graphics and Applications 6:3, 26 - 35.
502 Bibliography
________________________________________________________________________
Cohen, M.F., S.E. Chen, J.R. Wallace and D.P. Greenberg [1988]. “A Progressive Refinement Approach to
Fast Radiosity Image Generation”, Computer Graphics 22:4 (Proc. ACM SIGGRAPH ‘88), 75 - 84.
DiLaura, D.L. [1992]. “On the Development of a Recursive Method for the Solution of Radiative Transfer
DiLaura, D.L. and P. Franck [1993]. “On Setting Up and Solving Large Radiative Transfer Systems”, J.
Dorsey, J. O’B. [1993]. Computer Graphics Techniques for Opera Lighting Design and Simulation, Ph.D.
Dorsey, J. O’B., F.X. Sillion and D.P. Greenberg [1991]. “Design and Simulation of Opera Lighting and
Projection Effects”, Computer Graphics 25:4 (Proc. ACM SIGGRAPH ‘91), 41 - 50.
Drettakis, G. and E. Fiume [1991]. “Structure-Directed Sampling, Reconstruction and Data Representation
for Global Illumination”, Proc. Second Eurographics Workshop on Rendering, Barcelona, Spain, 189 -
201.
Drettakis, G. and E. Fiume [1992]. “Concrete Computation of Global Illumination Using Structured
Drettakis, G. and E. Fiume [1993]. “Accurate and Consistent Reconstruction of Illumination Functions
Using Structured Sampling”, Computer Graphics Forum 12:3 (Eurographics ‘93), 273 - 284.
Drucker, S.M. and P. Schröeder [1992], “Fast Radiosity Using a Data Parallel Architecture”, Proc. Third
Emery, A.F., O. Johansson, M. Lobo and A. Abrous [1991]. “A Comparative Study of Methods for
Computing the Diffuse Radiation Viewfactors for Complex Structures”, J. Heat Transfer 113, 413 - 422.
Feda, M. and W. Purgathofer [1991]. “Progressive Refinement Radiosity on a Transputer Network”, Proc.
Foley, J.D., A. van Dam, S.K. Feiner and J.F. Hughes [1990]. Computer Graphics: Principles and Practice
Franck, P. [1990]. Mathematical Approaches to Solving the Luminous Radiative Transfer Problem,
Independent Study Report, Dept. of Civil and Architectural Engineering, U. of Colorado, Boulder, CO.
Gatenby, N. and W.T. Hewitt [1991]. “Radiosity in Computer Graphics: A Proposed Alternative to the
George, D.W. [1990]. A Radiosity Redistribution Algorithm for Dynamic Environments, Master’s Thesis,
George, D.W., F. X. Sillion and D.P. Greenberg [1990]. “Radiosity Redistribution in Dynamic
Goldfeather, J. [1989]. Progressive Radiosity Using Hemispheres, Technical Report TR89-002, Dept. of
Goral, C. [1985]. A Model for the Interaction of Light Between Diffuse Surfaces, Master’s Thesis, Program
Goral, C. M., K.E. Torrance, D.P. Greenberg and B. Battaile [1984]. “Modeling the Interaction of Light
Between Diffuse Surfaces”, Computer Graphics 18:3 (Proc. ACM SIGGRAPH ‘84), 213 - 222.
Gortler, S. and M.F. Cohen [1993]. Radiosity and Relaxation Methods: Progressive Refinement is
Gortler, S.J., P. Schröder, M.F. Cohen and P. Hanrahan [1993]. “Wavelet Radiosity”, Computer Graphics
Greene, N., M. Kass and G. Miller 1993]. “Hierarchical Z-Buffer Visibility”, Computer Graphics
Greenberg, D.P. and F. Sillion [1991]. Global Illumination Algorithms, Eurographics Technical Report EG
Greiner, G., W. Heidrich and P. Slusallek [1993], “Blockwise Refinement - A New Method for Solving the
Radiosity Problem”, Proc. Fourth Eurographics Workshop on Rendering, Paris, France, 233 - 245.
Guitton, P., J. Roman and C. Schlick [1991]. “Two Parallel Approaches for a Progressive Radiosity”, Proc.
Haines, E. and J. Wallace [1991]. “Shaft Culling for Efficient Ray-Traced Radiosity”, Proc. Second
Hall, D.E. [1990]. An Analysis and Modification of Shao’s Radiosity Method for Computer Graphics
Image Synthesis, Master’s Thesis, School of Mechanical Engineering, Georgia Institute of Technology.
Hall, D.E. and H.E. Rushmeier [1993]. “Improved Explicit Radiosity Method for Calculating Non-
Hall, R. [1989]. Illumination and Color in Computer Generated Imagery, Springer-Verlag, New York,
NY.
Hamid, T.P. [1988]. The Radiosity Model, Project Report, Dept. of Computer Science, U. of Glasgow,
Glasgow, Scotland.
Hanrahan, P. and D.B. Salzman [1990a]. A Rapid Hierarchical Radiosity Algorithm for Unoccluded
Hanrahan, P. and D. Salzman [1990b]. “A Rapid Hierarchical Radiosity Algorithm for Unoccluded
Hanrahan, P., D. Salzman and L. Aupperle [1991]. “A Rapid Hierarchical Radiosity Algorithm”, Computer
Heckbert, P.S. [1991]. Simulating Global Illumination Using Adaptive Meshing, Ph.D. Thesis, U. of
Heckbert, P.S. [1992a]. “Discontinuity Meshing for Radiosity”, Proc. Third Eurographics Workshop on
Heckbert, P. [1992b]. “Radiosity in Flatland”, Computer Graphics Forum 11:3 (Proc. Eurographics ‘92),
C-181 - C-192.
Heckbert, P.S. and J.M. Winget [1991]. “Finite Element Methods for Global Illumination”, U. of
Hermitage, S.A., T.L. Huntsberger and B.A. Huntsberger [1990]. “Hypercube Algorithm for Radiosity in a
Ray Traced Environment”, Proc. Fifth Distributed Memory Computing Conference, IEEE Society Press,
206 - 211.
Immel, D.S., M.F. Cohen and D.P. Greenberg [1986]. “A Radiosity Method for Non-Diffuse
Environments”, Computer Graphics 20:4 (Proc. ACM SIGGRAPH ‘86), 133 - 142.
Jessel, J.P., M. Paulin and R. Caubet [1991]. “An Extended Radiosity Using Parallel Ray-Traced Specular
Jones, G.R., C.G. Christou, B.G. Cumming, A.J. Parker and A. Zisserman [1993]. “Accurate Rendering of
Curved Shadows and Interreflections”, Proc. Fourth Eurographics Workshop on Rendering, Paris, France,
337 - 347
Kajiya, J.T. [1986]. “The Rendering Equation”, Computer Graphics 20:4 (Proc. ACM SIGGRAPH ‘86),
143 - 150.
Kajiyama, H. and S. Kodaira [1989]. “An Illuminance Analysis in Partitioned Spaces Using the Monte
Kirk, D., Ed. [1992]. Graphic Gems III, Academic Press, San Diego, CA.
Kokcsis, F. and J.F. Böhme [1992]. “Fast Algorithms and Parallel Structures for Form Factor Evaluation”,
Kok, A.J.F. [1992a]. “Grouping of Patches in Progressive Radiosity”, Proc. Fourth Eurographics
Kok, A.J.F. and F.W. Jansen [1992b]. “Adaptive Sampling of Area Light Sources in Ray Tracing
Including Diffuse Interreflection”, Computer Graphics Forum 11:3 (Eurographics '92), 289-298.
Kok, A.J.F., F.W. Jansen and C. Woodward [1993]. “Efficient, Complete Radiosity Ray Tracing Using a
Kok, A.J.F., A.C. Yilmaz and L.H.J. Bierens [1990]. “A Two-Pass Radiosity Method for Bézier Patches”,
Kok, A.J.F, C. Yilmaz and L.H.J. Bierens [1991]. “Source Selection for the Direct Lighting Computation
Kwok, B. [1992]. Analysis of Radiosity Techniques in Computer Graphics, Master’s Thesis, York
Lalonde, P. [1993]. “An Adaptive Discretization Method for Progressive Radiosity”, Graphics Interface
Languénou, E., K. Bouatouch and P. Tellier [1992]. “An Adaptive Discretization Method for Radiosity”,
Languénou, E. and P. Tellier [1992]. “Including Physical Light Sources and Daylight in Global
Illumination”, Proc. Third Eurographics Workshop on Rendering, Bristol, UK, 217 - 225.
Le Saec, B. and C. Schlick [1990]. “A Progressive Ray Tracing Based Radiosity with General Reflectance
Lischinski, D., F. Tampieri and D.P. Greenberg [1991]. Improving Sampling and Reconstruction
Techniques for Radiosity, Tech. Report 91-1202, Dept. of Computer Science, Cornell University, Ithaca,
NY.
Lischinski, D., F. Tampieri and D.P. Greenberg [1992]. “Discontinuity Meshing for Accurate Radiosity”,
Lischinski, D., F. Tampieri and D.P. Greenberg [1993]. “Combining Hierarchical Radiosity and
Discontinuity Meshing”, Computer Graphics Proceedings (ACM SIGGRAPH ‘93), 199 - 208.
Magnenat-Thalmann, N. and D. Thalmann [1987]. Image Synthesis: Theory and Practice, Springer-Verlag,
Tokyo, Japan.
Max, N.L. and M.J. Allison [1992]. “Linear Radiosity Approximation Using Vertex-to-Vertex Form
Max, N. and R. Troutman [1993]. “Optimal Hemicube Sampling”, Proc. Fourth Eurographics Workshop
Maxwell, G.M., M.J. Bailey and V.W. Goldschmidt [1986]. “Calculations of the Radiation Configuration
Meyer, G.W., H.E. Rushmeier, M.F. Cohen, D.P. Greenberg and K.E. Torrance [1986]. “An Experimental
Evaluation of Computer Graphics Imagery”, ACM Trans. Computer Graphics 5:1, 30 - 50.
Michelin, S., G. Maffies, D. Arques and J.C. Grossetie [1993]. “Form Factor Calculation: A New
Expression with Implementations on a Parallel T.Node Computer”, Computer Graphics Forum 12:3,
Mistrick, R.G. and D.L. DiLaura [1987]. “A New Finite Orthogonal Transform Applied to Radiative
Barcelona, Spain.
Neumann, L. and A. Neumann [1990]. “Efficient Radiosity Methods for Non-Separable Reflectance
Ng, A. and M. Slater [1993]. “A Multiprocessor Implementation of Radiosity”, Computer Graphics Forum
Taking Account of Shadows and Interreflection”, Computer Graphics 19:3 (Proc. ACM SIGGRAPH ‘85),
23 - 30.
Nishita, T. and E. Nakamae [1993]. “A New Radiosity Apporach Using Area Sampling for Parametric
Paddon, D. [1993]. “Multiprocessor Models for the Radiosity Method”, First Bilkent Computer Graphics
Pattanaik, S. [1990]. Computational Methods for Global Illumination and Visualization of Complex 3D
Environments, Ph.D. Thesis, Birla Institute of Technology and Science, Pilani, India.
Pattanaik, S. and S. Mudur [1992]. “Computation of Global Illumination by Monte Carlo Simulation of the
Particle Light”, Proc. Third Eurographics Workshop on Rendering, Bristol, UK, 71 - 83.
Pattanaik, S. and S. Mudur [1993a]. “Efficient Potential Equation Solutions for Global Illumination
Pattanaik, S. and S. Mudur [1993b]. “The Potential Equation and Importance in Illumination
and Their Surroundings”, J. American Society of Agricultural Engineering Tech. Report 59-323.
Priol, T., K. Bouatouch and D. Menard [1993]. “Parallel Radiosity Using a Shared Virtual Memory”, First
Pietrek, G. [1993]. “Fast Calculation of Accurate Formfactors”, Proc. Fourth Eurographics Workshop on
Price, M. and G. Truman [1989]. “Parallelism Makes Light Work”, Computer Graphics ‘89, November,
Puech, C., F. Sillion and C. Vedel [1990]. “Improving Interaction with Radiosity-based Lighting
Simulation Programs”, Computer Graphics 24:1 (Proc. ACM Workshop on Interactive Graphics), 51- 57.
Pueyo, X. [1991]. “Diffuse Interreflections. Techniques for Form-factor Computation: A Survey”, The
Purgathofer, W. and M. Zeller [1990]. “Fast Radiosity by Parallelization”, in Bouatouch and Bouville
Recker, R.J. [1990]. Improved Techniques for Progressive Refinement Radiosity, Master’s Thesis, Program
Recker, R.J., D.W. George and D.P. Greenberg [1990]. “Acceleration Techniques for Progressive
Refinement Radiosity”, Computer Graphics 24:2 (1990 Symposium on Interactive 3D Graphics), 59 - 66.
Reichert, M. [1992]. A Two-Pass Radiosity Method Driven by Lights and Viewer Position, Master’s
Rogers, D.E. and R.A. Earnshaw [1991]. State of the Art in Computer Graphics: Visualization and
Rushmeier, H. [1988]. Realistic Image Synthesis for Scenes with Radiatively Participating Media, Ph.D.
Rushmeier, H., C. Patterson and A. Veerasamy [1993]. “Geometric Simplification for Indirect Illumination
Rushmeier, H. and K. Torrance [1987]. “The Zonal Method for Calculating Light Intensities in the
Presence of a Participating Medium”, Computer Graphics 21:4 (Proc. ACM SIGGRAPH ‘87), 293 - 302.
Rushmeier, H.E. and K.E. Torrance [1990]. “Extending the Radiosity Method to Include Specularly
Reflecting and Translucent Materials”, ACM Trans. Computer Graphics 9:1, 1 - 27.
Salesin, D., D. Lischinski and T. DeRose [1992]. “Reconstructing Illumination Functions with Selected
Sbert, M. [1993]. “An Integral Geometry Based Method for Fast Form-Factor Computation”, Computer
Schröder, P. [1993]. “Numerical Integration for Radiosity in the Presence of Singularities”, Proc. Fourth
Schröder, P., S.J. Gortler, M.F. Cohen and P. Hanrahan [1993]. “Wavelet Projections for Radiosity”, Proc.
Schuierer, S. [1989]. “Delaunay Triangulations and the Radiosity Approach”, Eurographics ‘89 (Proc.
European Computer Graphics Conference and Exhibition), W. Hansmann, F.R.A. Hopgood and W.
Strasser, Eds., Elsevier Science Publishers B.V. (North-Holland), Amsterdam, 345 - 353.
Shao, M. and N.I. Badler [1993a]. A Gathering and Shooting Progressive Refinement Radiosity Method,
Pennsylvania.
Shao, M. and N.I. Badler [1993b]. “Analysis and Acceleration of Progressive Refinement Radiosity
Method”, Proc. Fourth Eurographics Workshop on Rendering, Paris, France, 247 - 258.
Bibliography 511
________________________________________________________________________
Shao, M., Q. Peng and Y. Liang [1988a]. “Form Factors for General Environments”, Eurographics ‘88
(Proc. European Computer Graphics Conference and Exhibition), D.A. Duce and P. Jancene, Eds., Elsevier
Shao, M., Q. Peng and Y. Liang [1988b]. “A New Radiosity Approach by Procedural Refinements for
Realistic Image Synthesis”, Computer Graphics 22:4 (Proc. ACM SIGGRAPH ‘88), 93 - 101.
Shen, L., E. Deprettere and P. Dewilde [1992]. “A New Space Partitioning for Mapping Computations of
the Radiosity Method onto a Highly Pipelined Parallel Architecture”, Advances in Computer Graphics V,
Shirley, P. [1990a]. Physically Based Lighting Calculations for Computer Graphics, Ph.D. Thesis, Dept. of
Shirley, P. [1990b]. “Physically Based Lighting Calculations for Computer Graphics: A Modern
Shirley, P. [1990c]. “A Ray Tracing Method for Illumination Calculation in Diffuse-Specular Scenes”,
Shirley, P. [1991a]. “Radiosity Via Ray Tracing”, in Arvo [1991], 306 - 310.
Shirley, P. [1991b]. “Time Complexity of Monte Carlo Radiosity”, Eurographics ‘91 (Proc. European
Computer Graphics Conference and Exhibition), F.H. Post and W. Barth, Eds., Elsevier Science Publishers
Shirley, P., K. Sung and W. Brown [1991]. “A Ray Tracing Framework for Global Illumination Systems”,
Shirley, P. and C. Wang [1991]. “Direct Lighting Calculations by Monte Carlo Integration”, Proc. Second
Siegel, R. and J.R. Howell [1992]. Thermal Radiation Heat Transfer, Third Edition, Hemisphere
311 - 315.
Sillion, F.X. and C. Puech [1989]. “A General Two-Pass Method Integrating Specular and Diffuse
Reflection”, Computer Graphics 23:3 (Proc. ACM SIGGRAPH ‘89), 335 - 344.
Sillion, F.X. and C. Puech [1994]. Radiosity and Global Illumination, Morgan Kaufmann, San Mateo, CA.
Sillion, F.X., J.R. Arvo, S.H. Westin and D.P. Greenberg [1991]. “A Global Illumination Solution for
General Reflectance Distributions”, Computer Graphics 25:4 (Proc. ACM SIGGRAPH ‘91), 187 - 196.
Smith, K.P. [1991]. “Fast and Accurate Radiosity-Based Rendering”, Master’s Project Report, U. of
Smits, B.E., J.R. Arvo and D.H. Salesin [1992]. “An Importance-Driven Radiosity Algorithm”, Computer
Spencer, S. [1990]. “The Hemisphere Radiosity Method: A Tale of Two Algorithms”, in Bouatouch and
Sturzlinger, W. “Radiosity with Voronoi Diagrams”, Proc. Third Eurographics Workshop on Rendering,
Sun, J., L.Q. Zou and R.L. Grimsdale [1993]. “The Determination of Form-Factors by Lookup Table”,
Tampieri, F. [1990]. Global Illumination Algorithms for Parallel Computer Architectures, Master's Thesis,
Tampieri, F. [1991]. “Fast Vertex Radiosity Update”, in Arvo [1991], 303 - 305, 598.
Tampieri, F. [1992]. “Accurate Form-Factor Computation”, in Kirk [1992], 329 - 333, 577 - 581.
Tampieri, F. [1993]. Discontinuity Meshing for Radiosity Image Synthesis, Ph.D. Thesis, Cornell
Teller, S.J. [1991]. Computing the Antipenumbra of an Area Light Source, U. of California Berkeley
Teller, S.J. [1992]. “Computing the Antipenumbra of an Area Light”, Computer Graphics 26:4 (Proc.
Tellier, P., E. Maisel, K. Bouatouch and E. Languénou [1993]. “Exploiting Spatial Coherence to
Troutman, R. and N. Max [1993]. “Radiosity Algorithms Using Higher Order Finite Element Methods”,
van Liere, R. [1991]. “Divide and Conquer Radiosity”, Proc. Second Eurographics Workshop on
Varshney, A. [1991]. Parallel Radiosity Techniques for Mesh-Connected SIMD Computers, Master's
Thesis, Technical Report TR91-028, Department of Computer Science, University of North Carolina at
Chapel Hill.
Varshney, A. and J.F. Prins [1992]. “An Environment-Projection Approach to Radiosity for Mesh-
Connected Computers”, Proc. Third Eurographics Workshop on Rendering, Bristol, UK, 271-281.
Vedel, C. and C. Puech [1991]. “A Testbed for Adaptive Subdivision in Progressive Radiosity”, Proc.
Vedel, C. [1992]. “Improved Storage and Reconstruction of Light Intensities on Surfaces”, Proc. Third
Vilaplana, J. [1992]. “Parallel Radiosity Solutions Based on Partial Result Messages”, Proc. Third
Vilaplana, J. and X. Pueyo [1990]. “Exploiting Coherence for Clipping and View Transformation in
Radiosity Methods, Master’s Thesis, Program of Computer Graphics, Cornell University, Ithaca, NY.
Wallace, J.R., M.F. Cohen and D.P. Greenberg [1987]. “A Two-Pass Solution to the Rendering Equation:
A Synthesis of Ray Tracing and Radiosity Methods”, Computer Graphics 21:4 (Proc. ACM SIGGRAPH
Wallace, J.R., K.A. Elmquist and E.A. Haines [1989]. “A Ray Tracing Algorithm for Progressive
Radiosity”, Computer Graphics 23:3 (Proc. ACM SIGGRAPH ‘89), 315 - 324.
Wang, M., H. Bao and Q. Peng [1992]. “A New Progressive Radiosity Algorithm Through the Use of
Wang, Y. [1990]. Image Synthesis Using Radiosity Methods, Ph.D. Thesis, University of Alberta, Calgary,
Alberta.
Wang, Y. and W.A. Davis [1990]. “Octant Priority for Radiosity Image Rendering”, Graphics Interface
‘90, 83 - 91.
Wanuga, P.H. [1991]. Accelerated Radiosity Methods for Rendering Complex Environments, Master's
Ward, G.J, F.M. Rubinstein and R.D. Clear [1988]. “A Ray Tracing Solution for Diffuse Interreflection”,
Ward, G.J. and P. Heckbert [1992]. “Irradiance Gradients”, Proc. Third Eurographics Worskhop on
MA.
Watt, A. and M. Watt [1992]. Advanced Animation and Rendering Techniques, Addison-Wesley, Reading,
MA.
Bibliography 515
________________________________________________________________________
Xu, H., Q.S. Peng and Y.D. Liang [1989]. “Accelerated Radiosity Method for Complex Environments”,
Eurographics ‘89 (Proc. European Computer Graphics Conference and Exhibition), W. Hansmann, F.R.A.
Hopgood and W. Strasser, Eds., Elsevier Science Publishers B.V. (North-Holland), Amsterdam, 51 - 61.
Zatz, H. [1993]. “Galerkin Radiosity: A Higher Order Solution Method for Global Illumination”,
Zhang, N. [1991]. “Two Methods for Speeding Up Form-Factor Calculation”, Proc. Second Eurographics
Zhang, X. [1987]. The Finite Fourier Transform for Radiative Transfer Analysis in Complicated
Zhao, Z.H. and D. Dobkin [1993]. “Continuous Algorithms for Visibility: The Space Searching
Approach”, Proc. Fourth Eurographics Workshop on Rendering, Paris, France, 115 - 126.
Zhou, Y. and Q. Peng [1992]. “The Super-Plane Buffer: An Efficient Form-Factor Evaluation Algorithm