Fractal programming and ray tracing
Fractal programming and ray tracing
All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means,
electronic or mechanical, including photocopying, recording, or by any information storage and retrieval sytem,
without prior written pemission from the Publisher. Contact the Publisher for information on foreign rights.
The Author and Publisher make no warranty of any kind, expressed or implied, with regard to these programs or
the documentation contained in this book. The Author and Publisher shall not be liable in any event for
incidental or consequential damages in connection with, or arising out of, the furnishing, performance, or use of
these programs.
Trademarks:
All products, names, and services are trademarks or registered trademarks of their respective companies.
Ray Tracing 3
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Th ree-Dimensional Vectors 7
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Quaternions 12
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
I n t h e Beg i n n i n g 15
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
N i n e Years Later 16
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Constructors 34
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Overloading Operators 35
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
New Di rections 42
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
F ILE_NAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 59
PATTE R N . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 60
COLOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 62
B E G IN_BBOX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 64
B EG IN_INSTANCES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 65
SPHERE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 65
T R IANGLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 66
R ING . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 68
PARALLELOG RAM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 70
QUADRATIC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 73
CON E .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 76
SKY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 78
FOC_LENGTH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 79
LAMP .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 79
OBS E RV E R . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 80
XRES .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 80
.
Y R ES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 81
NAME . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 81
Sample Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 81
Destructors . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 88 . . .
The Header File . . . . . . . . . . . . . . . . . . . .... . . . .... . .... . . . . . ......... . .. . . .............. . . . ........ 330
Input for the Quaternion Prog ram . ... . . . . . . . . .. . .... . .. . . ............... . ...... ...... 330
BACKG ROUND . . . . . . . . . . . .. . ......... . . ................................................... . .. 332
AMB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ....... . . . . . . . .................. . . ......... ..................... . . 338
DIFF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ... . . ......... . . . .. . . .. . . . . . . .......... . . . . . ...... 339
S R E FLECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . ................ . . ... . ........... . . . . ............. 339
R E FLECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . .......... . ................... . . . ....... . . 339
FILE_NAME . . . . . . . . . . . . . . . . . ........ . . . . .... . ......... . . ...... ............................. . . . . . 339
FLIP . . . . . . . . . . . . . . . . . . . . . . . . . .. . .. . . . . . . . ............................... . ................ . ... . ....... 340
LIG HT_P H I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . .. . . . . . . . . . . . .. . . . . . . .... . . ......... . . . ... . .. . ....... 340
LIG HT_TH ETA . . . . . . . . . . . . . . ......... . .................................... . . . . ........ . . .. . .... 34 1
VIEW_PH l . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . .. . . . . . . . .. . . . . . . . . . . . . . . . . . . . ..... . . . . .. . . . . . ... . .. 34 1
XRES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . .. . .. . . . . . . . . . . .. . . . . . ..... . . . . . ... . .. . . . 34 1
Y R ES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ... . . . .. . . . . . . . ...... . . . .... . ............. . . . . ........ . . . . . .. . . . 34 1
XMAX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ... . ....... ................................ . . .. 34 1
XMIN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . ...... . . . . . . . . . . . . . . . . . . . . . . . .. . ....... . . 34 1
YMAX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ... . .. . . . . . . . . ...... . . . . ........................... 342
YMIN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ...... . . . ..... . . . . ........ . . . . . . . ....... . .. . . .... . .. . . . .. . . . . .. . ... 342
ZMAX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . ...... . . . . . ... . ............................. . . . . 342
ZMIN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ........ . ... . . ......... . .. . . . . . . .. . . . . . . . . . . . . 342
QUAT E R N ION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . .. . . . . .. . . . . . . ....... ......... . . . . . . . . . . . . ... 342
MAX_S IZE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .... . . . . . . . ....... . . . . . . . . . .. . ... . . . . . . . . ........ . . . . . 343
MAX_ITE RATIONS . . . . . . . . . . . . . . . . . . . . . . . . ........ . . . . . . . . . . . . . . . . . ........... . .. . .. . .. . . . . . 344
JULIA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . . . .......... . . . . . . . .... . .. . . . .......... . . . . . 344
DRAGON . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .... . . . . ......... . . . . . . .. . . . ... . . ............. . . . . . . . . . . . . . 344
Computing the Quaternions ... . . . . . . . . . . .. . .................... . . .. . .. . . .. . .... . ........ 348
Ray Tracing the Object . . . . . . .. . . . . . . . . . . . . . . . . . . . . . . . . . . . ............ . . . . . . . . . . .. . . . . . . ... 349
Determ i n i ng the Color of a Pixel .. . . . . . . . . . . . . . . . . . . . . . . . . . ...... . . . . . . . . . . . . . . . . . . . . . 357
Producing the Color Picture . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . .......... . .... . . . . . . . . . . . . . . 358
Appendix A Data Files for Ray Traced Scenes ........................... 365
All of the software in this book was written using Zortech C++ furnished by
Zortech, Inc . , 4-C Gill St., Woburn, MA 0 1 80 1 . It was also checked with Turbo
C++ furnished by Borland International, 4835 Scotts Valley Drive, Scotts Valley,
CA 95066.
Valuable technical information on the format of the .PCX files and a copy of
PC Paintbrush were supplied by Shannon of Z-Soft Corporation, 1 950 Spectrum
Circle, Marietta, GA 30067.
Software was developed and tested on computers using a Vega VGA card
and a Vega VGA 1 024i card both furnished by Headland Technology Inc., 4622 1
Landing Parkway, Fremont, CA 94538. Color pictures were viewed on a NEC
Multisync Plus Color Monitor furnished by NEC Home Electronics (U.S.A.) Inc.
This book includes some instruction in how to use C++ that should get
you started with this language and help you to use and/or modify the programs.
The programs have not been fully tested with Turbo C++, but you should be able
to run them with this language with a little ingenuity. Some clues are given as to
differences between Turbo C++ and Zortech C++.
Executable files for rendering ray-traced scenes and julia sets and
dragons in the quartemions are supplied on the disk that accompanies this book
in two forms: one for use with the math coprocessor, and one for use in systems
without a math coprocessor. If you only want to run these programs without
delving any deeper into the programs, you can do so. All information for setting
up data files for your own pictures is given in the book.
If you don 't have a VGA display system, you can still use the program
to render pictures and store them on disk files, but you will not be able to view
the results except on a VGA-equipped computer. However, since rendering can
take hours and viewing requires only a few minutes, you may want to render on
one machine and view on another.
1
CHAPTER 1
Introduction
C++ is the programming language of the future . Every major software
house that now has a C compiler is coming out with a C++ compiler. Within a
few years everyone w i l l be u s ing C++ because i t not only has all of the
capabilities of C, but has object-oriented and operator overloading capabilities
that let you write elegant programs. If you want to get started learning about
C++, here 's your chance. First, forget everything you 've heard about object
oriented programming being a unique way of thinking that programmers don't
understand. We 're going to use C++ as a natural extension that is required when
objects are important parts of our program. And we ' ll explore a ray-tracing
program, which is at the forefront of PC graphics, and demands that we try some
object-oriented techniques. The result may not be optimum code for the purist,
but will make you familiar with the capabilities of C++ and help you make a
natural transition from a C programming background.
Ray Traci ng
Ray tracing is a technique for creating a two dimensional picture of a three
dimensional world. There are many methods of doing this, some involving very
simple constructive geometry. Ray tracing is different in that it attempts to cause
the computer to duplicate an actual photographic process. This enables us to
specify a scene of simple primitive objects (spheres, parallelograms, triangles,
etc . ) , together w ith patterns to be projected on surfaces, light sources, and
position of the observer. The ray tracer will trace every beam of light, creating
complex shadows and reflections with breath-taking realism.
3
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
project the light ray backwards from observer to screen and then to the nearest
object. The color of the ray at the intersection with this object is what appears
on the screen; we shall build a file of color data in which we assign that pixel on
the screen to the light ray color.
The color of the ray at the object intersection is not something that can be
determined casually. It depends upon what happens to the light ray before it gets
to this point. If the light is totally emitted by the object, and is of a specified
color, our problem is solved. But if the surface is transmitting a color from
within a partially transparent object, reflecting a color, or changing a color that is
originally projected by a light source, we have to follow the path of the light ray
back toward the light sources and sum the various color contributions to
determine the actual ray color at the object intersection.
4
I NTRODUCTION
Lamp
--
--
--
Object
--
--
--
--
--
--
--
--
- --
--
--
--
--
--
--
--
--
--
--
--
- -
--
--
--
--
--
5
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
Lamp
{) ..
..
..
Shadow
..
..
..
..
..
..
..
..
..
..
..
..
..
..
..
RAYS
Shadow
6
INTRODUCTION
7
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
transparent. Another is the line class which defines the location and direction of
a light ray and includes a flag to indicate whether the ray is within or outside of a
transparent object. Lamp and pattern classes are also defined. Finally, there is a
generic definition of the characteristics of an object, and then derived classes for
each particular primitive object that the program can handle. Figure 1 -3 is a
diagram showing the relationship of these classes. All of these are described in
detail in Chapter 5 . It is important to note that adding another object class in this
header and defining its associated functions in the "objects" part of the program
is all that is necessary to accommodate a new class of object.
8
I NTRODUCTION
Using th e La ng uage
Chapter 9 gives instructions in how to use the language that was created in
order to specify the objects, lamps, observer, and more which make up the scene
to be rendered.
9
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
Fu n c t i o n De s c r i p t i o n
F i n d No r m Ge n e r a t e s a ve c t o r t h a t i s
n o rma l to the surface of
the obj e c t a t t h e s pe c i f i ed
pos i t i on .
F i n d BB o x C omp u t e s t h e c o o r d i n a t e s o f
the top l eft corner and
b o t t om r i gh t c o r n e r o f a
b o u n d i ng b o x wh i c h e n c l o s e s
t h e o b j ec t .
Po s i t i o n C om p u t e s two p o s i t i o n
va r i a b l e s n e e d e d f o r t h e
i n t e r s e c t i o n c omp u t a t i o n .
10
I NTRODUCTION
Putting it Al l Together
Chapter 1 3 shows how the make capability of C++ operates and gives a
listing of the make file used to compile and link the various sections of the ray
tracing program. This eliminates the repeated recompiling of portions of the
program that have not been modified since the previous pass. The output of the
make capability is the completed ray-tracing program, ready to be run.
11
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
Quaternions
Chapter 16 gives a description of quaternions, four-dimensional vectors first
discovered by Lord Hamilton. We describe in detail the uses of quaternions and
the derivation of their mathematics. In Chapter 1 7 , we show how the class and
operator overloading feature s of C++ c an be used to permit handling of
quaternions as if they were just another type of number.
12
I NTRODUCTION
giving the height of each point, and compute the color and shading of each pixel
from this data.
These programs have been tried on several different computers and have
13
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
14
CHAPTER 2
Object-Oriented
Programming : Myth and
Fact
In the Beg i n n i n g
In August 1 98 1 , Byte M agazine devoted i t s entire issue t o articles o n
Smalltalk, one o f the first object-oriented languages. Smalltalk had been under
development at the Xerox Palo Alto Research Center since 1 97 1 . Byte was
slightly apologetic because there was no version of the language available for
use with personal computers, but was so impressed with the potential of the
language that it thought a special issue was worthwhile and necessary.
15
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
Let's expand on this a little further. In the first place, an essential quality of
objects is that they hide many of their characteristics. From the outside, you
send a message to the object and it responds. However, you have no idea what is
going on that translates the message to the correct response. In fact, from the
16
O B J E CT-O R I E N T E D P R O G R AM M I N G : M YTH A N D FACT
inside; things begin to look a lot more like conventional computer programming,
with the necessary code to translate an incoming message into an outgoing
response. But all of this is hidden from the user of the object; it can ' t be
tampered with.
Suppose, however, that one object has all the characteristics of a particular
class, and is unique in that it has additional characteristics or responds differently
to a particular message. (Sandy may respond A lf, arf, but Lassie may respond
Bow, wow, for example . ) To cope with this situation, the object-oriented
language has the characteristic of inheritance. In this situation, a base class is
modified to create another derived class. A derived class inherits all of the
characteristics of its base class, but then may be modified to be different in
content or behavior.
The Wo rd i s Parad i g m
The word most in vogue to promote object-oriented languages is paradigm.
A paradigm is a model. As used in the object-oriented language discussions, you
have a paradigm of the world (which is not the real world, but your model of it).
It is claimed that object-oriented programming is a paradigm of the world very
close to the paradigm we carry around in our heads, and thus we can more easily
program with it. This is patently nonsense. To be sure, you know of an object
Joe and want to send him a message Come. However, it is pretty artificial to say
that we have as an object a set of numbers and that we are going to send them the
17
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
message Sum whereupon they will respond with the answer. Moreover, there is
plenty of reason to believe that rather than selecting a language that corresponds
to our view of the world, our view of the world is largely determined by our
habitual language.
What Korzybski is saying is that our thought processes are dominated by the
language that we are used to, rather than the language being a reflection of a way
of thinking. If this is true, how do we apply it to the implication that object
oriented languages are "more natural" to computer neophytes, but strange to
computer professionals. (There is something very strange about a philosophy
that says that a product is to be commended because it is liked by those with no
experience in the field but is disliked by the experts.) I think one of the obvious
implications is that the thought patterns most natural to us using English and
other European languages correspond to object-oriented computer languages ,
and the thought patterns o f those versed i n mathematics correspond to traditional
computer languages.
18
O B J E CT-O R I E N T E D P R O G R A M M I N G : M YTH A N D FACT
environment might be less spoiled, world food production could never meet the
global population demands, and many of us would not be here.
The case is much less clear for the contributions of those whose favorite
language is English or a European language . Communication of critical data
appears fuzzy, to say the least. The languages have not lent themselves to
fostering understanding and friendly relations. Korzybski claims that this is
because all of our languages have heavy Aristotelian philosophical roots, which
tend to make us look for solutions to all problems as black or white (yes or no)
i n s t e a d of p e rc e i v i n g s h a d e s of gray i m portant in a c h i e v i n g peacefu l
compromises. We know that both computers and brain cells work i n a binary
(Aristotelian) mode, so perhaps we are incapable of anything but Aristotelian
thinking. At any rate, there doesn 't appear to be any good reason for embracing
a language that has many features in common with languages that have failed to
handle the world's problems to date.
19
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
you should forget all of this hype about learning a new way of thinking and let
the object-oriented approaches flow when they are needed. This demands a
language that supports both conventional and object-oriented programming
techniques. The best example is C++.
2. The language should make it possible to have sets of functions, each set
using a single calling statement that identifies the type of object being
called and executes the proper function for that type of object.
Other object-oriented features such as inheritance and hiding private data are
useful, but not essential . Note that the only object-oriented language that
provides for overloading of a mathematical operator (essential to achieving the
first goal presented above) is C++. When you also consider that C++ has all the
detailed mathematical and data manipulation capabilities included in C, then it
becomes a natural choice for those who want to use object-oriented capabilities
in complicated mathematical programming. The rest of this book assumes that
C++ is the wave of the future, and naturally fits into the problem of creating ray
tracing programs to generate advanced graphics and fractal pictures.
20
CHAPTER 3
f(z ) = 0 ( Eq u a t i on 3 - 1 )
( Eq u a t i on 3 - 2 )
where f' is the derivative off For the first pass, we have zO on the
right side of the equation and obtain z l on the left.
21
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
This iteration process is similar to that used to obtain Julia sets and dragon
curves . I n fact, the graph o f the process for a number o f starting values
throughout the complex plane looks like a fractal display, but in this case, there
is an additional mathematical meaning attached to the results.
G raphics Functions
Before showing the first Newton 's method program , we need to address
three simple graphics functions which are used with either C or C++ in all of the
Newton 's method programs that follow. These functions are shown in Figure 3-
1 . They are setMode , els, and plot. If you want to get into the nuts and bolts of
these functions, which make use of the ROM B IOS video services and direct
c a l l s to the v i d e o re g i sters , y o u ' 11 need to l o ok at m y book G rap h ics
Programming in C. However, the functions are simple and the details of how
they work are not important to the application described here. The first function,
setMode, simply sets the mode of the display screen. In the Newton 's method
programs , we shall al ways set to mode 1 6, which is 640 pixel by 350 line
graphics using 1 6 colors. This mode will work equally well with EGA or VGA
adapter boards. The second function, els , works only when the system is in
display mode 1 6. It clears the existing information from the screen and fills the
screen with whatever color (0 to 1 5) is passed to the function as a parameter.
The third function, plot, also works only with mode 1 6. It plots a point on the
screen. The parameters passed to this function are x (display column), y (display
row), and color (pixel color). The function designates location and color to the
pixel.
z3 - 1 0 ( Eq u a t i on 3 - 3 )
22
B EY O N D C WITH C++ : A N EWTON'S M ETHOD EXAM P L E
/*
s etMode ( ) Sets V i deo Mode
*I
v o i d s etMode ( i n t mod e )
{
uni on REGS reg ;
reg . h . a h =0;
reg . h . a l = mode ;
i n t86 ( Ox l O , ® , & reg ) ;
I*
cl s ( ) C l ea rs t h e Screen
*I
voi d cl s ( i nt col or )
{
uni on REGS reg ;
reg . x . a x Ox0600 ;
reg . x . cx 0:
reg . x . dx O x l 84 F ;
reg . h . bh col or ;
i nt86 ( 0x l 0 , & reg , ® ) ;
I*
pl ot ( ) = Pl ots a poi nt a t ( x , y ) i n col o r
f o r E n h a n c e d G r a p h i c s Ad a p t e r , u s i n g
Turbo C port output functi ons
*/
voi d pl ot ( i nt x , i nt y , i nt col o r )
{
# d e f i n e s e q_o u t ( i n d e x , v a l ) { o u t p ( O x 3 C 4 , i n d e x ) ; \
outp ( Ox3C5 , va l ) ; }
#d e f i n e g r a p h_o u t ( i n d e x , v a l ) { o u t p ( O x 3 C E , i n d e x ) ; \
23
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
outp ( Ox3C F , va l ) ; }
u n s i g n ed i n t o f f s e t ;
i n t m a s k , d u mmy ;
c h a r f a r * m e m_a d d r e s s ;
24
B E Y O N D C WITH C + + : A N EWTON'S M ETHOD EXAM P L E
pixel is then plotted on the screen in the appropriate color. Hence, the group of
colors to which the color belongs indicates which root was ultimately targeted,
whereas the color within the group is a measure of the number of iterations
required to get there. Normally, we set up the display palette so that one root has
all shades of a single color (the first root might have shades of green, the second
shades of red, and the third shades of blue, for example).
/*
c n ew t o n 3 MAP OF N EWTON ' S METHOD FOR SOLV I NG z3
*!
voi d cl s ( i nt col or ) ;
v o i d s etMode ( i n t mode )
voi d pl ot ( i nt x , i nt y , i nt col or )
ma i n ( )
{
doubl e del ta X , del taY . X . Y , Xsqua re , Xol d , Yol d ,
25
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
Y s q u a r e , Y t em p , t e m p l , t e m p 2 , d e n om . t h e t a ;
i n t c o l o r , row . c o l ;
s etMode ( l 6 ) ;
cl s( 7 ) ;
del t a X = ( Xmax - Xmi n ) / ( ma xcol ) ;
d e l t a Y = ( Ym a x - Ym i n ) / ( ma x row ) ;
f o r ( c o l =O ; c o l <=m a x c o l ; c o l ++ )
{
i f ( kbh i t ( ) ! = 0 )
brea k ;
f o r ( r ow=O ; r o w <=m a x r ow ; r ow++ )
{
X = Xmi n + col * del t a X ;
Y = Yma x - row * d e l t a Y ;
Xsqua re = 0 ;
Y squa re = O ;
Xol d = 42 ;
Yol d = 42 ;
f o r ( i =O ; i < m a x_i t e r a t i o n s ; i ++ )
{
Xsqua re = X*X ;
Y squa re = Y*Y ;
d e n om = 3 * ( ( X s q u a r e - Y s q u a r e ) * ( X s q u a r e
Y s q u a re ) + 4* X s q u a re*Y s q u a re ) ;
i f ( d e n om == 0 )
d e n om = . 0 0 0 0 0 0 0 1 ;
t e m p l = . 6 6 6 6 6 6 7 * X + ( X s q u a r e - Y s q u a r e ) / d e n om ;
Y . 6 6 6 6 6 6 7 * Y - 2 * X * Y / d e n om ;
X = templ ;
i f ( ( Xol d X ) & & ( Y o l d == Y ) )
brea k ;
Xol d x ;
Yol d = Y ;
i f ( X>O )
col or i %5 ;
el se
{
i f ( ( X < - . 3 ) && ( Y > O ) )
col o r = ( i %5 ) + 5 ;
26
BEYOND C WITH C++ : A N EWTON'S M ETHOD EXAM PLE
el se
col or = ( i %6 l + 1 0 ;
p l o t ( c o l , r ow . c o l o r ) ;
getc h ( l ;
If you look at the part of the program which computes the Newton's method
iterations, note that the mathematics is fairly simple for this equation. Consider
what happens, however, when we use a more complex equation having higher
powers of z and more terms. Decomposition is no longer possible. Of course,
we c an create a lot of special purpose functions to attempt to address the
problem, but, using C++, there is a simpler and more elegant way.
27
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
I*
C om p l e x c l a s s of comp l ex n umbe r s
*I
#i n c l u d e <stdi o . h>
#i n c l ude <ma t h . h >
#i n c l ude <dos . h>
#i n c l u d e < p roces s . h>
#i n c l ude < s t ream . hpp>
#i n c l ude < c on i o . h > ;
voi d cl s ( i nt col or ) ;
voi d pl ot ( i n t x , i nt y , i nt col or ) ;
v o i d setMode ( i n t mode ) ;
c l a s s C o mp l e x I
d o u b l e r e a l , i m a g i n a ry ;
publ i c :
C om p l e x ( ) ;
Compl ex ( d o u b l e r , d o u b l e i ) ;
Comp l e x ( Comp l ex & ) ;
28
BEYOND C WITH C++ : A N EWTON'S M ETHOD EXAM P L E
C o m p l e x o p e r a t o r + ( C om p l e x & J ;
C om p l e x o p e r a t o r - ( C om p l e x & ) ;
C om p l e x o p e r a t o r= ( C om p l e x & J ;
C om p l e x o p e r a t o r * ( C om p l e x & ) ;
C om p l e x o p e r a t o r * ( f l o a t & ) ;
C om p l e x o p e r a t o r / ( C om p l e x & J ;
C om p l e x o p e r a t o r- ( ) ;
i n t o p e r a t o r ! = ( C om p l e x & J ;
i n t o p e r a t o r== ( C om p l e x & J ;
v o i d p r i n t ( c h a r * n a me = " " ) ;
doubl e r ( ) ;
daub1 e i ( ) ;
f r i e n d o s t r e a m & o p e r a t o r < < ( o s t r e a m& , C o m p l e x & J ;
};
Compl ex : : C omp l e x ( )
{
rea l = 0 ;
i m a g i n a ry O;
C o m p l e x : : C om p l e x ( d o u b l e r , d o u b l e i )
{
rea l = r ;
i m a g i n a ry i ;
C o m p l e x : : C o m p l e x ( C om p l e x & o t h e r c o m p l e x ) {
r e a l = o t h e r c om p l e x . r e a l ;
i m a g i n a ry = o t h e r c om p l e x . i m a g i n a ry ;
C o m p l e x C o m p l e x : : o p e r a t o r+ ( C om p l e x & a r g ) {
C om p l e x r e s u l t ;
res u l t . rea l = rea l + a rg . rea l ;
r e s u l t . i m a g i n a ry i m a g i n a ry + a r g . i m a g i n a ry ;
return resul t ;
C o mp l e x C o m p l e x : : o p e r a t o r - ( C om p l e x & a r g ) {
C om p l e x r e s u l t ;
res u l t . rea l = rea l - a rg . rea l ;
29
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
r e s u l t . i m a g i n a ry i m a g i n a ry - a r g . i m a g i n a ry ;
return resul t ;
C o m p l e x C om p l e x : : o p e r a t o r * ( C o m p l e x & a r g ) {
Comp l ex r e s u l t ;
r e s u l t . r e a l = r e a l * a r g . r e a l - i m a g i n a ry * a r g . i m a g i n a ry ;
r e s u l t . i m a g i n a ry r e a l * a r g . i m a g i n a ry + i m a g i n a ry *
a rg . rea l ;
retu rn resul t ;
C o m p l e x C om p l e x : : o p e r a t o r / ( C o m p l e x & a r g ) {
doubl e temp ;
C om p l e x r e s u l t ;
t e m p = a r g . r e a l * a r g . r e a l + a r g . i m a g i n a ry * a r g . i m a g i n a ry ;
r e s u l t . r e a l = ( r e a l * a r g . r e a l + i m a g i n a ry *
a r g . i m a g i n a ry ) / t e m p ;
r e s u l t . i m a g i n a ry = ( i m a g i n a ry * a r g . r e a l - r e a l *
a r g . i m a g i n a ry ) / t e m p ;
return resul t ;
C o m p l e x C o m p l e x : : o p e r a t o r- ( v o i d ) {
doubl e temp ;
C om p l e x r e s u l t ;
t em p = r e a l * r e a l + i m a g i n a ry * i m a g i n a ry ;
r e s u l t . r e a l = r e a l / t emp ;
r e s u l t . i m a g i n a ry = - i m a g i n a ry / t e m p ;
return resul t ;
C o m p l e x C o m p l e x : : o p e r a t o r= ( Com p l e x & r v a l u e ) {
rea l = rva l ue . rea l ;
i m a g i n a ry = r v a l u e . i m a g i n a ry ;
return *thi s ;
i n t C o m p l e x : : o p e r a t o r== ( C om p l e x & r v a l u e )
30
B E Y O N D C WITH C + + : A N EWTO N'S M ETHOD EXAM P L E
i n t C om p l e x : : o p e r a t o r ! = ( C om p l e x & r v a l u e )
{
i f ( f l o a t ( r v a l u e . r e a l - r e a l ) == f l o a t ( r v a l u e . i m a g i n a ry -
i m a g i n a ry ) )
return O ;
el se
return l ;
return s ;
d o u b l e C om p l e x : : r ( )
{
doubl e temp ;
temp = rea 1 ;
ret u r n temp ;
doubl e Compl ex : : i ( )
{
d o u b l e t em p ;
t e m p = i m a g i n a ry ;
r e t u r n t em p ;
31
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
The protected keyword identifies members of a class that are hidden from
external functions but appear as public to classes that are derived from the
specified class. There are no derived functions for the complex number class
(we ' ll speak more about derived functions in later chapters) so there is no need
for any members to be protected.
The public keyword indicates that designated members of the class are
accessible from anywhere within the C++ program where a class object is within
scope. If you are trying to achieve maximum data protection, all of your class
variables will be private and the only access to them from the outside world will
be through various functions that are public. On the other hand, it is perfectly
acceptable to have the entire contents of a class be public . (We ' l l see some
examples of this in later chapters.) You gain in flexibility but pay the price of
losing data protection from the outside world. Note that all of the functions used
by the Complex c l ass are public . In order to permit needed access to the
individual hidden variables the functions r and i were created. They wouldn ' t
32
B E Y O N D C WITH C + + : A N EWTO N ' S M ETHOD EXA M P L E
have been needed if the two variables had been public. Things were left in this
form to demonstrate an alternate method of access.
rea l = temp . r ( ) ;
which will cause the function to return the real part of the complex number to
real. The two ordinary functions used with the Complex class are quite simple.
The function r returns the value of the real part of the complex number and the
function i returns the value of the imaginary part. Instead of making the real and
imaginary parts public, this technique enables us to get the values of the real
and/or imaginary parts for external use but does not permit us to modify them by
direct external action.
33
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
it, and this memory remains allocated to it until explicitly freed. There is a
special C++ function called a destructor, which, if defined by the programmer
for a class, will automatically be called whenever the class member goes out of
scope. This can be used to delete the memory assigned to a member as well as
any other housekeeping that is necessary. In the case where only the structure or
class address is defined, as in C, only the memory for the address is allocated.
However, C++ has the function new which can be called to allocate the memory
for a class or structure. Fortunately, C++ knows just how much memory to
allocate for a particular structure or class. There is also a companion function
delete, which is used to deallocate the memory assigned by new. If memory is
assigned by new, it will not be deallocated by the destructor; the delete function
must be used. The C++ language also has a function called a constructor. This
function is used to initialize a newly created object in any desired way.
Constructors
The constructor is a special function which is identified by the fact that it has
the same name as the class itself. This function provides for the initialization of
a class object. It is invoked by the compiler whenever a new object of the class
is created. The C++ language supports the concept of function overloading,
which means that you can have more than one definition of a function, providing
the parameters passed to the function are different for each instance. As you can
see in the listing of Figure 3-3, right after the public: statement, we have made
use of this capability to define three constructors. The first constructor is used
when we create a new instance of Complex without passing any parameters. In
the second case, we pass two numbers of type double to the new instance. In the
third case, we pass another complex number to the constructor. Looking down a
little further, you will come to the place where these constructors are defined.
Prototypes of all associated functions must be included w i thin the class
definition, but the actual body of code may be developed separately. The format
for creating a constructor is to begin with the type of data that is to be returned
(in this case Complex, followed by a double colon, followed by the class name,
which for a constructor is identical to the function name). The body of the
function for the first constructor simply sets the real and imaginary parts of the
34
B E Y O N D C WITH C + + : A N EWTO N ' S M ETHOD EXAM P L E
complex number to zero. This is the default case when no parameters are
specified. The second constructor sets the real and imaginary parts of the
complex number to the two numbers that are passed as parameters.
Overload i n g Operators
One of the most important capabilities of C++ is the capability to overload
operators. We have found it quite easy to define the class of complex numbers,
but what makes all of this worthwhile is the fact that we will be able to handle
operations of complex numbers arithmetic just as easily as arithmetic for integers
or floating point numbers. For the complex class, we have overloaded the +, -,
=, * , /, -, = = , and ! = operators. Now let's see how this is done. Look at the
definition for overloading the + operator in Figure 3 - 3 . The format for the
function definition begins like any class function with the type of variable to be
returned, followed by the class name and two colons. Next comes the keyword
operator followed by the function to be overloaded (in this case + ). Next, in
parentheses, are the arguments to be passed to the function. Note that you can't
p a s s j u s t any v ariab l e s . The number of v ariables that c an be passed i s
determined b y the operator that you select. More about that later. We see then
that in the case of the + operator, we are passing one complex number's pointer
to the function, and the function already has access to its own native complex
number. The body of the function definition sets up a complex number to
contain the result, adds the real and imaginary parts of the two complex numbers
separately, and returns the result. Thus when you write
c = a + b;
where a, b, and c are all complex numbers, the new definition of the + function
for complex numbers applies. Its native complex number is a and the complex
number b is passed to it. The addition is performed, returned, and c is set equal
to it. This implies something , however; that the = operator is capable of
performing its function for complex numbers. The definitions of C++ state that
the = operator is automatically overloaded for each class created.
35
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +
The Zortech C++ compiler is sometimes unable to handle this and returns a
compiler error. We have defined our own overload for this operator that sets real
and imaginary parts of the native complex number equal to their counterparts in
the complex number passed to the function. S imilarly, the operators for
subtraction, multiplication, and division are overloaded to properly perform
these operations on complex numbers. The operator - takes only one argument;
we have used it to represent the reciprocal of a complex number.
This application makes use of cout, a streamlined replacement for the print/
36
BEYOND C WITH C + + : A N EWTON'S M ETHOD EXAM PLE
function using overloading of the shift left (<<) operator. The function begins
with cout < < followed by a string or by any type of variable. The overloading
automatically functions out what type of v ariable is used and displays it
appropriately. Also, the function returns itself, so you may concatenate the left
shift operators into as long a series as you like. For example:
cout << "Th i s i s a t e s t o f " < < v a r i a b l e < < " i tems . \ n " :
is perfectly legal. Note that a semicolon must appear at the end of the series.
Now we are almost ready to consider overloading so that cout can be used
with our Complex class. But first, we need to know about friends. A friend of a
class i s a nonmember of a c l a s s , either a function, a member of another,
previously defined class, or a complete class, which is allowed access to the
nonpublic members of a class. This relationship must be declared within the
class, using the keyword friend.
Now let's see what would happen if we were to overload the double shift
operator within the Complex class in the normal manner. We would have the
prototype:
and some code to define what would be output when the operator was invoked.
However, this invocation (for a complex number temp, for example) would be of
the form:
temp«cout ;
which is very unlike the normal way of using cout for other types of data. What
we need to do is have a prototype of the form:
37
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
38
B EYON D C WITH C + + : A N EWTON'S M ETHOD EXAM PLE
from 0 to 9. The next few lines of code are very much like the Newton's method
program of Figure 3-2, setting up the values associated with each pixel location
and going into a double loop to compute for each pixel. When we get to the
arithmetic, it is all done with complex numbers and can be simply written for
these possibly complex equations as the arithmetic for the simple equation used
in Figure 3- 2. Note how we initially define z as a complex number. We first
enter a loop which puts together the values of f and f' , power-by-power from the
zeroeth to the next-to-last. We then add in the last power for f (there isn't one
for f'). The expression to compute the new Newton estimate is a single line. We
then compare the old and new values of the complex root and quit if they are the
same, or continue if they are not. (Note that it would be a little more convenient
to use the equality test here, but because of the way we have overloaded the
operators, we have to use the inequality test to obtain the tolerance that we
want.) As for determining the colors to plot, in this case we haven't tried to
assign groups to different roots, since determining all of the roots would be too
complicated. Instead, we cycle through the available colors based upon the
number of iterations it took to find a root. This program is an example of C++ at
its best and at its worst. It is at its best because you can see how simple it is to
write the software; the most difficult part is writing the functions and definitions
for the complex number class. Once you have done this, the actual program is
simple, and since this same complex class can be used again whenever you
encounter a complex number problem, the next program will be even simpler.
(Watch out if you use our peculiar inequality and equality overload functions in a
different application, however.) This is C++ at its worst because the few simple
and elegant lines of code that make up the program conceal a whole lot of
mathematical operations. The result is that this program will require days to
generate a display even with a fast computer and a math coprocessor, so don't
use it unless you have a lot of patience. If you do, you will be rewarded by
interesting displays like that shown in Plate 3, which is the plot of the equation:
z6 - 2z5 + 4z4 - z - 1 0 ( Eq u a t i on 3 - 4 )
39
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
/*
n ew t g e n P r o g r a m t o m a p t h e g e n e r a l i z e d N ew t o n ' s m e t h o d
voi d cl s ( i nt col or ) ;
voi d pl ot ( i nt x , i nt y , i nt col o r ) ;
v o i d s etMode ( i n t mode l ;
i n t c o l , row , i , j ;
i n t m a x_i t e r a t i o n s = 6 4 ;
i n t m a x_s i z e = 4 ;
f l o a t X m a x= 2 . 0 , X m i n = - 2 . 0 , Y m a x= l . 2 0 , Y m i n = - 1 . 2 0 , d e l t a X , d e l t a Y ;
C o m p l e x z , o l d_z ;
C o m p l e x f , f_p r i m e , z_p owe r ;
f l o a t a r g u me n t s [ l O J ;
f l o a t temp ;
c o n s t i n t ma x c o l = 639 ;
c o n s t i n t m a x r ow = 3 4 9 ;
c o n s t i n t m a x_c o l o r s = 1 6 ;
ma i n ( )
{
i n t c o l o r . r ow . c o l . d e g r e e ;
f o r ( i =O ; i < l O ; i ++ )
{
a rg umen t s [ i ] = O ;
cout < < "\nEnter " << << " t h coeffi c i en t : "
c i n > > a r g um e n t s [ i ] ;
s etMode ( l 6 ) ;
f o r ( i =9 ; i >=O ; i - - )
40
B E Y O N D C WITH C + + : A N EWTON'S M ETHOD EXAM P L E
i f ( a r g umen t s [ i ] ! = O J
I
deg ree = i ;
brea k ;
cl s ( l l ;
d e l t a X = ( Xm a x - Xm i n ) / ( ma xc o l + l ) ;
d e l t a Y = ( Y ma x - Ym i n ) / ( ma x row + l ) ;
o l d_z = C om p l e x ( 4 2 , 4 2 ) ;
f o r ( c o l =O ; c o l < =m a x c o l ; c o l ++ )
I
i f ( kbhi t ( ) ! = O J brea k ;
f o r ( r ow=O ; r ow < =m a x r ow ; r o w++ )
I
z = C omp l e x ( Xm i n + c o l * d e l t a X , Y m a x - row * d e l t a Y ) ;
i = 0;
w h i l e ( i < m a x_i t e r a t i o n s )
I
f = 0;
f_p r i m e = O ;
z_p o w e r = l ;
f o r ( j =O ; J < d e g r e e ; j ++ )
I
f = f + z_powe r * a r g u m e n t s [ j ] ;
f_p r i me = f_p r i me + ( z_powe r * a r g umen t s [ j +l ] ) *
( fl oa t ) ( j +l l ;
z_p ow e r = z * z_powe r ;
el se
brea k ;
col or = i %16 ;
p l ot ( c o l , row . co l o r ) ;
41
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
getch ( ) :
zn - 1 = 0 ( Eq u a t i on 3 - 5 )
New Di rections
Now that we 've been exposed to creating classes and using them to simplify
programming, we ' ll go on to the next chapter, where we ' ll look at the functions
and definitions needed to treat three-dimensional vectors. This will eventually
lead us into using these vector operations in the ray tracing program.
42
B EY O N D C WITH C + + : A N EWTON'S M ETHOD EXAM P L E
/*
*/
i n t m a x_i t e r a t i o n s = 64 ;
d o u b l e X m a x= 2 . 0 , X m i n = - 2 . 0 . Y m a x= l . 2 0 . Y m i n= - 1 . 2 0 , d e l t a X . d e l t a Y ;
C o m p l e x z . o l d_z . z_p owe r , z_p ow e r 2 . z_s q ;
Comp l ex r o o t s [ l O J ;
i n t deg ree ;
ma i n ( )
{
i n t i , j , co l o r . row . c o l . f l a g ;
d o u b l e a , b , t w o p i =6 . 2 8 3 1 8 5 3 ;
s etMode ( 1 6 ) ;
cout « " E n t e r degree of equa t i on ( 3 - 1 0 ) : " ;
c i n » deg ree ;
c o u t « " \ n E n t e r ' 0 f o r cy c l i c a l c o l o r s ; \ n "
·
43
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
cl s ( 7 ) :
d e l t a X = ( X m a x - X m i n ) / ( ma x c o l + 1 ) :
d e l t a Y = ( Ym a x - Ymi n ) / ( ma x row + 1 ) :
f o r ( c o l =O : c o l <=ma x c o l : c o l ++ )
{
i f ( kbh i t ( ) ! = 0 ) brea k :
f o r ( r ow=O : r o w <=ma x r ow : r o w++ )
{
z = C o m p l e x ( X m i n + c o l * d e l t a X , Y m a x - r ow * d e l t a Y ) :
o l d_z = C o m p l e x ( l 0 0 0 0 , 1 0 0 0 0 ) ;
i = 0:
w h i l e ( ( z ! = o l d_z ) && ( i < 6 4 ) )
{
o l d_z = z ·
z_s q = z * z :
swi tch ( deg ree )
{
case 3:
z _powe r z _s q :
ca se 4 :
z_powe r z * z_ s q :
brea k :
case 5 :
z_p owe r z_s q * z_s q :
brea k :
case 6 :
z _powe r z * z_ s q *z_s q :
brea k :
ca s e 7 :
z _powe r z_s q * z_s q * z_s q :
brea k :
case 8 :
z _powe r
z_s q * z_s q * z_s q * z :
brea k :
ca s e 9:
z _powe r z_s q * z_s q :
z_powe r z_p owe r * z_powe r :
brea k :
case 10 :
44
B E Y O N D C W I T H C + + : A N EWTO N ' S M ET H O D E X A M P L E
i f ( f l a g == 1 )
{
col or = 1 5 :
f o r ( j =O ; j < d e g r e e : j ++ )
{
i f ( z == r o o t s [ j ] )
c o l o r = 1 + j % 8 + 8* ( i % 2 ) ;
el se
col or = i %16 :
p l o t ( c o l , r ow . c o l o r ) :
getch ( ) ;
45
CHAPTER 4
Three Dimensional
Vector Mathematics with
C++
In this chapter, we are going to look in some detail at using C++ to define
the class Vector of three dimensional vectors. All of the information needed to
define these vectors for use in the ray tracing program is included in two files.
The first of these, vmath .hpp, is a header file which contains the definition of the
class. It is listed in Figure 4- 1 . The second file, vmath.cpp, contains the detailed
definitions of all of the functions that are contained within the class. It is listed
in Figure 4-2.
c = Vector ( 6 , 7 , 8 )
c = Vector ( )
47
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
I*
v m a t h . h p p=H e a d e r F i l e f o r T h r e e D i me n s i o n a l V e c t o r M a t h e m a t i c s
*I
cl a s s Vector I
publ i c :
fl oat x , y , z ·
Vector ( ) ;
Vector ( fl oat xl , fl oat y l , fl oat zl ) ;
Vector ( Vector & ) ;
V e c t o r o p e r a t o r+ ( V e c t o r & ) ;
Vector ope r a t o r - ( Vector & ) ;
Vector ope r a t o r - ( ) ;
V e c t o r o p e r a t o r= ( V e c t o r & ) ;
Vector opera tor* ( Vector & ) ;
Vector ope r a t o r* ( fl oat ) ;
Vector ope r a t o r l ( fl oa t ) ;
fl oat ope r a t o r% ( V ector & l ; I I Dot p roduct
Vector ope rator� ( Vector & ) ; II C ro s s p roduct
V e c t o r o p e r a t o r- ( ) ; I I N o rm a l i z e v e c t o r
Vector mi n ( Vector & ) ;
V e c t o r ma x ( V e c t o r & ) ;
V e c t o r Rot a t e ( f l o a t c o s l , f l o a t s i n l , f l o a t c o s 2 . fl o a t s i n 2 ) ;
V e c t o r R e v_Ro t a t e ( f l o a t c o s l , f l o a t s i n l , f l o a t c o s 2 . f l o a t
s i n2 ) ;
f r i e n d o s t r e a m & o p e r a t o r < < ( o s t r e a m& . V e c t o r & ) ;
v o i d g e t_v e c t o r ( ) ;
};
Figure 4-1 . Vector Mathematics Header File
48
T H R E E D I M E N S I O N A L V E C T O R M AT H E M AT I C S W I T H C + +
c = - a ;
where both c and a are vectors. This will only work because the - operator is
already defined in C++ as being applicable to a single variable as well as the
difference between two variables. Note that if, for some reason, we decided to
use the operator I as the operator for subtraction, we could only use it to define
subtraction between two vectors, since there is no single variable variation of /.
a = b * c;
where b is the vector and c is the floating-point number. This won't work if b is
the floating-point number and c is the vector, since we haven 't provided for
overloading in this way. To do so, we would have to overload the multiplication
operator for the class float. Unfortunately, C++ won 't recognize standard
number types as classes, even though they have a lot in common. Next, look at
the operator for defining the dot product of two vectors. The dot product is a
49
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
*/
e x t e r n c h a r s t r i n g_b u f [ 3 2 J ;
/*
Vector Constructors
*/
Vecto r : : Vecto r ( )
{
x O;
=
y 0;
z 0;
50
TH REE D I M E N S I O N A L V E C T O R M AT H E M AT I C S W I T H C + +
y yl ;
z z1 ;
=
/*
Vector Overl oad of + Ope rator
*/
V e c t o r V e c t o r : : o p e r a t o r+ ( V e c t o r & a r g )
{
Vector resul t ;
resul t . x x + a rg . x ;
res u l t . y =
y + a rg . y ;
res u l t . z =
z + a rg . z ;
retu rn res u l t ;
/*
V e c t o r O v e r l oad o f - Ope r a t o r ( a - b )
*/
res u l t . z =
z - a rg . z ;
retu rn resul t ;
51
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
/*
I
Vector Ove r l oad of - Ope r a t o r ( - a )
*/
/*
11 "' ° C t o r O v e r l o a d o f * O p e r a t o r ( V e c t o r T i me s a V e c t o
*/
/*
V e c t o r O v e r l oad of * Ope r a t o r ( Ve c t o r T i mes a F l oa t )
*/
52
T H R E E D I M E N S I O N A L V E C T O R M AT H E M AT I C S W I T H C + +
/*
V e c t o r O v e r l o a d o f I O p e r a t o r ( V e c t o r D i v i d e d by a F l o a t )
*/
V e c t o r Vecto r : : ope r a t o r / ( fl o a t a rg )
{
Vecto r res u l t ;
res u l t . x x I a rg ;
res u l t . y = y I a rg ;
re s u l t . z = z I a rg ;
return res ul t :
/*
Vector Overl oad of Ope r a t o r
*/
V e c t o r V e c t o r : : o p e r a t o r= ( V e c t o r & r v a l u e )
{
x = rva l ue . x :
y rva l ue . y ;
z rva l ue . z ;
return *thi s ;
/*
V e c t o r O v e r l o a d o f % O p e r a t o r ( D o t P r o d u c t o f Two V e c t o r s )
*/
fl o a t V e c t o r : : ope r a t o r % ( V e c t o r & a rg )
{
fl oat resul t ;
res u l t = x*a rg . x + y*a rg . y + z*a rg . z :
return resul t ;
53
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
*/
I*
V e c t o r O v e r l o a d o f - O p e r a t o r ( N o rm a l i z e a V e c t o r )
*/
V e c t o r V e c t o r : : o p e r a t o r- ( )
{
Vector resul t ;
fl oat l ;
l = *thi s % *thi s ;
l = s q rt ( l ) ;
resul t . x x/l ;
resul t . y = y / l ;
res ul t . z = z / l ;
return resul t ;
I*
max Re t u r n t h e m a x i m u m o f t w o v e c t o r s
*/
resul t . x MAX ( x , a rg . x ) ;
resul t . y MA X ( y , a r g . y ) ;
resul t . z MA X C z , a r g . z ) ;
ret u rn res ul t ;
54
T H R E E D I M E N S I O N A L V E C T O R M AT H E M AT I C S W I T H C + +
/*
mi n R e t u r n t h e m i n i m u m o f two v e c t o r s
*/
re s u l t . x M I N C x , a rg . x ) ;
resul t .y M I N C y , a rg . y ) ;
resul t . z M I N C z , a rg . z l ;
return resul t ;
/*
Rot a t e a Vector
*/
V e c t o r t emp , re s u l t ;
/*
Re v e r s e R o t a t e a V e c t o r
*/
V e c t o r V e c t o r : : R e v_R o t a t e C f l o a t c o s l , f l o a t s i n l , f l o a t c o s 2 ,
fl oat s i n 2 l
55
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
Vector temp , r e s u l t :
temp . x x·
resul t .y = y * cos2 + z * -sin2 :
temp . z = y * s i n2 + z * cos2 ;
re s u l t . x= temp . x * - c o s l + t em p . z * s i n l :
re s u l t . z= temp . x * - s i n l + temp . z * - cos l :
return ( res u l t ) ;
I*
Pri nt Out Vector Contents
*/
/*
G e t V e c t o r f r om i n p u t f i l e
*/
v o i d V e c t o r : : g e t_v e c t o r ( )
{
g e t_s t r i n g ( s t r i n g_b u f ) ;
x = a t o f ( s t r i n g_b u f ) ;
g e t_s t r i n g ( s t r i n g_b u f ) ;
y = a t o f ( s t r i n g_b u f ) ;
g e t_s t r i n g ( s t r i n g_b u f ) ;
z = a t o f ( s t r i n g_b u f ) ;
56
T H R E E D I M E N S I O N A L V E C T O R M AT H E M AT I C S W I T H C + +
Next look at the operator used to normalize a vector. In this case, we want
an operator that accepts only one input parameter. The - normally gives the user
the complement of an integer, but is also overloaded to be the destructor for an
object. U sing it for the normali ze operati on means that we won ' t have a
destructor for vectors, but this doesn 't really present a problem, since we aren't
going to be creating a lot of vectors that have to be removed from memory at
some later point. Normalization simply divides all components of the vector by
its magnitude so that the resulting vector has a magnitude of one.
Next we have two rotation functions. The first rotates the vector a specified
angle around the y axis and then another specified angle around the x axis. The
second rotates in the reverse direction, first by a specified angle around the x
axis and then by a specified angle around the z axis.
The print function is an overload of the << operator of the ostream class to
make it possible to use cout, for example, with vectors as well as other types of
data.
57
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
58
CHAPTE R 5
The header begins with a number of #define statements. These are strictly
for convenience in understanding the software. When we get into the subject of
communicating with the ray tracer (Chapter 8 ) we ' ll see that the heart of
communication is reading a string from a data file and comparing it with all
acceptable strings and a s s i gn i n g a type . The type i s simply a number
corresponding to the position of the matching string in the array. As we proceed
further with the input process, we often set up switch statements that take
different actions depending upon which type a string is. If the switch statement
simply provided different actions for different type numbers , it would be
obscure. We would have to go back to the string array each time to determine
which type of object we were dealing with. To clarify this whole process, for
each type we have defined a title that essentially matches the original kind of
string to be equal to the type number (the position in the array). Thus in a switch
statement, we can give this title instead of the number, and the user can identify
what type of string is being processed.
Next, we define some constants that will be used throughout the program.
Most of them are self-evident. A few need to be set up in the main program; we
list them here as extern so that they will be passed as global variables.
59
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
/*
Heade r Fi l e for Ray T ra c i ng P rogram
By R o g e r T . S t e v e n s 3/1 /90
-
*/
#i n c l ude <stdl i b . h>
#i n c l ude <stdi o . h>
#i n c l ude <ma t h . h >
#i n c l ude "vmath . hpp"
I*
Obj ect Defi n i t i on s
*/
#de f i n e P A T T_H E A D E R 0
#d e f i n e L I NE 1
#d e f i n e SPHERE 2
#de f i n e P A RA L L E L O G RAM 3
#d e f i n e T R I ANGLE 4
#d e f i n e LAM P 5
#d e f i n e O B S E RV E R 6
#d e f i n e G RO U N D 7
#d e f i n e S KY 8
#d e f i n e BBOX 9
#de f i n e R I NG 10
#d e f i n e Q U A D RAT I C 11
#d e f i n e B E G I N_B B O X 12
#d e f i n e E N D_B B O X 13
#d e f i n e B E G I N_ I N S T A N C E S 14
#d e f i n e E N D_ I N S T A N C E S 15
#d e f i n e AMB 16
#d e f i n e D I FF 17
#d e f i n e M I RROR 18
#d e f i n e TRANS 19
#d e f i n e D E N S I TY 20
#d e f i n e I NDEX 21
#d e f i n e D I TH E R 22
#d e f i n e SREFLECT 23
#de f i n e REFLECT 24
#d e f i n e LOC 25
#d e f i n e RAD I U S 26
60
R AY T R A C I N G O B J E C T ST R U CT U R E S
#d e f i n e PAt t e r n 27
#d e f i n e REMO V E 28
#d e f i n e XMU LT 29
#d e f i n e YMU LT 30
#d e f i n e NAME 31
#d e f i n e D I ST 32
#d e f i n e L O O KAT 33
#de f i n e Vl 34
#de f i n e V2 35
#d e f i n e Z E N I TH 36
#d e f i n e HOR I Z 37
#d e f i n e R A D_ l 38
#d e f i n e R A D_2 39
#d e f i n e A 40
#d e f i n e B 41
#d e f i n e c 42
#d e f i n e D 43
#d e f i n e E 44
#d e f i n e XMAX 45
#d e f i n e YMAX 46
#d e f i n e ZMAX 47
#d e f i n e XM I N 48
#d e f i n e YM I N 49
#d e f i n e ZM I N 50
#d e f i n e DIR 51
#d e f i n e FOC_L E N GTH 52
#d e f i n e F I R S T_S C A N 53
#de f i n e D E FA U L T 54
#d e f i n e F I L E_ N A M E 55
#de f i n e L A S T_S C A N 56
#d e f i n e XRES 57
#d e f i n e YRES 58
#d e f i n e X_S I Z E 59
#d e f i n e Y_S I Z E 60
#d e f i n e S T A R T_ X 61
#d e f i n e S T A RT_Y 62
#d e f i n e E N D_X 63
#d e f i n e E N D_Y 64
#d e f i n e P A REN 65
#d e f i n e N O_S H A D O W 66
#d e f i n e N O_ L A M P 67
/td e f i n e THRESHOLD 68
61
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
#d e f i n e UP 69
#d e f i n e I N STAN C E O F 70
#d e f i n e SCALE 71
#d e f i n e RE CTAN G L E 72
#d e f i n e C I RC L E 73
#d e f i n e PO LYGON 74
#d e f i n e CO LOR 75
#d e f i n e PO I NT 76
#d e f i n e CONE 77
#d e f i n e H E I GHT 78
#d e f i n e F R AC T A L 79
#d e f i n e D I MENS I ON 80
#d e f i n e SCA LAR 81
#d e f i n e NUl l 82
#d e f i n e l a s t_n o 83
I*
U s e f u l Con s t a n t s
*I
#d e f i n e T R U E 1
#d e f i n e FA L S E 0
#d e f i n e S M A L L 0 . 00 1
#d e f i n e A S P E C T 1 .0 II a s pect rati o
#d e f i n e C N U M 63 II n umber o f s h a d e s of c o l o r mi n u s o n e
#d e f i n e M A X_ I X 4 II maxi mum x i n t e r p o l a t i on
#d e f i n e M A X_ I Y 4 II maxi mum y i n t e r p o l a t i on
#d e f i n e m a x_p i x e l 800 II m a x o f R G B a r r a y s i z e ( d o t s p e r r ow )
extern i nt XS I ZE ;
extern i nt YSI ZE ;
extern i n t C ENTERX ;
e x t e r n i n t C E N T E RY ;
e x t e r n i n t X S I Z E4 ;
I*
Col o r Data Defi n i t i on s
*I
62
R AY T R A C I N G O B J E C T S T R U CT U R E S
c l a s s c o l o r_d a t a
{
publ i c :
Vector amb , I I amb i e n t l i g h t i n g
d i ff . I I d i ff u s e l i g h t i ng
mi rror . I I % l i g ht refl ected
trans . I I % l i g h t t r a n s m i t t ed
d e n s i ty ; I I d e n s i ty
fl oat refl ect . I I p e r c e n t s p e c u l a r l y refl ec ted
i ndex ; I I i n dex i f refract i on
short s refl ect , I I s pecu l a r refl coeffi c i ent
di ther ; I I col o r di theri ng
c o l o r d a t a o p e r a t o r= C c o l o r_d a t a & ) ;
l ;
I*
C l a s s defi n i t i on for Li ne
*I
cl ass Li ne
{
publ i c :
Vector l oc , d i r ;
i nt fl ag ;
l ;
I*
C l a s s defi n i t i on f o r Lamp
*I
c l a s s Lamp
{
publ i c :
Vector l oc ;
fl oat radi us . di stance ;
L a m p * n e x t_ l a m p ;
l ;
I*
63
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
*I
cl ass Pattern
{
publ i c :
short type : II type of pattern
fl oat xsi ze . II pattern s i ze i n x d i rect i on
ysi ze , II pattern s i ze i n y d i rect i on
sta rtx , II x c o o rd i n a te s t a r t i n g po s i t i on
s t a rty , II y coord i n a te s t a rt i ng pos i t i on
endx , II x c o o rd i n a t e en d i ng po s i t i on
e n dy , II y c o o rd i n a te end i ng po s i t i on
radi us ; II radi us of ci rcl e pattern
c o l o r_d a t a c o l _d a t a : II c o l o r i n forma t i on
char n a me [ 3 2 J ; II n a me o f p a t t e r n
Pattern *chi l d ,
*s i bl i ng ,
*l i n k :
};
I*
C l a s s Defi n i t i on s for Obj ect
*I
c l a s s Obj ect
{
publ i c :
unsi gned c h a r type , I I obj ect type
fl ag :
cha r n a me [ l 6 J ; I I o b j e c t n a me
Vector l OC , I I obj ect l oc a t i on
vectl , I I t h ree vectors
vect2 ,
vect3 .
l ow e r , I I l owe r b o u n d
uppe r , I I uppe r bound
n o rm :
fl oat c t e rm , I I u s ed for q u a d r a t i c
64
R AY T R A C I N G O B J E CT S T R U C T U R E S
II s u r f a c e s on l y
xm u l t . II x mul t i pl i e r for
II patterns
ymul t , II y mu l t i p l i e r f o r
II pattern
nl , II p r e c om p u t e d v a l u e s
l en 1 ,
l en2 ,
cosl .
sin1 ,
cos2 ,
si n2 :
c o l o r_d a t a * c o l _d a t a : I I c o l o r i n f o rma t i o n
Obj ect *nextobj , I I addr o f next obj ect i n l i st
*c h i l d : I I add res s of c h i l d for
II bound i ng boxes
Pattern *pattern , I I a d d r of pattern s t ructure
* r em o v e : I I a d d r e s s o f s t r u c t t o r e mo v e
I I obj s e c t i on
O b j e c t o p e r a t o r= ( O b j e c t & ) :
v i r t u a l v o i d F i n d N o r m ( V e c t o r * n o rma l , V e c t o r * p o s i t i o n ) :
v i rtua l v o i d Po s i t i on ( f l oa t * po s l , fl oat *pos 2 , Vector
*l ocat i on ) :
v i r t u a l i n t Col l i s i onTes t ( Li ne * l i ne , f l oat *t ) :
v i rtua l v o i d F i nd Bbox ( Vector * v l . Vector * v2 ) :
v i r t u a l v o i d S c a l e_ I n s t a n c e ( V e c t o r *mu l t , i n t f f l a g ) ;
}:
65
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
Tri angl e( ) :
v o i d F i n d N o rm ( V e c t o r * n o rm a l , V e c t o r * p o s i t i o n ) ;
v o i d Pos i t i on ( f l o a t * pos l , f l o a t *po s 2 . Vector * l oca t i on ) :
i n t Col l i s i onTest ( L i n e * l i ne , fl oat *t ) ;
voi d Fi ndBbox ( Vector * v l , Vector * v 2 ) ;
v o i d S c a l e_ I n s t a n c e ( V e c t o r *m u l t , i n t f f l a g ) ;
}:
66
R AY T R A C I N G O B J E C T S T R U C T U R E S
i n t C ol l i s i onTe s t ( L i n e * l i n e , fl oat *t ) ;
voi d Fi ndBbox ( Vector * v l , Vector * v2 ) ;
I ;
I*
Structure for the Worl d
*I
ty p e d e f s t r u c t wo r l d
{
Obj ect * stack , II l i s t of obj e c t s i n
II pi cture
* i nstances ; II l i st of user defi ned
II pri mi ti ves
Lamp * l amps ; II l i s t o f l a mp s
Li ne * l i ne ;
i nt obj count . II n um b e r o f o b j e c t s
l a mp c o u n t , II n umbe r o f l amps
f i r s t_s c a n , II fi rst scan l i ne
l a s t_s c a n ; II l ast scan l i ne
l ong r a y_ i n t e r s e c t s , II stati sti cs
p r i m a ry_t r a c e d ,
t o_ l a m p ,
r e f l _t r a n s .
b b o x_i n t e r s e c t s .
i n t e r s e c t_t e s t s ,
p i x e l s_h i t ,
p a t t e r n_ma t c h e s ;
Vector obs ri ght , II obs e r v e r r i ght d i rect i on
obsup , II observer u p di recti on
obsl oc , II l ocati on o f observer
obsdi r , II di recti on i n whi ch observer
II l oaks
s ky c o l o r_h o r i z , II s ky c o l o r a t h o r i z o n
s ky c o l o r_z e n i t h ; II s ky c o l o r a t z e n i t h
fl oat s ky_d i t h e r ;
Pattern * pa tl i st ; I I l i s t o f pattern add res s e s
fl oat fl ength . 11 fo c a l l e n g t h
g l obi ndex ; 1 1 g l oba l i ndex of
II refra c t i on
67
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
Wo r l d :
I*
M a t h Defi n i t i on s
*I
I*
S t r u c t u r e of Defa u l t V a l ues
*I
t y p e d e f s t r u c t d e f_s t r u c t
{
c o l o r_d a t a c o l _d a t a : II defa u l t col o r i n fo
short s h a d ow : II c o mp u t e s h a d ow s ?
fl oat th reshol d : II cutoff poi n t for mi n refl ,
II refl rays
short i threshol d : II i n teger v e r s i on o f a bove
DEF ;
I*
Setup of V a r i abl es
68
R AY T R A C I N G O B J E C T S T R U C T U R E S
*I
exte r n Wo r l d WORLD : I I t h e wo r l d o f o b j e c t s i n t h e s c e n e
ex t e r n D E F def : I I d e f a u l t v a l u e s f o r s ome p a r a m e t e r s
extern i n t l i n e n umbe r : I I l i ne counter
I*
Funct i on Prototypes for RENDER . C
*I
voi d i n i t_w o r l d ( v o i d ) :
voi d i n i t_c o l o r ( v o i d ) :
voi d W o r l d_S t a t s ( v o i d ) :
voi d O p e n_ F i l e ( ) ;
voi d C l o s e_ F i l e ( ) :
voi d s c a n ne r ( Obj ect * test ) ;
I*
F u n c t i o n P r o t o ty p e s f o r I N P U T . C
*I
P a t t e r n * A t t a c h_ P a t t e r n ( ) ;
i n t G e t A t t r i b ( i n t t y p e . c h a r s t r i n g_b u f [ J ) :
P a t t e r n * G e t_C i r c l e_P a t t e r n ( ) ;
i n t g e t_c o l o r_d a t a ( i n t t y p e , c o l o r_d a t a * c o l _d a t a ) ;
O b j e c t * g e t_d a t a ( ) :
i n t Ge t la mp ( ) ;
i nt LoadWo r l d ( ) :
O b j e c t * G e t_O b j e c t ( i n t t y p e . O b j e c t * q u e u e ) :
Obj ect * Get P a ra l l el ogram( ) :
i nt Get Pattern ( ) :
P a t t e r n * G e t_P o l y_P a t t e r n ( ) ;
P a t t e r n * G e t_ R e c t_ P a t t e r n ( ) :
Obj ect * GetRi ng ( ) :
Obj ect * GetSphere ( ) ;
i n t g e t_s t r i n g ( c h a r s t r i n g_b u f [ J ) :
P a t t e r n * G e t_S u b P a t t e r n ( i n t t y p e ) ;
69
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
/*
*/
l�
I =====�
F u n c t i o n P r o t o ty p e s f o r RAY . C
v o i d T r a c e_S c e n e ( ) ;
v o i d D i f f u s e C o l o r ( V e c t o r * c o l o r , c o l o r_d a t a * c o l _d a t a . V e c t o r *
n o rm . V e c t o r * l a c ,
Li ne * ol i ne ) :
v o i d D u mp_ L i n e ( i n t l i n e n o , c h a r r [ J , c h a r g [ J . c h a r b [ J ) :
v o i d Amb i entC o l o r ( V e c t o r * c o l o r . c o l o r_da t a * c o l _d a t a , V e c t o r * n o rm ,
Vector * l ac ) :
v o i d T r a n s p a r e n t C o l o r < V e c t o r * c o l o r . c o l o r d a t a * c o l _d a t a ,
Vector *
n o rm . V e c t o r * l a c ,
Li n e * l i n e . fl o a t i nmu l t ) :
v o i d R e f l e c t C o l o r ( V e c t o r * c o l o r , c o l o r_d a t a * c o l _d a t a . V e c t o r *
n o rm . Vector * l ac ,
L i n e * l i n e . fl o a t i nmu l t ) ;
v o i d S ky C o l o r ( L i n e * l i n e . V e c t o r * c o l o r ) :
voi d Di the r ( Vector * col or . fl oat di ther ) :
v o i d D i t h e r ( V e c t o r * c o l o r , c o l o r_d a t a * c o l _d a t a ) :
O bj e c t * I n t e r s e c t ( Obj e c t * C u r rObj , L i n e * l i n e . f l o a t * s h o r t e s t_t i me .
s h o r t s h a d ow_f l a g , s h o r t i n i t_f l a g , V e c t o r * a t t e n ) :
i n t T r a c e_ R a y ( L i n e * l i n e . V e c t o r * c o l o r . f l o a t m u l t i p l i e r ) :
i n t F i n d_C o l o r ( O b j e c t * o b j . P a t t e r n * p a t t e r n . V e c t o r * l o c a t i o n ,
c o l o r_d a t a * c_d a t a , f l o a t x_m u l t , f l o a t y_m u l t ) :
70
R AY T R A C I N G O B J E C T S T R U C T U R E S
We ' re now ready to think about handl ing data within the ray trac ing
program. The first C++ class we are going to set up is color_data. This is not a
very intere sting c l a s s , since it c ontains only one embedded function. It
represents all color characteristics that are likely to be associated with an object.
A number of these are defined as vectors, which permits them to be treated with
vector mathematics, although in this case, the three vector components refer to
values of red, green , and blue that make up the color rather than to position data.
All of these values are assumed to vary between zero and the maximum color
value (63).
The first color to be defined is that for ambient light that falls upon the
object. The second color is the diffused color, i.e. , the inherent color of the
object (the color that it is painted, if you will). If you look around at various
objects, you can recognize that you do not actually see the diffuse color of an
object at any point on the object, but rather one that depends upon how the object
is lighted. The next defined color is the mirror color, which is the proportion of
each color reflected by the object. If this is (63, 63, 63), you have a perfectly
reflecting mirror; if it is (0,0,0), which is the default value, the object has no
mirror-like quality. Other values can cause partial or colored mirror reflection.
The next color is the transparency value. It defines the percentage of each color
transmitted through a transparent object. Next comes the density factor, which
determines how light of each color is attenuated as it passes through a semi
transparent object. These are all of the color vectors associated with an object.
71
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
later on the ray tracing program can scan them and determine what to do about
intersecting a ray with each object.
Now let's see what happens when we want to retrieve data from this list of
objects. We first go to the address specified by WORLD.stack. There, we find
the data for the last object we generated and process that. Then, we go to the
address specified by the next_object variable in this object. There we find the
data for the next-to-last object we created and process it. We continue this
process until, after we have processed data for the first object generated, we find
that the next object variable contains a NULL, which is a signal for us to quit
since we have come to the end of the list. This is basically how a linked list
works.
However, sometimes things are a little more complicated. Suppose there are
several objects we only want to process if a certain criterion is met. For
example, in attempting to intersect arrays with objects, we often draw a box
around several objects. The data for the box are in our main list. If a light ray
intersects this box, we want to go ahead and process the list of objects that are
within the box; otherwise, we want to ignore them and continue down the main
list. We get around this by having a variable for each object called child.
Now, when we get to the point where we generate the box object, we put the
address of the next main object in the next_object variable as usual, but we put a
NULL in the child address variable. Then we process each of the objects that are
enclosed in the box, each time taking the address from the child address variable
72
R AY T R A C I N G O B J E C T S T R U C T U R E S
and putting it into the next_object address of the current object. We take the
address of the current object and put it into the child address variable of the box.
Now when we process data, each time we meet some preestablished criterion, we
take the address from the associate child address variable and process the data
from that object. We then proceed normally through the list of objects in the
box. But when we come to a NULL, which indicates that we are through with
them, we don 't quit, but go back to the box that had the original child address
and p i c k up the addre s s in the n ext_ object v ariabl e . We then continue
processing.
This procedure adds a nice technique for branching in the list scanning
process. How this all works out for the ray tracing program is shown in Figure
5-2. We pick up the address of the first object in the variable WORLD.stack.
After processing it, we get the next object address from next_object. This
process continues until we come to a bounding box. This has an address in
child. We then branch off and continue the usual process until we hit a NULL
address. We then go back up to the bounding box and pick up its next_object.
When we come to a NULL address in the main stream, the entire process
terminates.
Following this, the Lamp class is defined. This is used for all of the light
sources that are illuminating the scene. It consists simply of vectors defining the
location of the light source, the radius of the light source, and an address for the
next lamp, to permit this to be a linked list. The radius is actually an overkill,
since we won't be concerned about the radius of the light source in this version
of the ray tracing program. For one thing, in all of the demonstration pictures we
are careful to define all of the light sources so that they are located outside of the
73
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
picture. In the future, we might want to include lamps within the picture itself,
in which case more details of the lamp characteristics would have to be included
and treated by the program.
74
R AY T R A C I N G O B J E C T ST R U CT U R E S
The next line is a prototype for the overloading of the = operator to apply to
objects. As previously mentioned, it should not be necessary to overload the =
operator; this should be done automatically for each class that i s created.
However, a current bug in the Zortech C++ compiler makes it necessary to do
this overloading. Then comes a list of prototype virtual functions.
A virtual function is defined for the base class, but it can be redefined for
each class that is derived from the base class. The function can be called as if we
were calling the base class function, and yet the compiler automatically selects
whichever redefined version of the function is appropriate to the derived class
that we are concerned with.
Now, you're wondering what a derived class is. A derived class is a new
class which inherits all of the data members and member functions from one or
more classes that have been previously defined. It is set up in C++ in this
manner;
In this case, Sphere is the new class. It has all the member variables and
member functions of the class Object, which has already been defined. If you
look at Figure 5- 1 , you ' ll see that we have defined six new derived classes, one
for each of five types of primitive objects and one for bounding boxes. Each
derived class has all of the characteristics of the base class. In addition, within
each class description you will see prototypes for each redefinition of each
virtual function that is redefined for this class. In Chapter 8, we will list these
redefinitions and describe how these functions are used in further detail.
75
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
WORLD.stack
I
PARALLELOG RAM
child
next_object
I
SPHERE
child
next_object
I
BBOX
child
next_object
I
QUAD RATIC TRIANGLE
child child
next_object next_object
I
PARALLELOG RAM SPHERE
child child
next_object next_object
I
N U LL N U LL
76
R AY T R A C I N G O B J E C T S T R U CT U R E S
for the beginning of the stack (which is the list of objects), the address for the
beginning of instances (which will be described in Chapter 6), the beginning of
the list of lamps and the beginning of the list of lines. A count of the number of
objects and lamps is also kept. Next are variables to store a number of statistics
that are collected during the course of rendering a particular scene and data on
the observer and the sky. This is followed by a list of the addresses of all
patterns. Finally comes the focal length, a global index of refraction, the output
file name and pointer, and two threshold parameters . The focal length is
supposed to be set up to be similar to a 35 millimeter camera, so that if you enter
50 (a 50 mm lens is a normal lens) you will get a normal perspective of the
scene.
77
CHAPTER 6
Rendering the
Scene An Overview
In this chapter, the contents of the file render.cpp are described. The file
principally contains the main program for rendering scenes using the ray tracing
technique . This file is listed in Figure 6- 1 . It gives an overview of the ray
tracing program. Once we have the overview we will look in more detail at the
functions that do the detailed processing. This takes place in later chapters. At
the very beginning of the render.cpp file, a few parameters are initialized. These
include the parameters XSIZE and YSIZE which define the size of the display
screen in pixels. These are default values; you can override them by putting in
new parameters for XRES and YRES in your scene data file. You will want to do
this if you are using a standard VGA card, since the VGA resolution is 320 by
200 pixels, whereas the default values in the program are for a high resolution
super VGA mode of 640 by 480 pixels.
The code for overloading the = operator for the class Object.next appears
next in this file. You 've already encountered the format for overloading of
operators in Chapters 3 and 4. To overload the = operator we simply set each
parameter of one object equal to the corresponding parameter in the other. This
permits us to have a statement like:
79
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
a = b
where a and b are both objects and have the contents of one automatically
transferred to the other. S ince this is a generic overload for the base class object,
it is inherited by all of the classes derived from this base class. If you use it with
a derived class, however, you should be careful to make sure that both a and b
are of the same derived class. In other words, if a is of class Sphere then b must
be of class Sphere also. If this isn't the case, (if a is of class Sphere and b is of
class Parallelogram) you will get a diagnostic telling you that the classes are not
the same and the program won't run. This overloading function is followed by a
similar overloading function for the class of color_data. This overload function
makes it possible to transfer all the color data information from one class
member to another with a simple = statement. It doesn ' t do any harm to
overload the = operator, but it shouldn't be necessary since this is supposed to be
done automatically. With my copy of Zortech C++ the function had to be
specifically overloaded for proper compilation.
/*
R a y t r a c e = S i mp l i f i e d R a y T r a c i n g P r o g r a m
B y Ro g e r T . S t e v e n s - 1 / 6 / 9 0
*/
u n s i g n ed _s t a c k = 3 0 0 0 0 ;
#i n c l ude " rende r . hpp"
#i n c l u d e <dos . h>
#i n c l ude <stri ng . h>
e x t e r n c h a r s t r i n g_ty p e s [ l 2 8 ] [ 3 2 J ;
#d e f i n e MA X X 800
i n t X S I Z E = 640 ;
i n t Y S I Z E = 480 ;
i nt CENTERX XSIZE/2 ;
i n t C E N T E RY YSIZE/2 ;
i n t X S I Z E4 XSIZE/4 ;
i nt i ;
80
R E N D E R I N G T H E S C E N E-AN O V E R V I EW
Worl d WORLD ; I I A l l o f t h e d a t a to be p r o ce s s ed
DEF def ; I I col o r defa u l ts
i nt l i n e n umbe r ;
I* lI�
�
=====-===II
i n i t worl d ( ) I n i t i a l i z e t h e WO R L D
*I
v o i d i n i t_w o r l d ( v o i d )
{
WO R L D . s t a c k NULL ;
WO R L D . i n s t a n c e s NULL ;
WO R L D . p a t l i s t NULL ;
WO R L D . o u t f i l e [ O ] NULL ;
WO R L D . l a m p s NULL ;
WO R L D . l i n e NULL ;
WO R L D . o b j c o u n t O;
WO R L D . l a m p c o u n t O;
WO R L D . f l e n g t h 250 ;
W O R L D . f i r s t_s c a n 0;
W O R L D . l a s t_s c a n YSIZE- 1 ;
WO R L D . ob s u p = V e c t o r ( 0 , 1 , 0 ) ;
WO R L D . ob s l o c = V e c t o r ( 5 0 , 7 0 , 1 1 5 ) ;
W O R L D . s ky c o l o r_z e n i t h = V e c t o r ( ) ;
W O R L D . s ky c o l o r_h o r i z =V e c t o r ( ) ;
W O R L D . s ky_d i t h e r = O ;
W O R L D . r a y_i n t e r s e c t s
W O R L D . p i x e l s _h i t
W O R L D . p r i m a ry_t r a c e d
W O R L D . t o_ l a m p
WO R L D . refl t r a n s
WO R L D . bbox i n t e r s e c t s
W O R L D . p a t t e r n_m a t c h e s
W O R L D . i n t e r s e c t_t e s t s 0;
WO R L D . g l o b i n d e x = 1 . 00 ;
WO R L D . t h re s h o l d = . l ;
W O R L D . i n t_t h r e s h o l d = WO R L D . t h r e s h o l d * C N U M ;
WO R L D . f r a c t a l _d i m = 0 . 9 ;
WO R L D . l e v e l = 4 ;
W O R L D . f r a c t a l _s c a l a r = 0 . 0 0 2 ;
81
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
/*
i n i t_c o l o r ( ) Sets up defa u l t col o r d a t a
*/
v o i d i n i t_c o l o r ( v o i d )
{
def . col data . trans Vector ( ) :
d e f . c o l _d a t a . m i r r o r Vector ( ) :
d e f . c o l _d a t a . a m b Vector ( 25 , 25 , 25 ) :
def . col data . d i ff Vecto r ( 48 , 2 7 , 9 ) ;
d e f . c o l _d a t a . d e n s i ty Vecto r ( . 01 . . 01 . . 01 ) :
d e f . c o l _d a t a . i n d e x CNUM ;
def . col data . di ther 3:
def . col data . refl ect 0:
def . col data . s refl ect 10 :
d e f . s h a d ow = T RU E :
/*
O v e r l o a d of ' = ' ope r a t o r fo r Obj e c t c l a s s
*/
O b j e c t O b j e c t : : o p e r a t o r= ( Q b j e c t & r v a l u e )
{
ty p e = r v a l u e . ty p e ;
s t r c py ( n a m e , r v a l u e . n a me ) :
l oc = rva l ue . l oc :
vectl rva l ue . vectl ;
vect2 rva l ue . vect2 :
vect3 rva l ue . vect3 :
l ow e r r v a l u e . l ow e r :
uppe r r v a l ue . uppe r :
n o rm = r v a l u e . n o rm :
c t e rm r v a l u e . c t e rm :
y t e rm r v a l u e . y t e rm :
xm u l t r v a l u e . xm u l t :
ymu l t rv a l ue . ymu l t :
n l = rval ue . n l :
82
R E N D E R I N G T H E S C E N E-AN OVERV I EW
l en l rval ue . l en l :
l en2 rva l ue . l en2 :
cos l rval ue . cosl :
sinl rval ue . s i n l :
cos2 rval ue . cos2 :
si n2 rva l ue . s i n2 :
c o l _d a t a = r v a l u e . c o l _d a t a :
n extobj = r v a l u e . n ext obj :
chi l d = rval ue . chi l d :
pattern = rva l ue . pattern :
r e mo v e = r v a l u e . r e m o v e :
ret u rn *thi s :
/*
Overl oad of ' = ' operator for col o r data cl a s s
*/
/*
F u n ct i on to d i s p l ay ray t r a c i n g s t a t i s t i c s
*/
v o i d W o r l d_S t a t s ( )
{
pri ntf(
..
\n ) :
pri ntf(
..
" II 1 1 \n l :
83
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +
pri ntf(
" II Worl d Stat i s t i cs 1 1 \n" l :
pri ntf(
.. 1 1 ..
1 1 \n l :
pri ntf(
" II Obj e ct s : %4d l l \n" .
WORLD . obj count ) ;
pri ntf(
" II Lamp s : %4d l l \n" ,
WO R L D . l a m p c o u n t ) ;
pri ntf(
" II I ntersect tests : %8l d l l \n" .
WO R L D . i n t e r s e c t_t e s t s ) ;
pri ntf(
" II T ot a l i n t e r s e ct i o n s : %8l d l l \n" ,
WO R L D . r a y_i n t e r s e c t s + W O R L D . b b ox_i n t e r s e c t s ) ;
pri ntf(
" II Obj ect i n t e r s e ct i on s : %8 l d l l \n" .
WO R L D . r a y_i n t e r s e c t s ) ;
pri ntf(
" II Boundi ng B o x i ntersect i ons : %8l d ll \n" .
W O R L D . b b ox_i n t e r s e c t s ) ;
pri ntf(
" 11 Rays t r a ced : %81 d 1 1 \n" .
W O R L D . p r i ma ry_t r a c e d + W O R L D . t o_l a m p +WO R L D . r e f l _t r a n s ) ;
pri ntf(
" II P r i m a ry : %8l d ll \n" ,
W O R L D . p r i m a ry_t r a c e d ) ;
pri ntf(
" II To l amps : %8l d ll\n" ,
W O R L D . t o_l a m p ) ;
pri ntf(
" II Re f l e c t e d o r T r a n s m i t t e d : % 8 1 d 1 1 \n" .
WO R L D . r e f l _t r a n s ) ;
pri ntf(
" II P a t t e r n ma t c h e s : %8l d 11 \n" .
WO R L D . p a t t e r n_m a t c h e s ) ;
pri ntf(
" II Data set to fi l e : %12s 1 1 \n" .
84
R E N D E R I N G T H E S C E N E-AN OVERVIEW
WO R L D . o u t f i l e ) ;
pri ntf(
.. 1 1 ..
11 \n l ;
p r n t f
.. l!::
I ======================::!lh n .. ) ;
/*
F u n ct i on t o open f i l e a n d e n t e r i ma g e s i z e
*/
v o i d O p e n_ F i l e ( )
{
i f ( ( W O R L D . f i l e p t= f o p e n ( W O R L D . o u t f i l e , "w b " ) ) ==N U L L )
{
cout << "Unabl e to open output fi l e" ;
ex i t ( l ) ;
/*
Funct i on to c l ose output fi l e
*/
v o i d C l o s e_ F i l e ( )
{
i f ( f c l o s e ( WO R L D . f i l e p t l l
{
cout << "Unabl e to cl ose output fi l e" ;
exi t ( l ) ;
85
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
/*
*/
ma i n ( )
{
Obj ect *test , *test2 ;
cout «
II
1 1 \n" :
cout «
" II 1 1\n" :
cout «
" II S i mp l i f i ed Ray T r a c i n g P r o g r a m 1 1\n" :
cout «
" II 1 1\n" :
cout «
" II By R o g e r T . S t e v e n s - J a n u a ry 6 , 1 9 9 0 1 1 \n" :
cout «
" II 1 1 \n" :
cout «
" II C omma n d L i n e : r e n d e r < f i l e n a me 1 1 \n" :
cout «
" II 1 1\n" :
cout «
II 1 1 \n" :
i n i t_w o r l d ( ) ;
i n i t_c o l o r ( ) ;
86
R E N D E R I N G T H E S C E N E-AN OVERVIEW
i f ( ! LoadWor l d ( ) )
{
c o u t < < " Sy n t a x e r r o r i n l o a d i n g w o r l d \ n " :
ex i t ( l ) ;
Following this, we have the function World_Stats, used to print out some
statistics about the ray tracing process. These statistics are gathered during the
rendering process and are printed out at the completion of the rendering
program.
The function Open _File opens the data file for the output data. The file
name is that which was read in from the input data. If the file cannot be opened
an error message i s displayed and the program terminates. Otherwise, we
immediately write to the file the information on the pixel size of the display in
the x and y directions.
Next comes the function Close_File, which simply closes the data file. If it
cannot be closed, an error message is displayed and the program terminates.
87
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
shows how the program should be called up. Next, the functions init_world and
init_color are called to provide initialization. The LoadWorld function is then
called to load in all of the information about the scene from the data file.
Following this, we call the function Make_Bbox. This function creates the
bounding boxes, wherever one was called for by the input data. After making
the boxes, the input data file is closed. The program displays pixel size and the
name of the file used to store the output data. The size information is the latest
received from the input data file, if such information existed; otherwise the
default values will be displayed. Next Open_File is called to open the output
data file. The function Trace_Scene is then called. This function supervises all
of the ray tracing activity, including storing the final data to the output file.
When the ray tracing has been completed, Close_File i s called to close the
output data file. We then call World_Stats to display the statistics that were
collected during the ray tracing process. After this, the program terminates.
88
CHAPTER 7
Ray Tracing
Rendering Interfaces
The first maj or problem that i s encountered i n designing a ray tracer i s
determining the proper method of communicating the data describing the scene
to the program . Thi s includes descriptions of primitive objects (spheres,
parallelograms and quadratics), information on patterns applied to surfaces, a
description of background or sky, a definition of light sources which illuminate
the picture, and the position of the camera or observer. It would certainly be
ideal if there was a standard adopted for every interface with a ray tracing
program. Unfortunately, this is not the case. There seem to be about as many
ways of defining the data for a scene as there are ray tracing programs. We will
discuss a few of the different interface methods used and then go on to develop
our own interface software.
Micro Doc
c/o F. W. Pospeschil
3 1 08 Jackson Street
Bellevue, Nebraska 68005
89
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
Some of these standard displays are beyond the capabilities of the simple ray
tracer described in thi s book. (They were designed for use with ray tracers
associated with work stations, minicomputers, or mainframes.) However, many
of the standard displays can be simplified enough to produce workable data files
for our ray tracing program. One good aspect of Haines software is that source
code is provided in C and can be easily modified to create a data file in whatever
format you decide is necessary for interfacing. I wrote a program to transform
one of these data files to the format used in the ray tracer described in this book.
The resultant data listing required some message to produce Plate 8. Right now,
we are interested in the format that Haines creates with his software. A partial
listing of one of his data files is given in Figure 7 - 1 . This format is fairly
obscure. You can guess that the first few lines define the observer's position and
that each line beginning with an s defines a sphere . However, if you are
attempting to look at the data file and determine something about the scene, you
may find it rough sledding.
Pixar
3240 Kerner Blvd.
San Rafael, California 9490 1
90
R AY T R A C I N G R E N D E R I N G I N T E R FA C E S
v
f r om 2 . 1 1 . 3 1 . 7
at 0 O O
up O 0 1
angl e 45
hi ther 1
resol u t i on 5 1 2 5 1 2
b 0 . 078 0 . 36 1 0 . 753
1 4 3 2
1 1 -4 4
1 -3 1 5
f 1 0 . 7 5 0 . 33 1 0 0 0 0
p4
12 12 - 0 . 5
- 12 1 2 - 0 . 5
- 12 - 12 - 0 . 5
12 - 12 -0.5
f 1 0.9 0.7 0.5 3 0 0
s 0 0 0 0.5
s 0 . 2 7 2 1 66 0 . 2 7 2 1 6 6 0 . 544331 0 . 1 66667
s 0 . 4 2 0 3 1 4 0 . 4 2 0 3 1 4 0 . 6 1 84 0 5 0 . 0 5 5 5 5 5 6
s 0 . 4 6 1 84 4 0 . 3 0 4 7 0 9 0 . 4 3 3 2 2 0 . 0 5 5 5 5 5 6
s 0 . 3 0 4 0 7 9 0 . 4 6 1 8 44 0 . 4 3 3 2 2 0 . 0 5 5 5 5 5 6
s 0 . 230635 0 . 387 7 7 0 . 7 2 9 5 1 6 0 . 0555556
s 0 . 1 1 50 3 1 0 . 4293 0 . 544331 0 . 0 5 5 5 5 5 6
s 0 . 082487 0 . 239622 0 . 6 55442 0 . 0555556
s 0 . 38 7 7 7 0 . 230635 0 . 7 29 5 1 6 0 . 0555556
It turns out that the RenderMan interface has found a solid niche in the realm
of work stations, particularly in interfacing between programs like AutoCad and
ray tracing programs designed to convert the graphics outputs into realistic three
dimensional scenes. When one closely examines the RenderMan interface, it
does a fine job in this particular area. However, it doesn 't claim to provide all
the three-dimensional functions which might be appropriate to a large mainframe
with higher speeds and more memory than in a work station. On the other hand,
P i x ar i n s i s t s that a R e n derMan program i n c o rporate a l l aspects of the
91
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
RenderMan interface, which is pushing the limits of a PC. Pixar believes that
rendering programs using their interlace should be able to handle complicated
scenes with 1 0,000 to 1 ,000 , 000 primitives. Your ordinary PC is just not going
to be able to do this.
R i A t m o s p h e r e ( n a m e , p a r a me t e r l i s t ) s e t s t h e a tmo s p h e r e
shader .
R i A r e a L i g h t S o u r c e ( n a me , p a r a m e t e r l i s t ) c reates a n a rea l i g ht .
Ri Att r i buteBeg i n ( ) pushes c u r rent set of
attri butes .
Ri Att r i buteEnd ( ) pops c u r rent set of
attri butes .
Ri Ba s i s ( u ba s i s , v ba s i s ) s e t s the ba s i s ma t r i ces
that defi ne patches .
R i B e g i n ( n a me ) beg i n s the g r a ph i cs
state .
Ri Bound ( bound ) sets the bound for a
bound i ng box .
Ri C l i ppi ng ( nea r . fa r ) sets nea r and fa r
cl i ppi ng pl anes .
R i C o l o r S a m p l e s ( n , n RG B , R G B n ) s e t s n um b e r o f c o l o r
c om p o n e n t s u s e d i n
s p e c i fy i n g c o l o r s .
Ri Col o r ( col or ) sets a n obj ect col o r .
Ri C on c a t T r a n s f o rm ( t r a n s form ) c o n c a t e n a t e t r a n s f o rm
onto the c u r rent
t r a n s f o rm a t i o n .
Ri Con e ( h e i g h t , r a d i u s , t h e t a ma x , s e t s p a r a me t e r s f o r a
p a r a me t e r l i s t ) cone .
92
R AY T R A C I N G R E N D E R I N G I N T E R FA C E S
R i De c l a r e ( n a me , d e c l a r a t i o n ) d e c l a r e s n a me a n d ty p e
of a vari abl e .
R i D e f o r m a t i o n ( n a m e , p a r a me t e r l i s t ) c o n c a t e n a t e t h e n a med
d e f o rm a t i o n s h a d e r o n t o
the c u r rent
t r a n s forma t i on .
Ri Dept hOfFi e l d ( fstop , foca l l ength , sets the camera l ens
foca l d i sta n ce ) p a r amete rs .
R i Det a i l Ra n g e ( mi n v i s i b l e , sets the c u r rent deta i l
l owe r t r a n s i t i o n , ra nge .
uppe r t r a n s i t i on , ma xv i s i bl e )
R i Det a i 1 ( b o u n d ) sets the c u r rent deta i l
t o the a rea of the
bound i ng box .
R i D i s k ( h e i g h t , r a d i u s , t h e t a ma x , s e t s t h e p a r a me t e r s f o r
pa rameter l i s t ) a di sk.
R i D i s p l a c eme n t ( n a me , p a r a me t e r l i s t ) sets the cur rent
d i s p l a c eme n t s h a d e r .
R i D i s p l a y ( n a m e , ty pe , mo d e ) s e t s d i s p l a y n a me , t y p e
and mode .
Ri End ( ) end of g raphi cs state .
R i E r r o rM od e ( mode , h a n d l e r ) sets the e r ror handl i ng
mode .
R i E x p o s u r e ( g a i n , g a mm a ) c o n t r o l s s e n s i t i v i ty
a n d n o n - l i n e a r i ty o f
expos u re p roce s s .
R i E x t e r i o r ( n a me , p a r a me t e r l i s t ) sets c u r rent exte r i o r
v o l ume s h a d e r .
R i F o rm a t ( x r e s o l u t i o n , y r e s o l u t i o n , sets resol u t i on and
p i xel a s pectra t i o ) a s pect r a t i o .
R i F r ameA s p e c t Ra t i o ( f r amea s p e c t r a t i o ) s e t s f r a me a s p e c t
rati o .
R i F r a me B e g i n ( f r a m e ) s t a r t of f rame .
Ri FrameEnd ( ) end of f rame .
Ri Gen e ra l P o l y g on ( n l oops , n v e r t s , defi ne genera l concave
p a r a me t e r l i s t ) pol ygon .
93
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
R i G e o me t r i c Ap p r o x i m a t i o n ( ty p e , v a l u e ) method of a p p r ox i ma t i n g
a sma l 1 s u rface
e l emen t .
R i G e o m e t ry ( ty p e , p a r a m e t e r l i s t ) defi nes an
i mp l e me n t a t i o n
s p e c i f i c g e om e t r i c
pri mi ti ve .
R i H i d e r ( ty p e , p a r a m e t e r l i s t ) con t rol s h i dden s u rface
a l gori thm .
R i Hy p e r b o l o i d ( p o i n t l , p o i n t 2 , t h e t a m a x , defi nes a hype rbol oi d .
p a r a me t e r l i s t )
R i I d e n t i ty ( ) s e t c u r rent
t r a n s f o rm a t i o n t o
i d e n t i ty .
Ri I l 1 umi n a t e ( 1 i g h t , onoff ) a d d o r r e mo v e a n a r e a
l i ght source to the
1 i st .
R i l m a g e r ( n a me , p a r a m e t e r l i s t ) s e l e c t a n i ma g e r
fun c t i on .
Ri l n t e r i o r ( n ame , pa ramete r l i s t ) sets the current
i n t e r i o r v o l ume s h a de r .
R i l i g h t S o u r c e ( n a me , p a r a m e t e r l i s t ) add a non - a rea l i g h t
sou rce to the l i s t .
Ri Ma k e B ump ( p i c t u ren ame , tex t u ren ame , convert a hei ght fi el d
swra p , twra p , f i l terfunc , swi dth , i m a g e i n t o a b um p m a p
twi d t h , pa ramete r l i s t ) fi l e .
R i M a k e C u b e F a c e E n v i r o n m e n t ( p x , n x , py , p r o j e c t e n v i r o n me n t
ny , pz , n z , tex t u r e f i l e , fov , on t o s i x c u be f a c e s .
f i l t e r f u n c , s w i d t h , tw i d t h ,
pa ramete r l i s t )
R i M a k e l a t t l o n g E n v i r o n me n t ( p i c t u r e f i l e , c o n v e r t a n i ma g e i n to a
textu refi l e , f i l terfunc , swi d t h , l a t i tude - l o n g i tude ma p .
t w i d t h , p a r a me t e r l i s t )
R i M a k e S h a d ow ( p i c t u r e f i l e , t e x t u r e f i l e , c on v e r t a depth
pa ramete r l i st ) i ma g e f i l e
94
R AY T R A C I N G R E N D E R I N G I N T E R FA C E S
i n t o a s h a d ow m a p .
Ri Ma keTex t u r e ( p i c t u ren ame , texturen ame , c o n v e r t a n i ma g e
s w r a p . tw r a p . f i l te rf u n c . swi d t h . i n to a texture fi l e .
twi d t h , pa ramete r l i s t )
Ri Matte ( ) i ndi cates that
s u bsequent obj ects a re
matte obj ects .
Ri Moti onBegi n ( n , tO , t l , . . . , tn ) s t a rt the defi n i t i on of
a mov i ng p r i mi t i v e .
Ri Mot i on End ( ) end t h e defi n i t i on o f a
mov i n g p r i mi t i v e .
R i N u P a t c h ( n u , u o r d e r . u k n o t , um i n , c re a t e a B - s p l i n e
umax , n v , v o rd e r , v k n o t , vm i n , vma x , surface patch .
pa rameterl i st .
Ri Obj ectBeg i n ( ) s t a r t obj ect
defi n i ti on .
Ri Obj e c t E n d ( ) end obj ect defi n i t i on .
R i O p a c i ty ( c o l o r ) set the c u r rent col o r .
R i O p t i o n ( n a me , p a r a me t e r l i s t ) s e t i mp l eme n t a t i o n
speci fi c opt i on .
Ri O r i enta t i on ( o r i enta t i on ) s e t s o r i e n t a t i on to
r i g h t - h a n ded o r l ef t
h a n ded .
Ri P a r a b o l o i d ( rma x , zm i n , zma x , t h e tamax , defi nes a p a r a bol o i d .
p a r a me t e r l i s t )
R i P a t c h M e s h ( ty p e , n u . u w r a p , n u s t e p , n v , s pe c i f i e s a
v w r a p , n v s t e p , p a r a me t e r l i s t ) q u a d ra l a t e r a l mes h of
patches .
R i P a t c h ( ty p e , p a r a me t e r l i s t ) defi nes a s i ngl e patch .
Ri P e r s pe c t i v e ( fo v ) concatenates a
p e r s pe ct i v e
t r a n s f o rm a t i o n o n t o t h e
c u r r e n t t r a n s fo rm a t i o n .
R i P i x e l F i d e l i ty ( v a r i a t i o n ) s e t s t h e a mo u n t i ma g e
v a l u e s c a n d e v i a t e f r om
t rue v a l ues .
95
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
R i P i x e l F i l t e r ( f i l t e r f u n c , xw i d t h , sets anti a l i a s i ng
ywi d t h ) fi l te r .
Ri P i xe l Sampl es ( xs ampl es , y s ampl es ) sets s ampl i n g rate .
Ri Poi n tsGen e r a l Po l ygon s ( npol y s , n l oops , defi nes general
nverts , verts , pa rameter l i s t ) pol ygon s .
Ri Poi n t s Po l ygons ( n pol y s , nverts , verts , defi nes pol ygon s .
p a r a me t e r l i s t )
R i P o l y g o n ( n v e r t s , p a r a me t e r l i s t ) sets no . of v e r t i ces
for pol ygon
R i P r o c ed u r a l ( d a t a , b o u n d , s u b d i v i d e f u n c , defi nes a p rocedu r a l
f reefun c ) f u n c t i on .
R i P r o j e c t i o n ( n a me , p a r a m e t e r l i s t ) s e t s ty p e o f
p roj e c t i on .
R i O u a n t i z e ( ty p e , o n e . m i n , m a x , s e t s t h e q u a n t i z a t i on
ddi therampl i tude ) p a r amete r s .
R i Re l a t i v e D e t a i l ( r e l a t i v e d e t a i l ) sets rel a t i ve l evel of
deta i l .
R i Re v e r s eO r i e n t a t i o n ( ) c a u s e s c u r rent
o r i en tati on to be
toggl ed .
R i Ro t a t e ( a n g l e , d x , dy , d z ) conca ten a tes a rota t i on
onto the current
t r a n s f o rm a t i o n .
Ri Sca l e ( s x , sy , s z ) concatenates a sca l i ng
onto the c u r rent
t r a n s f o rm a t i o n .
R i S c r e e n W i n d ow ( l e f t , r i g h t , t o p , b o t t om ) d e f i n e s a w i n d ow .
R i S h a d i n g i n t e r p o l a t i o n ( ty p e ) control s shadi ng .
Ri Shadi ngRate ( s i ze ) sets c u r rent shadi ng
rate .
Ri S h u t te r ( mi n . ma x ) sets ti mes t h a t s h utter
open s and c l oses .
Ri S i des ( s i des ) dete rmi nes wh e t h e r
s u rfaces a re one o r
t wo - s i d e d .
R i S k ew ( a n g l e , d x l , dy l , d z l , d x 2 , dy 2 , d z 2 ) c o n c a t e n a t e s a s k ew
96
R AY T R A C I N G R E N D E R I N G I N T E R FA C E S
97
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +
When setting up a standard, it is not a good idea to try to make the standard
be all things to all people. Pixar is wise in not trying to make the RenderMan
interface equally applicable to PC 's and mainframes. Pixar does have a piece of
software called PhotoRealistic RenderMan, which works on a PC, but it requires
a 386 machine having a 387 math coprocessor and at least two megabytes of
memory. Not everyone has such a high-powered computer readily available. In
any case, the RenderMan interface seems to be overkill for the simple ray tracer
described in this book. Furthermore, casting everything in the C language fails
to take advantage of the natural improvements available for thi s type of
operation using C++. So we need to look further.
98
R AY T R A C I N G R E N D E R I N G I N T E R FA C E S
hesitate to add additional commands to make things easier. Finally, since the
number of primitive objects that are defined is small, the techniques used
together with the characteristics of the C++ language make it easy for you to add
additional objects and include them as part of the new descriptive language. In
the following chapter, we will describe our technique for reading in scene data.
99
CHAPTER 8
r e n d e r f i l e n a me
where render is the name of our ray-tracing program and filename is the name of
the file containing the data for the scene you want to render. For convenience,
we have assigned the extension ray to all files containing scene data, but this is
not essential. The input.cpp file is listed in Figure 8- 1 .
1 01
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
a character from the input data file. It converts this character to upper case
lettering. If the comment flag is zero, it checks to see if the character is a letter, a
number, a decimal point, a minus sign, or a right parenthesis. These are the only
acceptable characters for the beginning of a string. The letters and numbers can
be the beginning of a name ; the decimal point and minus sign can be the
beginning of a numeric quantity. If an acceptable character is encountered, it is
placed as the first character in the string buffer; if the character is not acceptable,
it is ignored. Two other characters are checked, the right and left curly brackets.
If the left curly bracket is encountered, the comment flag is set to one; if the
right, zero. Once the flag is set, all characters are ignored until the flag is reset,
so that any comments between curly brackets are ignored.
Next, the function checks the string it has created against an array of
acceptable strings. If a match is encountered, the function terminates, returning
the number of the matching string in the array. If no match is found, the last
number (which doesn 't correspond to any matching string location) is returned.
Finally, there is a display message of the string and its type. This message is
normally commented out, but if you are having real trouble getting a data file to
read, you can recompile with this message in the program and locate exactly
where your difficulty is.
1 02
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R
At the beginning of the input.cpp file, you will see the function LoadWorld,
but it is not very interesting. All it does is call the function get_data, place the
return address from this function in WORLD .stack, and return a TRUE.
The get_data function scans right down through the entire scene data file,
collecting inputs and processing them, until an error occurs or the file comes to
an end. The first thing that this function does is to return a NULL if the file end
has already been encountered (the file is empty). If there is some file data, the
function goes into a while loop and begins its work by using the parser to read
the first data string from the file. It then sets the parameter found to FALSE.
The get_data function is going to process four different kinds of inputs. The
first of these i s attribute . This type of input includes lamp characteristics ,
observer characteristics, patterns, etc. The second type o f input is an instance.
An instance is a user-defined object, consisting of a group of primitive objects
used at different places in the scene. The third kind of data concerns bounding
boxes. When the data specifies a bounding box, the program must generate a
box around all the objects listed within the box . The fourth kind of data is
objects. These are the primitives that compose the scene.
1 03
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
/*
i n p u t . c p p = F u n c t i o n s t o r e a d d a t a f r om d i s k f i l e
By R o g e r T . S t e v e n s - 3 / 22 /90
*/
c h a r s t r i n g_ty p e s [ l 2 8 J [ 3 2 J
{ " P ATT_H E A D E R " , " L I N E " , " S P H E R E " , " P A RA L L E L O G RA M " , " T R I A N G L E " , " LAM P " ,
" O B S E R V E R " , " G RO U N D " , " S KY " , " B B O X " , " R I N G " , " Q U A D RAT I C " , " B E G I N_B B O
" , " E N D_B B O X " , " B E G I N_ I N S T A N C E S " , " E N D_ I N S T A N C E S " , " A M B " , " D I F F " ,
" M I R RO R " , " T RA N S " , " D E N S I T Y " , " I N D E X " , " D I T H E R " , " S R E F L E C T " ,
" R E F L E C T " , " L O C " , " RA D I U S " , " P ATT E R N " , " R E MO V E " , " X M U L T " , " Y M U L T " ,
" N A M E " , " D I S T " , " L O O KA T " , " V l " , " V 2 " , " Z E N I T H " , " H O R I Z " , " RA D_l " ,
" RA D_2 " , " A " , " B " , " C " , " D " , " E " , " X M A X " , " Y MA X " , " Z M A X " , " X M I N " , " Y M I N "
, " Z M I N " , " D I R " , " F O C _ L E N G T H " , " F I R S T_S C A N " , " D E FA U L T " , " F I L E_NAM E " ,
" LA S T_S C A N " , " X R E S " , " Y R E S " , " X_S I Z E " , " Y_S I Z E " , " S T A RT_X " , " S TA R T_Y
" , " E N D_X " , " E N D_Y " , " ) " , " N O_S H A D OW " , " N O_ L AM P " , " T H R E S H O L D " , " U P " ,
" I N S T A N C E_O F " , " S C A L E " , " R E C T A N G L E " , " C I RC L E " , " P O L Y G O N " , " C O L O R " ,
" P O I N T " , " C O N E " , " H E I G H T " , " F RA C T A L " , " D I M E N S I O N " , " S C A L A R " , N U L L } ;
c h a r s t r i n g_b u f [ 3 2 J ;
c h a r n a me [ 3 2 J :
F I LE *fget ;
/*
Loa dWo r l d ( ) L o a d s t h e W o r l d w i t h d a t a f r om s t d i n
*I
1 04
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R
i n t Loa dWo r l d ( )
{
f g e t = f o p e n ( f i l e_i n , " r b " ) ;
WO R L D . s t a c k= g e t_d a t a ( ) ;
return ( TRUE ) ;
fcl ose ( fget ) ;
/*
g e t_d a t a ( ) G e t s d a t a f r om s t d i n a n d p l a c e s i t i n Wo r l d
*/
O b j e c t * g e t_d a t a ( )
{
Obj ect * queue . * temp ;
B B ox * n ewobj ;
V e c t o r l o c . r a d , d , v 3 . u p p e r . l owe r ;
i n t found . type ;
n a m e [ O ] = N U L L ; q u e u e= N U L L ;
1 o c = Vector ( ) ;
rad = Vector ( ) ;
d = Vector ( ) ;
v3 = Vector ( ) ;
upper = Vector ( ) ;
1 owe r = V e c t o r ( ) ;
i f ( feof ( fget ) ) return ( NU L L ) ;
w h i l e ( ! fe o f ( fget ) )
{
t y p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
i f ( s t r c m p ( s t r i n g_b u f , N U L L ) ==O )
retu rn ( queue ) ;
found = FA LS E ;
i f ( G e t A t t r i b ( ty p e , s t r i n g_b u f ) )
{
found = T RU E ;
i f ( n a m e [ O ] == N U L L )
conti nue ;
1 05
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
ty p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
i f ( ty p e ! = B E G I N_B B O X )
{
c o u t < < " E r r o r : N a me m u s t b e f o l l owed < < " by
' B E G I N_B B O X ' \ n " ;
exi t ( l ) ;
s w i t c h ( ty p e )
{
c a s e B EG I N I N STANC E S :
found = T RU E ;
W O R L D . i n s t a n c e s = g e t_d a t a ( ) ;
brea k ;
c a s e E N D_ I N S T A N C E S :
found = TRU E ;
return ( queue ) ;
brea k ;
c a s e E N D_B B O X :
found = T RU E ;
return ( queue ) ;
brea k ;
c a s e B E G I N_B B O X :
n ew o b j = n e w B B o x ;
s t r c py ( n ew o b j - > n a me , n a me ) ;
n e w o b j - > ty p e = B B O X ;
n ew o b j - > c h i l d = g e t_d a t a ( ) ;
n ew o b j - > n e x t o b j = q u e u e ;
q u e u e = n ew o b j ;
found = T RU E ;
brea k ;
i f ( ty p e == F RA C T A L )
{
i f ( ( t emp=G e t_O b j e c t ( t y p e , q u e u e ) ) ! = N U L L )
{
found TRU E ;
queue temp ;
el se
1 06
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R
i f ( ( t e mp=G e t_O b j e c t ( t y p e , q u e u e ) ) ! = N U L L )
{
found = T RU E :
t e m p - > n e x t o b j =q u e u e :
queue = temp ;
return ( queue ) ;
g e t_s t r i n g ( ) Re a d s a s t r i n g o f d a t a f r om f g e t
*/
i n t g e t_s t r i n g ( c h a r s t r i n g_b u f [ J )
{
char ch ;
i n t fl ag = O , i . resul t . test ;
s t r i n g_b u f [ O J = N U L L :
r e s u l t = l a s t_n o ;
w h i l e ( ! fe o f ( fget ) )
{
c h = touppe r C fgetc ( fget ) ) ;
i f ( f l a g == 0 )
{
i f ( ( i s a l num ( c h ) ) 1 1 ( c h . . . l 1 1 ( ch .-.l I I
( c h == · ) ) ) ·
s t r i n g_b u f [ O J = c h ;
brea k ;
1 07
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
el se
{
i f ( c h == ' { ' )
fl ag = l ;
el se
i f ( c h == } ) . .
fl ag = 0 ;
f o r ( i = l ; i < 3 2 ; i ++ )
{
i f ( c h == ' ) ' )
{
s t r i n g_b u f [ l ] NULL ;
brea k ;
f o r ( i =O ; i < l a s t_n o ; i ++ )
{
i f ( s t r c mp ( s t r i n g_b u f , s t r i n g_ty p e s [ i ] ) 0)
{
res ul t = i ;
brea k ;
}
II c o u t < < " S t r i n g b u f fe r c o n t a i n s : < < s t r i n g_b u f < <
•
return ( resul t ) ;
1 08
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R
I*
G e t_A t t r i b ( ) G e t s a t t r i b u t e o t h e r t h a n o b j e c t f r om f g e t
*I
i n t G e t A t t r i b ( i n t Ty p e . c h a r s t r i n g_b u f [ J )
!
i n t i , ty p e=O , n o_p a r a m=O . f o u n d =T R U E
Vector l oc , l ook ;
fl oat radi us . di stance ;
Lamp * l amps ;
s w i t c h ( Ty p e )
!
c a s e S KY :
found = T RU E ;
w h i l e ( ty p e ! = P A R E N && ! feof ( fget ) )
!
ty p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
s w i t c h ( ty p e )
!
c a s e Z E N I TH :
W O R L D . s ky c o l o r_z e n i t h . g e t_v e c t o r ( ) ;
WO R L D . s ky c o l o r_z e n i t h =
W O R L D . s ky c o l o r_z e n i t h * ( f l o a t ) C N U M ;
brea k ;
case HORI Z :
W O R L D . s ky c o l o r_h o r i z . g e t_v e c t o r ( ) ;
W O R L D . s ky c o l o r_h o r i z =
W O R L D . s ky c o l o r_h o r i z * ( f l o a t ) C N U M ;
brea k ;
c a s e D I TH E R :
g e t_s t r i n g ( s t r i n g_b u f ) ;
WO R L D . s ky_d i t h e r =
f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
case PAREN :
brea k ;
defa u l t :
f o u n d = FA L S E ;
1 09
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
brea k ;
c a s e C O LO R :
w h i l e ( ty p e ! = P A R E N & & ! f e o f ( f g e t ) )
{
t y p e = g e t_ s t r i n g ( s t r i n g_b u f ) ;
f o u n d = g e t_c o l o r_d a t a ( ty p e , & d e f . c o l _d a t a ) ;
i f ( ty p e == P A R E N )
{
found = TRU E ;
brea k :
i f ( ! found )
{
c o u t < < " U n d e f i n e d p a r a me t e r " < < s t r i n g_b u f
< < "wh i l e l oa d i ng col o r d a t a i n
' i n p u t . c p p "' ;
ex i t ( l ) ;
brea k ;
c a s e F O C L E N GT H :
g e t_s t r i n g ( s t r i n g_b u f ) ;
WO R L D . f l e n g t h = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
W O R L D . f l e n g t h *= 5
brea k ;
c a s e F I L E_NAM E :
g e t_s t r i n g ( s t r i n g_b u f ) ;
s t r c py ( W O R L D . o u t f i l e , s t r i n g_b u f ) ;
brea k ;
c a s e L AM P :
d i stance = 1 50 ;
w h i l e ( ty p e ! = P A R E N & & ! f e o f ( f g e t ) )
{
ty p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
found = T RU E ;
s w i t c h ( ty p e )
!
c a s e LOC :
l o c . g e t_v e c t o r ( ) ;
n o_p a r a m I = l ;
brea k ;
110
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R
c a s e RA D I U S :
g e t_s t r i n g ( s t r i n g_b u f ) ;
r a d i u s = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e D I ST :
g e t_s t r i n g ( s t r i n g_b u f ) ;
d i s t a n c e = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
case PAREN :
brea k ;
defa ul t :
found FALS E ;
i f ( ! found )
{
c o u t < < " U n d e f i n e d p a r a me t e r " < < s t r i n g_b u f
< < " w h i l e l o a d i n g l a mp i n
' i nput . cpp ' " ;
exi t ( l ) ;
i f ( n o_p a r a m < 1 )
{
c o u t < < " T o o few p a r a m e t e r s f o r l a mp i n
' i nput . cpp ' " ;
exi t ( l ) ;
l a m p s = n ew L a m p ;
l amps - > l oc = l oc ;
l amps - > radi u s = radi us ;
l amps - >d i s tance = d i stance ;
l a m p s - > n e x t_l a mp = W O R L D . l a m p s ;
WORLD . l amps = l amps ;
W O R L D . l a m p c o u n t++ ;
brea k ;
c a s e O B S E RV E R :
l ook = Vector ( 200 , 50 , 0 ) ;
found = TRU E ;
w h i l e ( ty p e ! = P A R E N & & ! f e o f ( f g e t ) )
{
t y p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
s w i t c h ( ty p e )
111
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
case LOC :
W O R L D . o b s l o c . g e t_v e c t o r ( ) ;
n o_p a r a m I = l ;
brea k ;
c a s e L O O KAT :
l o o k . g e t_v e c t o r ( ) ;
n o_p a r a m I = 2 :
brea k ;
case UP:
W O R L D . o b s u p . g e t_v e c t o r ( ) ;
brea k ;
case PAREN :
brea k ;
defa ul t :
found FA LS E ;
i f ( ! found )
{
c o u t < < " U n d e f i n ed p a r a me t e r " < < s t r i n g_b u f
<< " wh i l e l oa d i n g obs e rv e r i n
' i n put . cpp ' " ;
ex i t ( l ) ;
WO R L D . o bs d i r l oo k - WORLD . ob s l oc ;
WORLD . obsdi r -WO R L D . o b s d i r ;
W O R L D . ob s r i g h t = WO R L D . ob s u p A W O R L D . ob s d i r ;
WO R L D . o b s u p = WO R L D . ob s d i r A WO R L D . ob s r i g h t ;
W O R L D . o b s u p = -WO R L D . o b s u p ;
W O R L D . o b s r i g h t = -WO R L D . o b s r i g h t ;
i f ( n o_p a r a m ! = 3 )
{
c o u t < < " T o o few p a r a m e t e r s f o r o b s e r v e r " < < " i n
' i nput . cpp ' " ;
exi t ( l ) ;
brea k ;
c a s e PAttern :
Get Pattern ( ) ;
brea k ;
112
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R
case XRES :
g e t_s t r i n g ( s t r i n g_b u f ) ;
XSIZE = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
CENTERX =XSIZE I 2 ;
X S I Z E4 = XSIZE I 4 ;
brea k ;
case Y RES :
g e t_s t r i n g ( s t r i n g_b u f ) ;
YSIZE = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
W O R L D . l a s t_s c a n YSIZE - l ;
C E N T E RY =YSIZE I 2 ;
brea k ;
c a s e N AM E :
g e t_s t r i n g ( n a me ) ;
brea k ;
defa ul t :
found = FALS E ;
return ( found ) :
g e t_c o l o r_d a t a G e t s t h e c o l o r i n f o r m a t i o n f r om a f i l e
*I
113
F R A CTA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +
c a s e M I R RO R :
c o l _d a t a - >m i r r o r . g e t_v e c t o r ( ) ;
c o l _d a t a - > m i r r o r c o l _d a t a - > m i r r o r * ( f l o a t ) C N U M ;
brea k ;
c a s e T RA N S :
c o l _d a t a - > t r a n s . g e t_v e c t o r ( ) ;
c o l _d a t a - > t r a n s c o l _d a t a - > t r a n s * ( f l o a t ) C N U M ;
brea k ;
c a s e D E N S I TY :
c o l _d a t a - > d e n s i ty . g e t_v e c t o r ( ) ;
c o l _d a t a - > d e n s i ty = c o l _d a t a - > d e n s i ty * ( f l o a t ) C N U M ;
brea k ;
case I NDEX :
g e t_s t r i n g ( s t r i n g_b u f ) ;
c o l _d a t a - > i n d e x = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e D I TH E R :
g e t_s t r i n g ( s t r i n g_b u f ) ;
c o l _d a t a - > d i t h e r = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e S R E F L ECT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
c o l _d a t a - > s r e f l e c t = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e RE F L ECT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
c o l _d a t a - > r e f l e c t = a t o f ( s t r i n g_b u f ) * C N U M ;
brea k ;
defa ul t :
found = FALSE ;
retu rn ( found ) ;
/ *r.=====�
G e t S p h e r e ( ) = L o a d a s p h e r e f r om f g e t a n d r e t u r n p o i n t e r t o i t
*/
114
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R
S p h e r e * n ew o b j ;
i n t t y p e=O , n o_p a r a m 0 , found ;
f l o a t temp ;
n ew o b j = n ew S p h e r e ;
n ew o b j - > c o l _d a t a = n e w c o l o r_d a t a ;
* n e w o b j - > c o l _d a t a = d e f . c o l _d a t a ;
w h i l e ( ty p e ! = P A R E N & & ! f e o f C f g e t ) )
{
t y p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
f o u n d = g e t_c o l o r_d a t a ( ty p e , n ew o b j - > c o l _d a t a ) ;
i f ( f o u n d == T RU E )
conti nue ;
f o u n d = T RU E ;
swi t c h C type )
c a s e LOC :
n e w o b j - > l o c . g e t_v e c t o r ( ) ;
n o_p a r a m I = l ;
brea k ;
c a s e RA D I U S :
g e t_s t r i n g ( s t r i n g_b u f ) ;
t e m p = f a b s C a t o f C s t r i n g_b u f ) ) ; n ew o b j - > v e c t l
Vecto r C temp , 0 , 0 ) ;
n o_p a r a m I = 2 ;
brea k ;
c a s e PAtte rn :
n ew o b j - > p a t t e r n=At t a c h_P a t t e r n ( ) ;
brea k :
case REMOV E :
n ew o b j - > r e m o v e=A t t a c h_P a t t e r n ( ) ;
brea k ;
c a s e X M U LT :
g e t_s t r i n g ( s t r i n g_b u f ) :
n ew o b j - > xm u l t = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e Y M U LT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - >y m u l t = f a b s C a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e NAM E :
g e t_s t r i n g ( n ew o b j - > n a me ) ;
115
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
brea k ;
case PAREN :
brea k :
defa u l t :
found FALS E :
i f ( ! found )
{
c o u t < < " U n d e f i n e d p a r a m e t e r " < < s t r i n g_b u f < < " w h i l e
l oadi ng sphere i n ' i nput . cpp ' " ;
ex i t ( l ) ;
i f ( n o_p a r a m ! = 3 )
{
c o u t < < "Too few p a ramete r s f o r s p h e r e i n ' i n p u t . c pp ' " :
ex i t ( l l :
/* ===�
n=
GetT r i a n g l e ( ) L o a d a t r i a n g l e f r om f g e t a n d r e t u r n
poi nter to i t
*/
n ew o b j = n ew T r i a n g l e :
n ew o b j - > c o l _d a t a = n ew c o l o r_d a t a :
* n ew o b j - > c o l _d a t a = d e f . c o l _d a t a ;
w h i l e ( ty p e ! = P A R E N & & ! f e o f ( f g e t l l
{
t y p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
f o u n d = g e t_c o l o r_d a t a ( ty p e , n ew o b j - > c o l _d a t a l ;
116
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R
i f ( f o u n d == T RU E )
cont i nue ;
f o u n d = T RU E ;
s w i t c h ( ty p e )
(
c a s e LOC :
n e w o b j - > l o c . g e t_v e c t o r ( ) ;
n o_p a r a m i = l ;
brea k ;
case Vl :
n ew o b j - > v e c t l . g e t_v e c t o r ( ) ;
n o_p a r a m i = 2 ;
brea k ;
case V2 :
n ew o b j - > v e c t 2 . g e t_v e c t o r ( ) ;
n o_p a r a m i = 4 ;
brea k ;
c a s e PAtt e r n :
n e w o b j - > p a t t e r n=A t t a c h_ P a t t e r n ( ) ;
brea k ;
c a s e R E MO V E :
n e w o b j - > r e m o v e=A t t a c h_ P a t t e r n ( ) ;
brea k ;
c a s e XMU LT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n e w o b j - > xm u l t = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e YMU LT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n e w o b j - >y m u l t = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e NAM E :
g e t_ s t r i n g ( n ew o b j - > n a m e ) ;
brea k ;
c a s e PA R E N :
brea k ;
defa u l t :
found FA L S E ;
i f ( ! fo u n d )
{
117
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +
i f ( n o_ p a r a m ! = 7 )
(
c o u t < < "Too few pa r ame t e r s f o r t r i a n g l e i n ' i n p u t . c pp ' " ;
exi t ( l ) ;
/ * rr======;i
GetRi ng ( ) L o a d a r i n g f r om f g e t a n d r e t u r n p o i n t e r t o i t
*/
n ew o b j = n ew R i n g ;
n ew o b j - > c o l _d a t a = n ew c o l o r_d a t a ;
* n ew o b j - > c o l _d a t a = d e f . c o l _d a t a ;
w h i l e ( ty p e ! = P A R E N & & ! f e o f ( f g e t ) )
(
t y p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
f o u n d = g e t_c o l o r_d a t a ( ty p e , n e w o b j - > c o l _d a t a ) ;
i f ( f o u n d == T R U E )
conti nue ;
found = T RU E ;
s w i t c h ( ty p e )
118
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R
c a s e LOC :
n ew o b j - > l o c . g e t_v e c t o r ( ) ;
n o_p a r a m I = l ;
brea k ;
case Vl :
n ew o b j - > v e c t l . g e t_v e c t o r ( ) ;
n o_p a r a m I = 2 ;
brea k ;
case V2 :
n e w o b j - > v e c t 2 . g e t_v e c t o r ( ) ;
n o_p a r a m i = 4 ;
brea k ;
c a s e R A D_ l :
g e t_ s t r i n g ( s t r i n g_b u f ) ;
n e w o b j - > v e c t 3 . x = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
n o_p a r a m I = 8 ;
brea k ;
c a s e RA D_2 :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > v e c t 3 . y = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
n o_p a r a m i = 1 6 ;
brea k ;
c a s e PAtt e r n :
n ew o b j - > p a t t e r n=At t a c h_ P a t t e r n ( ) ;
brea k ;
c a s e REMOV E :
n ew o b j - > r e m o v e=At t a c h_ P a t t e r n ( ) ;
brea k ;
c a s e XMU LT :
g e t_ s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > xm u l t = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e YMU LT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - >y m u l t = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e NAM E :
g e t_s t r i n g ( n ew o b j - > n a me ) ;
brea k ;
case PAREN :
brea k ;
119
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
defa u l t :
found FALSE ;
i f ( ! found )
(
c o u t < < " U n d e f i n e d p a r a me t e r " < < s t r i n g_b u f < <
" wh i l e l oa d i ng r i ng i n ' i nput . cpp ' " ;
exi t ( l ) ;
i f ( n o_ p a r a m ! = 3 1 )
{
c o u t < < "Too few p a r amet e r s f o r r i n g i n ' i n p u t . c pp ' " ;
exi t ( l ) ;
n ew o b j - > v e c t 3 . z O;
n ew o b j - > v e c t l = - n e w o b j - > v e c t l ;
n ew o b j - > v e c t 2 = - n ew o b j - > v e c t 2 ;
n ew o b j - > n o rm = n e w o b j - > v e c t l A n ew o b j - > v e c t 2 ;
n ew o b j - > n o r m = - n e w o b j - > n o rm ;
n ew o b j - > n l = n ew o b j - > n o rm % n e w o b j - > l o c ;
n ew o b j - > l e n l = n ew o b j - > v e c t l % n ew o b j - > v e c t l ;
n e w o b j - > l e n 2 = n ew o b j - > v e c t 2 % n ew o b j - > v e c t 2 ;
W O R L D . o b j c o u n t++ ;
retu rn ( newobj ) ;
G e t P a r a l l e l o g r a m ( ) = L o a d a p a r a l l e l o g r a m f r om f g e t a n d
r e t u r n po i n t e r to i t
*/
n ew o b j = n e w P a r a l l e l o g r a m ;
n ew o b j - > c o l _d a t a = n e w c o l o r_d a t a ;
* n ew o b j - > c o l _d a t a = d e f . c o l _d a t a ;
1 20
C O M M U N I C AT I N G W I T H T H E R AV T R A C E R
w h i l e ( ty p e ! = P A R E N & & ! f e o f ( f g e t ) )
{
t y p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
f o u n d = g e t_c o l o r_d a t a ( ty p e , n e w o b j - > c o l _d a t a ) ;
i f ( found == T RU E )
cont i nue ;
found = T RU E ;
s w i t c h ( ty p e )
I
c a s e LOC :
n ew o b j - > l o c . g e t_v e c t o r ( ) ;
n o_p a r a m I l ;=
brea k ;
case Vl :
n e w o b j - > v e c t l . g e t_v e c t o r ( ) ;
n o_p a r a m I 2 ; =
brea k ;
case V2 :
n e w o b j - > v e c t 2 . g e t_v e c t o r ( ) ;
n o_p a r a m I 4 ; =
brea k ;
c a s e PAtt e r n :
n ew o b j - > p a t t e r n =A t t a c h_P a t t e r n ( ) ;
brea k ;
c a s e REMOV E :
n ew o b j - > r e m o v e=At t a c h_ P a t t e r n ( ) ;
brea k ;
c a s e XMU LT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n e w o b j - > xm u l t = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e YMU LT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - >y m u l t = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e NAM E :
g e t_s t r i n g ( n ew o b j - > n a m e ) ;
brea k ;
case PAREN :
brea k ;
defa ul t :
found = FALSE ;
1 21
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
i f ( ! fo u n d )
(
c o u t < < " U n d e f i n e d p a r a m e t e r " < < s t r i n g_b u f < <
" wh i l e l oa d i ng pa ra l l e l ogram i n ' i nput . cpp ' " ;
ex i t ( l ) ;
i f ( n o_p a r a m ! = 7 )
(
c o u t < < "Too few pa r a met e r s f o r pa r a l l e l o g r a m i n ' i n p u t . cpp ' " ;
ex i t ( l ) ;
I*
GetCone ( ) L o a d a c o n e f r om f g e t a n d r e t u r n p o i n t e r t o i t
*/
n ew o b j = n e w Q u a d r a t i c ;
n ew o b j - > c o l _d a t a = n e w c o l o r_d a t a ;
* n ew o b j - > c o l _d a t a = d e f . c o l _d a t a ;
n ew o b j - > v e c t l = V e c t o r ( 0 , 1 , 0 ) ;
w h i l e ( ty p e ! = P A R E N && ! f e o f ( f g e t ) )
(
t y p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
f o u n d = g e t_c o l o r_d a t a ( ty p e , n ew o b j - > c o l _d a t a ) ;
1 22
C O M M U N I C AT I N G W I T H T H E R AV T R A C E R
i f ( f o u n d == T R U E )
cont i nue ;
found = T RU E ;
swi t c h ( type )
(
c a s e LDC :
n ew o b j - > l o c . g e t_v e c t o r ( ) ;
n o_p a r a m I = l ;
brea k ;
c a s e RA D I U S :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > v e c t 2 . x = a t o f ( s t r i n g_b u f ) ;
n o_p a r a m I = 2 ;
brea k ;
c a s e H E I GHT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > v e c t 2 . z = a t o f ( s t r i n g_b u f ) ;
n o_p a r a m I = 4 ;
brea k ;
case DIR:
n ew o b j - > v e c t l . g e t_v e c t o r ( ) ;
brea k ;
c a s e PAt t e r n :
n ew o b j - > p a t t e r n=A t t a c h_P a t t e r n ( ) ;
brea k ;
c a s e REMOV E :
n ew o b j - > r e m o v e=A t t a c h_ P a t t e r n ( ) ;
brea k ;
c a s e XMU LT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > xm u l t = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
ca s e YMU LT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - >y m u l t = f a b s ( a t o f ( s t r i n g_ b u f ) ) ;
brea k ;
c a s e NAM E :
g e t_s t r i n g ( n ew o b j - > n a m e ) ;
brea k ;
c a s e PA R E N :
brea k ;
1 23
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
defa ul t :
found FALSE ;
i f ( ! found )
!
c o u t < < " U n d e f i n e d p a r a m e t e r " < < s t r i n g_b u f < <
" whi l e l oadi ng cone i n ' i nput . cpp ' " ;
exi t ( 1 ) ;
i f ( n o_p a r a m ! = 7 )
!
c o u t < < " T o o few p a r a me t e r s f o r c o n e i n ' i n p u t . c p p ' " ;
ex i t ( l ) ;
n ew o b j - > c t e rm O;
n ew o b j - > l ow e r . x - n ew o b j - > v e c t 2 . x ;
n ew o b j - > l ow e r . z - n ew o b j - > v e c t 2 . x ;
n ew o b j - > l ow e r . y - n ew o b j - > v e c t 2 . z ;
n ew o b j - > u p p e r . x n ew o b j - > v e c t 2 . x ;
n ew o b j - > u p p e r . z n ew o b j - > v e c t 2 . x ;
n ew o b j - > u p p e r . y O;
n ew o b j - > v e c t 2 . x n ew o b j - > v e c t 2 . x * n ew o b j - > v e c t 2 . x ;
n ew o b j - > v e c t 2 . z n ew o b j - > v e c t 2 . z * n ew o b j - > v e c t 2 . z ;
n ew o b j - > v e c t 2 . y - n e w o b j - > v e c t 2 . x * n ew o b j - > v e c t 2 . x ;
n ew o b j - > v e c t 2 . x n ew o b j - > v e c t 2 . x * n ew o b j - > v e c t 2 . z ;
n ew o b j - > v e c t 2 . z n ew o b j - > v e c t 2 . x ;
n ew o b j - > v e c t l = - n ew o b j - > v e c t l ;
t em p = n ew o b j - > v e c t l . x * n ew o b j - > v e c t l . x + n e w o b j - > v e c t l . z *
n ew o b j - > v e c t l . z ;
i f ( t e m p == 0 )
n ew o b j - > c o s l l;
el se
n ew o b j - > c o s l n ew o b j - > v e c t l . z / s q r t ( t e mp ) ;
n ew o b j - > s i n l s q r t ( l - n ew o b j - > c o s l * n ew o b j - > c o s l ) ;
n ewd i r . x = n ew o b j - > v e c t l . x * n ew o b j - > c o s l + n ew o b j - > v e c t l . z *
- newobj - > s i n l ;
n ewd i r . y = n ew o b j - > v e c t l . y ;
n ewd i r . z = n ew o b j - > v e c t l . x * n ew o b j - > s i n l +
n ew o b j - > v e c t l . z * n ew o b j - > c o s l ;
t em p = n ewd i r . y * n ewd i r . y + n ewd i r . z * n ewd i r . z ;
i f ( t e m p == 0 )
1 24
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R
n ew o b j - > c o s 2 l;
el se
n ew o b j - > c o s 2 n ewd i r . y / s q r t ( t em p ) ;
n e w o b j - > s i n 2 = s q r t ( l - n ew o b j - > c o s 2 * n ew o b j - > c o s 2 ) ;
W O R L D . o b j c o u n t++ ;
r e t u r n ( n ew o b j ) ;
/* rr=
====;i
GetQuadrati c ( ) L o a d a q u a d r a t i c s u r f a c e f r om f g e t a n d
return po i n ter to i t
*/
n ew o b j = n e w Q u a d r a t i c ;
n ew o b j - > c o l _d a t a = n ew c o l o r_d a t a ;
* n ew o b j - > c o l _d a t a = d e f . c o l _d a t a ;
n ew o b j - > v e c t l = V e c t o r ( 0 , 1 , 0 ) ;
w h i l e ( ty p e ! = P A R E N & & ! f e o f ( f g e t ) )
{
t y p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
f o u n d = g e t_c o l o r_d a t a ( ty p e , n ew o b j - > c o l _d a t a ) ;
i f ( f o u n d == T R U E )
con t i n u e ;
found = T RU E ;
s w i t c h ( ty p e )
{
c a s e LOC :
n e w o b j - > l o c . g e t_v e c t o r ( ) ;
n o_p a r a m I = l ;
brea k ;
case A:
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > v e c t 2 . x = a t o f ( s t r i n g_b u f ) ;
n o_p a r a m I = 2 ;
1 25
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
brea k ;
case B :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > v e c t 2 . y = a t o f ( s t r i n g_b u f ) ;
n o_p a r a m I = 4 ;
brea k ;
case C :
g e t_s t r i n g ( s t r i n g_b u f ) ;
newobj - > v e c t 2 . z = a t o f ( s t r i n g_b u f ) ;
n o_p a r a m I = 8 ;
brea k ;
case D :
g e t_ s t r i n g ( s t r i n g_b u f ) ;
n e w o b j - > c t e rm = a t o f ( s t r i n g_b u f ) ;
n o_p a r a m I = 1 6 ;
brea k ;
case E :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n e w o b j - >y t e rm = a t o f ( s t r i n g_b u f ) ;
n o_p a r a m i = 3 2 ;
brea k ;
case XMI N :
g e t_ s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > l o w e r . x = a t o f ( s t r i n g_b u f ) ;
brea k ;
c a s e X MA X :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > u p p e r . x = a t o f ( s t r i n g_b u f ) ;
brea k ;
case YMI N :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > l ow e r . y = a t o f ( s t r i n g_b u f ) ;
brea k ;
c a s e Y MA X :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > u p p e r . y = a t o f ( s t r i n g_b u f ) ;
brea k :
case ZM I N :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > l owe r . z = a t o f ( s t r i n g_b u f ) ;
brea k :
1 26
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R
c a s e ZMAX :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > u p p e r . z = a t o f ( s t r i n g_b u f ) ;
brea k ;
case D I R :
n ew o b j - > v e c t l . g e t_v e c t o r ( ) ;
brea k ;
c a s e PAt t e r n :
n ew o b j - > p a t t e r n =A t t a c h_P a t t e r n ( ) ;
brea k ;
c a s e REMOV E :
n ew o b j - > r e mo v e=At t a c h_P a t t e r n ( ) ;
b r ea k ;
c a s e X M U LT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > x m u l t = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e YMU LT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - >y m u l t = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e N AM E :
g e t_s t r i n g ( n e w o b j - > n a me ) ;
brea k ;
case PAREN :
brea k ;
defa u l t :
found FALSE ;
i f ( ! found )
{
c o u t < < " U n d e f i n e d p a r a me t e r " < < s t r i n g_b u f < <
" w h i l e l oa d i ng q u a d r i c i n ' i nput . cpp ' " ;
ex i t ( l ) ;
n ew o b j - > v e c t l - n ew o b j - > v e c t l ;
1 27
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
/ * rr=====;i
Get Fracta l ( ) L o a d a f r a c t a l f r om f g e t a n d r e t u r n
po i nt e r to i t
*/
n ew o b j = n ew T r i a n g l e ;
n ew o b j - > c o l _d a t a = n e w c o l o r_d a t a ;
* n ew o b j - > c o l _d a t a = d e f . c o l _d a t a ;
w h i l e ( ty p e ! = P A R E N & & ! f e o f ( f g e t ) )
I
t y p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
f o u n d = g e t_c o l o r_d a t a ( ty p e , n e w o b j - > c o l _d a t a ) ;
i f ( f o u n d == T R U E )
1 28
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R
cont i nue ;
found = T RU E ;
swi tch ( type )
{
c a s e LOC :
n ew o b j - > l o c . g e t_v e c t o r ( ) ;
n o_p a r a m I = l ;
brea k ;
case Vl :
n ew o b j - > v e c t l . g e t_v e c t o r ( ) ;
n o_p a r a m I = 2 ;
brea k ;
case V2 :
n ew o b j - > v e c t 2 . g e t_v e c t o r ( ) ;
n o_p a r a m I = 4 ;
brea k ;
case DI MENS I ON :
g e t_s t r i n g ( s t r i n g_b u f ) ;
W O R L D . f r a c t a l _d i m = a t o f ( s t r i n g_b u f ) ;
brea k ;
c a s e S C A LA R :
g e t_ s t r i n g ( s t r i n g_b u f ) ;
W O R L D . f r a c t a l _s c a l a r = a t o f ( s t r i n g_b u f ) ;
brea k ;
c a s e PAtte rn :
n ew o b j - > p a t t e r n =At t a c h_P a t t e r n ( ) ;
brea k ;
c a s e REMOV E :
n ew o b j - > r e m o v e=A t t a c h_P a t t e r n ( ) ;
brea k ;
c a s e XMU LT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - > x m u l t = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e YMU LT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
n ew o b j - >y m u l t = f a b s ( a t o f ( s t r i n g_b u f ) ) ;
brea k ;
c a s e N AM E :
g e t_s t r i n g ( n ew o b j - > n a me ) :
brea k :
1 29
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
case PAREN :
brea k ;
defaul t :
found FA LS E ;
i f ( ! found )
{
c o u t < < " U n d e f i n e d p a r a m e t e r " < < s t r i n g_b u f < <
" whi l e l oadi ng fracta l t r i angl e i n ' i nput . cpp ' " ;
exi t ( l ) ;
i f ( n o_p a r a m ! = 7 )
{
c o u t < < " T o o few p a r a m e t e r s f o r f r a c t a l t r i a n g l e i n ' i n p u t . c p p ' " ;
ex i t ( l ) ;
F r a c t a l _c om p ( n ew o b j ) ;
q u e u e = M a k e_f r a c t a l _t r i a n g l e s ( n ew o b j - > l o c , n ew o b j - > v e c t l ,
n ew o b j - > v e c t 2 , n ew o b j - > v e c t 3 , q u e u e , WO R L D . l e v e l ) ;
W O R L D . o b j c o u n t++ ;
ret u rn ( queue ) ;
/* r.=====�
G e t_O b j e c t ( ) = L o a d a n o b j e c t f r om f g e t
and return po i nt e r to i t
*/
O b j e c t * G e t_O b j e c t ( i n t t y p e , O b j e c t * q u e u e )
{
O b j e c t * n ew o b j ;
n ew o b j = N U L L ;
s w i t c h ( ty p e )
{
case SPHERE :
n ew o b j =Ge t S p h e r e ( ) ;
b r ea k ;
c a s e P A RA L L E L O G RAM :
n ew o b j =G e t P a r a l l e l o g r a m ( ) ;
1 30
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R
brea k ;
c a s e T R I ANGLE :
n ew o b j = G e t T r i a n g l e ( ) ;
brea k ;
case RING:
n ew o b j = G e t R i n g ( ) ;
brea k ;
c a s e Q U A D RAT I C :
n ew o b j =G e t O u a d r a t i c ( ) ;
brea k ;
c a s e CON E :
n ew o b j =G e t C o n e ( ) ;
brea k ;
c a s e F RA C TA L :
n ew o b j = G e t F r a c t a l ( q u e u e ) ;
brea k ;
c a s e I N S T A N C E_O F :
n ew o b j =G e t_ I n s t a n c e_O f ( ) ;
brea k ;
r e t u r n ( n ew o b j ) ;
/* ===�
rr=
A t t a c h_ P a t t e r n ( ) = F i n d s p a t t e r n m a t c h i n g o b j e c t p a t t e r n
n ame a n d ret u r n s po i n t e r to i t
*/
P a t t e r n * A t t a c h_P a t t e r n ( )
{
Pattern * pat ;
g e t_s t r i n g ( s t r i n g_b u f ) ;
p a t=WO R L D . p a t l i s t ;
w h i l e ( pa t ! =N U L L )
{
i f ( s t r c m p ( s t r i n g_b u f , p a t - > n a m e ) ==O )
brea k ;
p a t=p a t - > s i b l i n g ;
i f ( p a t == N U L L )
1 31
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
ret u rn ( pa t ) ;
/*
G e t_C i r c l e_P a t t e r n ( ) Loa d s a c i r c l e s u b - pattern
*/
P a t t e r n * G e t_C i r c l e_ P a t t e r n ( )
I
i n t t y p e=O , n o_p a r a m = 0 , found ;
Pattern *pa ttern :
c o l o r_d a t a c o l _d a t a ;
p a t t e r n= n e w P a t t e r n :
p a t t e r n - > n a me [ O J = NULL :
pattern - >c h i l d = NULL ;
pattern - > s i bl i ng = N U L L :
pattern - >l i n k = N U L L ;
p a t t e r n - >type = C I RC L E :
c o l _d a t a = d e f . c o l _d a t a :
w h i l e ( ty p e ! = P A R E N & & ! f e o f ( f g e t ) )
{
t y p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
f o u n d = g e t_c o l o r_d a t a ( ty p e , & c o l _d a t a ) :
i f ( ty p e == RA D I U S )
I
g e t_s t r i n g ( s t r i n g_b u f ) :
pattern - > radi us =a b s ( a t o f ( s t r i n g_b u f ) ) ;
n o_ p a r a m I 1 ;
=
found = TRU E ;
i f ( ty p e == P A R E N )
I
found = T RU E :
i f ( ! fo u n d )
I
1 32
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R
i f ( n o_p a r a m ! = 1 )
{
c o u t < < "Too few p a ramet e r s i n g e t t i n g c i r c l e p a t t e rn \ n " ;
exi t ( l ) ;
p a t t e r n - > c o l _d a t a c o l _d a t a ;
retu rn ( pattern ) ;
/ * n=======;i
G e t_ R e c t_ P a t t e r n ( ) Load a rectangl e sub- pattern
*/
P a t t e r n * G e t_ R e c t_ P a t t e r n ( )
{
i n t t y p e=O , n o_p a r a m =O , f o u n d ;
Pattern *pattern ;
c o l o r_d a t a c o l _d a t a ;
p a t t e r n=new P a t t e rn ;
p a t t e r n - > n a me [ O J = N U L L ;
pattern - >chi l d = NU L L ;
pattern - >s i bl i ng = NULL ;
pattern - > l i n k = N U L L ;
patte r n - >type = RECTANGL E ;
c o l _d a t a = d e f . c o l _d a t a ;
w h i l e ( ty p e ! = P A R E N & & ! f e o f ( f g e t ) )
{
t y p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
f o u n d = g e t_c o l o r_d a t a ( ty p e , & c o l _d a t a ) ;
i f ( f o u n d == F A L S E )
f o u n d = T RU E ;
el se
conti nue ;
swi t c h ( type )
{
1 33
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
c a s e S T A RT_X :
g e t_s t r i n g ( s t r i n g_b u f ) ;
p a t t e r n - > s t a r t x = a t o f ( s t r i n g_b u f ) ;
n o_p a r a m I = l ;
brea k ;
c a s e S T A RT_Y :
g e t_ s t r i n g ( s t r i n g_b u f ) ;
p a t t e r n - > s t a r ty = a t o f ( s t r i n g_b u f ) ;
n o_p a r a m I = 2 ;
brea k :
c a s e E N O_X :
g e t_s t r i n g ( s t r i n g_b u f ) ;
p a t t e r n - > e n d x = a t o f ( s t r i n g_b u f ) ;
n o_p a r a m I = 4 ;
brea k :
c a s e E N D_Y :
g e t_ s t r i n g ( s t r i n g_b u f ) ;
p a t t e r n - > e n dy = a t o f ( s t r i n g_b u f ) ;
n o_p a r a m I = 8 :
brea k ;
case PAREN :
brea k ;
defa ul t :
found FALS E ;
i f ( ! found )
{
c o u t < < " U n d e f i n e d p a r a me t e r " < < s t r i n g_b u f < <
" i n gett i ng rectang l e pattern \ n " :
ex i t ( l ) ;
i f ( n o_p a r a m ! = 1 5 )
{
c o u t < < "Too few p a r amet e r s f o r r e c t a n g u l a r p a t t e rn " :
ex i t ( l ) ;
p a t t e r n - > c o l _d a t a c o l _d a t a :
return ( pa ttern ) :
1 34
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R
*I
P a t t e r n * G e t_P o l y_P a t t e r n ( )
{
i n t t y p e=O , n o_p a r a m = 0 , f o u n d ;
Pattern *pattern , *poi ntpatt ;
c o l o r_d a t a c o l _d a t a ;
patte rn=new P a t t e r n ;
p a t t e r n - > n a me [ O J = N U L L ;
pattern - >chi l d = NULL ;
pattern - > s i bl i ng = NULL ;
pattern - > l i n k = NU L L ;
p a t t e r n - > t y p e = P O L Y GO N ;
c o l _d a t a = d e f . c o l _d a t a ;
w h i l e ( ty p e ! = P A R E N & & ! f e o f ( f g e t ) )
{
found = FALSE ;
t y p e = g e t_s t r i n g ( s t r i n g_b u f ) ;
f o u n d = g e t_c o l o r_d a t a ( ty p e , & c o l _d a t a ) ;
i f ( f o u n d == T RU E )
con t i n u e ;
i f ( ty p e == P O I N T )
{
poi ntpatt = new Pattern ;
g e t_s t r i n g ( s t r i n g_b u f ) ;
p o i n t p a t t - > s t a r t x = a t o f ( s t r i n g_b u f ) ;
g e t_s t r i n g ( s t r i n g_b u f ) ;
p o i n t p a t t - > s t a r ty = a t o f ( s t r i n g_b u f ) ;
n o_p a r a m += l ;
poi n t p a tt - > l i n k = p a t t e rn - > l i n k ;
pattern - > l i n k = poi ntpatt ;
f o u n d = T RU E ;
i f ( ty p e == P A R E N )
brea k ;
i f ( ! found )
{
c o u t < < " U n d e f i n e d p a r ame t e r < < s t r i n g_b u f < <
"
1 35
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
ex i t ( l ) ;
i f ( n o_p a r a m < 3)
{
cout << " T o o few p a ramet e r s f o r p o l y g o n p a t t e rn · ;
ex i t ( l ) ;
p a t t e r n - > c o l _d a t a c o l _d a t a ;
retu rn ( pattern ) ;
I * ===================================== = ======
� - === = ====n
G e t_ S u b P a t t e r n ( ) Loa d a s ub pa tte rn
11
*
/
P a t t e r n * G e t_S u b P a t t e r n ( i n t t y p e )
{
s w i t c h ( ty p e )
{
c a s e RECTANG LE :
r e t u r n ( G e t _ R e c t_ P a t t e r n ( ) ) ;
c a s e C I RC L E :
r e t u r n ( G e t_ C i r c l e_ P a t t e r n ( ) ) ;
c a s e PO LYGON :
r e t u r n ( G e t_ P o l y_ P a t t e r n ( ) ) ;
defa ul t :
retu rn ( NU L L ) ;
====;!
*
/ �=
Ge t P a t t e r n ( ) Load a pattern i nto pattern l i st
*
/
i n t Ge t P a t t e r n ( )
{
i n t ty p e=O , n o_p a r a m = 0, f o u n d= T RU E ;
Pattern *pattern , *spa t :
p a t t e r n = n ew P a t t e r n :
1 36
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R
p a t t e r n - > n a me [ O J = N U L L ;
pattern - >chi l d = NULL ;
pattern - >si bl i ng = NULL ;
pattern - > l i n k = N U L L ;
p a t t e r n - > t y p e = P A T T_H E A O E R ;
w h i l e ( ty p e ! = PA R E N && ! feof ( fget ) )
(
t y p e = g e t_ s t r i n g ( s t r i n g_b u f ) ;
s w i t c h ( ty p e )
(
c a s e X_S I Z E :
n o_p a r a m I= l;
g e t_s t r i n g ( s t r i n g_b u f ) ;
p a t t e r n - > x s i z e = a t o f ( s t r i n g_b u f ) ;
brea k ;
c a s e Y _S I Z E :
g e t_ s t r i n g ( s t r i n g_ b u f ) ;
p a t t e r n - > y s i z e = a t o f ( s t r i n g_b u f ) ;
n o_p a r a m I= 2;
brea k ;
c a s e NAM E :
g e t_ s t r i n g ( p a t t e r n - > n a m e ) ;
n o_p a r a m I= 4;
b rea k ;
defa ul t :
f o u n d = FA LS E ;
i f ( ( s p a t = G e t_S u b P a t t e r n ( ty p e ) ) ! = N U L L )
(
s p a t - > s i b l i n g=p a t t e r n - > c h i l d ;
p a t t e r n - > c h i l d=s p a t ;
n o_p a r a m I= 8; found = T RU E ;
i f ( t y p e == P A R E N )
{
f o u n d = T RU E ;
i f ( ! found )
{
cout << " U n d e f i n ed pa rameter " << s t r i n g_ b u f <<
" i n getti ng pattern \ n " ;
exi t ( l ) ;
1 37
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
i f ( n o_p a r a m ! = 15)
{
cout << " T o o few p a r a me t e r s i n g e t t i n g p a t t e r n \ n " :
ex i t ( l ) ;
p a t t e r n - > s i b l i n g=WO R L D . p a t l i s t :
W O R L D . p a t l i s t =p a t t e r n :
return ( T RU E ) :
I*
*I I
!!:::= ==
M a k e Bbox l l C r e a t e a bound i n g box
=�
*
v o i d M a k e_B b o x ( O b j e c t node )
{
*
Obj ect t n od e :
Vector v l , v2 :
i f ( n ode - > c h i l d ! =N U L L )
M a k e_B b o x ( n o d e - > c h i l d ) :
i f ( n ode - > n e x t o b j ! =N U L L )
M a k e_B b o x ( n o d e - > n e x t o b j ) :
i f ( n o d e - > ty p e== B B O X )
{
t n o d e= n o d e - > c h i l d :
n o d e - > l owe r = V e c t o r ( 3e 3 0 , 3 e 3 0 , 3 e 30 ) :
node - > uppe r = Vector ( - 3e30 , - 3e30 , - 3e30 ) :
w h i l e ( t n o d e ! =N U L L )
{
t n od e - > F i n d B box ( &v l , & v 2 ) :
n o d e - > l owe r = v l . m i n ( n o d e - > l owe r ) ;
node - >upper = v 2 . ma x ( node - >uppe r ) ;
t n ode=t n od e - > n ex t o bj :
1 38
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R
*
/
N a me F i n d ( ) F i n d s o b j e c t i n s t a c k w i t h a g i v e n n a me
*
/
O b j e c t * N a me_ F i n d ( O b j e c t * o b j . c h a r * n a me )
{
Obj ect *temp ;
i f ( o b j == N U L L )
return ( NU LL ) ;
i f ( obj - > n ame ! = NU LL)
if ( s t r cmp ( n a me , obj - > n a me ) Ol
retu rn ( obj ) ;
i f ( obj - > c h i l d ! = NU L L )
if ( ( t e m p = N a m e_ F i n d ( o b j - > c h i l d , n a m e ) ) ! = NU LL)
r e t u r n ( temp ) ;
i f ( obj - > n ex t o bj != NULL )
i f ( ( t e m p = N a m e_ F i n d ( o b j - > n e x t o b j , n a m e ) ) ! = NU LL)
r e t u r n ( temp ) ;
return ( NU LL l ;
*
/
O b j e c t * G e t_ I n s t a n c e_O f ( )
{
c h a r n a me [ 3 2 J ;
i n t t y p e = O , n o_ p a r a m = 0, f o u n d =T R U E ;
Vector offset . mul t ;
Obj ect * sou rce . * dest ;
mu l t = Vec t o r (1,1,1);
w h i l e ( ty p e &&
! = PA R E N ! fe o f ( fget ) )
{
ty p e = g e t_ s t r i n g ( s t r i n g_b u f ) ;
s w i t c h ( ty p e )
{
1 39
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
c a s e NAM E :
g e t_s t r i n g ( n a m e ) :
n o_p a r a m I= 1 :
brea k :
c a s e LOC :
o f f s e t . g e t_v e c t o r ( ) ;
n o_p a r a m I= 2:
brea k :
c a s e SCA L E :
m u l t . g e t_v e c t o r ( ) :
brea k :
case PAREN :
brea k :
defa ul t :
found FA L S E :
i f ( ! found )
(
cout << " U n d e f i n ed pa ramet e r " << s t r i n g_b u f <<
" i n gett i ng I n stance" ;
ex i t ( l ) ;
i f ( n o_p a r a m ! = 3)
(
cout << " T o o few p a r a me t e r s i n g e tt i n g I n s t a n c e " ;
exi t ( l ) :
i f ( ( s o u r c e = N a m e_F i n d ( W O R L D . i n s t a n c e s , n a m e ) ) == N U L L )
(
cout << " U n d e f i n e d i n s t a n c e n a me : " << n a me << "\n" :
ex i t ( l ) ;
d e s t = M o v e_ I n s t a n c e ( s o u r c e , T R U E ) ;
d e s t - > S c a l e_ I n s t a n c e ( & m u l t , T R U E ) ;
O f f s e t_ I n s t a n c e ( d e s t , & o f f s e t , T R U E ) ;
W O R L D . o b j c o u n t ++ ;
return ( dest ) ;
1 40
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R
/
* ..,... ======-======-=======--=========-==============;i
...........
M o v e_ I n s t a n c e ( ) = M o v e s u s e r d e f i n e d p r i m i t i v e f r om
W O R L D . i n s t a n c e to W O R L D . s t a c k
*I
O b j e c t * M o v e_ I n s t a n c e ( O b j e c t * o b j , i nt ffl ag )
{
O b j e c t * n ew o b j ;
i f ( o b j == N U L L )
retu rn ( NU L L ) ;
s w i t c h ( o b j - > ty p e )
{
case SPHERE :
n ewobj = n ew S p h e r e ;
brea k ;
case T R I ANGLE :
n ew o b j = n ew T r i a n g l e ;
brea k ;
case RING:
n ew o b j = n ew R i n g ;
brea k ;
c a s e P A RA L L E L O G R A M :
n ewobj = n ew P a r a l l e l og r a m ;
brea k ;
c a s e Q U A D RAT I C :
n ewobj = n ew Q u a d r a t i c ;
brea k ;
case BBOX :
n ewobj n ew B B o x ;
brea k ;
defa ul t :
n ewobj n ew O bj e c t ;
* n ewobj = * obj ;
n ew o b j - > c h i l d = M o v e_ I n s t a n c e ( o b j - > c h i l d , F A L S E ) ;
i f ( ! ffl a g )
n ewo bj - > n ex t o b j M o v e_ I n s t a n c e ( o b j - > n e x t o b j , F A L S E ) ;
el se
n ewobj - > n e x t o b j NU L L ;
r e t u r n ( n ewobj ) ;
1 41
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
/*
Offset I n stance ( ) O f f s e t s a u s e r d e f i n e d p r i m i t i v e by
vector · offset '
*/
O f f s e t_ I n s t a n c e ( o b j - > c h i l d , o f f s e t , F A L S E ) ;
i f ( ! ffl ag )
O f f s e t_ I n s t a n c e ( o b j - > n e x t o b j , o f f s e t , F A L S E ) ;
Processi n g Attributes
The first type of data checked by the get_data function is attributes. This is
accomplished by calling the GetAttrib function. This function consists of a large
switch statement, which provides the proper actions for every attribute type that
might have been returned by the parser. As the function is entered, the local
found parameter is set to TRUE. At the end of the switch statement is the
default case, which is entered only if there is no match for any of the other cases.
The default case changes found to FALSE. Upon returning, the function returns
the value of found.
1 42
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R
The first type of attribute checked is sky data. If a match i s found, the
function enters a loop which uses the parser to read strings and processes each
with a switch statement until a right parenthesis is encountered, at which point
the loop terminate s . There are three acceptable strings (besides the right
parenthesis) for sky data. For the first two, ZENITH and HORIZ, a vector is
read into the appropriate place in the WORLD data. For the third kind of string,
DITHER, a string is read in, converted to a floating-point number, and the
absolute value entered into the WORLD .sky_dither parameter. This parameter
should always be positive. If a negative number is encountered, we might
choose to declare this an error, print an error message, and exit. Instead, by
taking the absolute value , we ignore the minus sign and assume that the
numerical value is correct.
Within the loop for sky parameters, we set the found parameter to TRUE
before entering the loop and then set it to FALSE if we ever get to the default
case. This means that when we exit the loop, if any string encountered within
the loop is unacceptable. found will be FALSE; otherwise it remains TRUE.
Next is the COLOR attribute. There are two different ways of assigning
color information to an object. One is a default array of color data stored in the
program. Whenever an object is created, all of the color information starts out
with the default color v alues. Then, as object data is entered from the file,
various items of color information may be entered; if they are, they replace the
default values . The COLOR attribute permits changing of the default color
values. Thus, you may enter default color values without object color values and
all following objects take on the default values. When you want a different
colored object, you change the default values before you define the next object.
Alternately, you can leave the default values alone and specify particular color
values for each object. This attribute is processed by a repeated loop until an end
of file is encountered, or a string is read which is a right parenthesis. The loop
begins by getting a string w i th the parser. The string i s then sent to the
get_color_data function, which checks for legitimate color data and processes it.
This function is described below. It returns a TRUE if the item was correct color
143
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
data or a FALSE. If the string was not a legitimate color parameter, an error
mes sage i s printed out and the program terminate s . Otherw i s e the loop
continues processing color data until it terminates.
If the attribute is FOC_LENGTH, the parser gets the focal length string from
the data file. It is converted to a floating-point number, the absolute value of this
taken (since negative focal lengths are impossible) and multiplied by five. The
result is stored in WORLD flength . The focal length parameter is used as a
multiplier to scale the perspective of the scene. With the mathematics in the ray
tracing functions, a parameter five times the focal length of the lens gives the
proper perspective for a 35 millimeter camera. We won 't go deeply into optics,
but be aware that a "normal" lens (which gives the kind of photograph we are
used to viewing), has a different focal length for each different film size. If you
go above the "normal" value, objects appear closer, but also more compressed.
This is the telephoto lens. If you go below the "normal" value, you have a wide
angle lens, which crams more into the picture, but creates distortion. We have
set up the mathematics so that the focal length inputs correspond to a 35 mm
camera, because it is so widely used and many people are familiar with the
photographic effects of the different lenses.
If the attribute i s FILE_NAME, the parser reads the next string and it is
copied to the parameter WORLD .outfi/e, used in opening the output data file.
The next attribute defines a lamp. Lamps are processed with a loop similar
to sky data. Only one parameter is required of a lamp, namely its location.
Another parameter, distance, is set to a default parameter of 1 50 for each new
lamp source, but may be changed by data from the file. In addition, a radius
parameter may be entered (to remain compatible with QRT), but it is otherwise
not essential. When the loop ends, the parameter noyaram will have a value of
one if the location has been entered. If not, an error message will be displayed
and the program terminated. This loop also uses the found parameter to generate
an error message and terminate the program if an undefined parameter i s
encountered. Once a lamp has successfully been defined, a new lamp structure
1 44
C O M M U N I C AT I N G W I T H T H E R AV T R A C E R
The GetA ttrib function next processes the PATTERN attribute. This i s
handled b y the GetPattern function, which will be described later.
The function then processes the XRES and YRES attributes. It uses the
parser to read a string for each of these, converts it to a floating-point number,
takes the absolute value of this number, and places it in the appropriate WORLD
parameter.
Finally, if the attribute is NAME, the parser gets the next string and places it
in the variable name.
1 45
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
Hence, each one is processed by using the get_vector function to read the
data from the stream and convert it into a vector. The vector is then multiplied
by CNUM to obtain the proper color range. Color data is stored in a color data
array, with address specified by a parameter passed to the function. Next, three
floating-point parameters are processed: index of refraction, dither value, and the
specular reflection coefficient. These are all positive numbers, so that the string
obtained from the data stream by the parser is converted from a floating-point
number into an absolute value.
Processing Instances
All of the instances defined in a file must be placed in a single block which
starts with BEGIN_INSTANCES and ends with END_INSTANCES. When this
first string is encountered, the get_data function is recalled recursively. This
results in the generation of a separate list of objects similar to the main list
described below. The get_data function terminates at the END_INSTANCES
string, whereupon the address of the last object added to the linked list is placed
in WORLD .instances.
1 46
C O M M U N I C AT I N G W I T H T H E R AV T R A C E R
BEGIN_BBOX is placed before the data of the first set of objects in the data file
and the string END_BB OX is placed after the end of the data of the last set of
objects. The reason for using a bounding box is to accelerate computations.
Instead of checking whether each ray intersects each nearby object, we can first
check to see if the ray intersects the bounding box. If it does not (as will happen
in most cases), we are through. Only for the few rays that intersect the bounding
box do we need to test against each of the enclosed objects for an intersection.
When the BEGIN_BBOX string is encountered, we first create an object of the
BBOX type. We then copy the current name to its name parameter. We then run
get_data recursively, putting all of the objects encountered into a separate linked
list until the string END_BBOX is encountered. At this point we terminate
get_data and place the address of the last object entered into the linked list in the
child of the box we are creating.
Processing Objects
Next, get_data calls the function Get_Object if the string indicates that
object data is to be processed. This function uses a switch statement to call the
proper function for the object to be created.
Creating a Sphere
If a sphere is to be created, we first allocate memory space. (The call to new
for class Sphere not only assigns the proper amount of memory, but also assures
that this object is always of class Sphere.) Next the function begins a while loop,
where it remains until the file ends or a right parenthesis is encountered. At the
beginning of each iteration of this loop, the parser gets a string. The parameter
found is set to TRUE. A switch statement is then run to see if the string matches
any parameters for the class Sphere. Except for the PATTERN string, which we
will describe later, each acceptable string generates a vector or number from the
data and stores it in the appropriate object variable location.
Some of these variables are optional; others are essential to the creation of a
sphere. When an essential variable is processed, the no_yaram variable has a bit
set in it so that when the loop is terminated, the parameter will contain a 3 if the
1 47
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +
essential parameters have been read. If the parameter does not contain a 3 when
the loop is finished, an error message is displayed and the program terminates.
As in processing several of the attributes, the default for the switch statement is
to set the found parameter to FALSE. So, upon leaving the loop, i f thi s
parameter is FALSE, i t indicates that an incorrect string was encountered. I n this
situation, the program displays an error message and terminates. Otherwise, the
function proceeds to precompute any parameters that do not change for the
sphere and are needed in the process of computing ray intersection s . B y
computing them at this point and storing them i n the object data structure, only
one c o m p u t a t i o n i s req u i re d ( rather than one for e v e r y ray t e s t e d fo r
intersection). In the case of the sphere, the only parameter that is computed is
nl . Finally, WORLD .objcount is incremented, which keeps count of the total
number of objects in the scene.
Creating a Triangle
As with a sphere, we allocate the memory space for a triangle by calling new
(for class Triangle) which not only assigns the proper amount of memory, but
assures that this object is always of class Triangle. Next, the function begins a
while loop, where it remains until the fi le ends or a right parenthe s i s i s
encountered. A t the beginning o f each iteration of this loop, the parser gets a
string. The parameter found is set to TRUE and a switch statement runs to see if
the string matches any of the acceptable parameters for the class Triangle .
Except for the PATTERN string, each acceptable string causes a vector or
number to be read from the data and stored in the appropriate object variable
location . S ome of these variables are optional ; others are essential to the
creation of a triangle. When an essential variable is processed, the no_yaram
variable has a bit set in it in such a manner that when the loop is terminated, the
parameter will contain a 7 if the essential parameters have been read in. If the
parameter does not contain a 7 when the loop is finished, an error message is
displayed and the program terminates. As in processing several of the attributes,
the default for the switch statement is to set the found parameter to FALSE. So,
on leaving the loop, if this parameter is FALSE, it indicates that an incorrect
string was encountered. In this situation, the program displays an error message
1 48
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R
and terminates. The critical parameters for the triangle are: loc, which is the
location of one of the vertices of the triangle in system coordinates; vl (stored as
vectl ), which is in a coordinate system centered at the first vertex; and v2 (stored
as vect2 ) , the third vertex of the triangle which is also in a coordinate system
centered at the first vertex. The triangle processing function precomputes norm,
nl , lenl , and len2 , which are used in the intersection computations. Finally, this
function also increments the object count.
Creating a Ring
If a ring is to be created, we first allocate the memory space for a ring. (The
call to new for class Ring not only assigns the proper amount of memory, but
also assures that this object is forevermore known to be of class Ring.) Next, the
function begins a while loop, in which it remains until the file ends or a right
parenthesis is encountered. At the beginning of each iteration of this loop, the
parser is used to get a string. The parameter found is set to TRUE. A switch
statement i s then run to see i f the string m atches any of the acceptable
parameters for the class Ring. Except for the PATTERN string, which we will
describe later, each acceptable string causes a vector or number to be read from
the data and stored in the appropriate object variable location. Some of these
variables are optional; others are essential to the creation of a ring. When an
essential variable is processed, the no_yaram variable has a bit set in it in such a
manner that when the loop is terminated, the parameter will contain a 3 1 if the
essential parameters have been read in. If the parameter does not contain a 3 1
when the loop i s finished, an error message i s displayed and the program
terminates.
As in processing several of the attributes, the default for the switch statement
is to set the found parameter to FALSE. So, upon leaving the loop, if this
parameter is FALSE, it indicates that an incorrect string was encountered. In this
situation, the program displays an error message and terminates. The ring
processing function precomputes norm, nl , lenl , and len2 , which are used in the
1 49
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +
1 50
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R
modify the software so that a fourth vertex can be entered as an input, the
parallelogram object can become a generalized quadralateral. The parallelogram
processing function precomputes norm, nl , lenl , and len2 , which are used in the
intersection computations. Finally, this function also increments the object
count.
Some of these variables are optional; others are essential to the creation of a
quadratic. When an essential variable is processed, the no_yaram variable has a
bit set in it in such a manner that when the loop is terminated, the parameter will
contain a 3 1 if the essential parameters have been read in. If the parameter does
not contain a 3 1 when the loop is finished, an error message is displayed and the
program terminates. As in the processing of several of the attributes, the default
for the switch statement is to set the found parameter to FALSE. So, upon
leaving the loop, if this parameter is FALSE, it indicates that an incorrect string
was encountered. In this situation, the program displays an error message and
term inate s . The quadratic preprocessing function normalizes vectl and
precomputes cos] and sin] . It then computes the direction vector newdir, using
vectl and cos] and sin] . Using this new vector, it precomputes cos2 and sin2 .
Finally, this function also increments the object count.
1 51
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +
Creating a Cone
The function for creating a Quadratic can produce a wide variety of shapes,
depending on the coefficients assigned to the terms of the equation. However,
the coefficient values needed for a shape are not always evident. Consequently,
you may w ant to create some new shape names , which use the quadratic
equation. A cone is an example of how such functions are created.
To begin w ith, you need to add the shape name at the beginning of the
input.cpp listing, and an appropriate define statement in the header file.
You need to do this for any new parameter names you will use. Now look at
the GetCone function to see how it is written. It is similar to the other functions
for getting objects except that it creates a new object of class Quadratic. The
terms processed within the switch statement used to define the cone are: radius
(at the base of the cone), cone height, and direction (which is the same as the
curve direction used in getting a quadratic).
After all input data is collected, we convert the radius and height parameters
into the proper coeffic ients for the quadratic equation to produce a cone.
Nothing else has to be done; all of the additional parts of the ray-tracing program
treat this cone in the same way as any other object of class Quadratic. You can
use this technique to create any shapes defined by a quadratic, such as a cylinder.
1 52
C O M M U N I C AT I N G W I T H T H E R AV T R A C E R
pattern with the name of the pattern that was read in for the object. If there is a
match, the function terminates and the address of the pattern is returned to the
object function where it is saved as part of the object data structure. If there is
no match, the function obtains the address of the next pattern in the list and
reiterates the loop. If a NULL address is obtained, it indicates that the entire list
has been read without a match being found. In this case, an error message is
displayed and the program terminates.
The found parameter is used a little differently. It starts out as TRUE. After
passing through the switch statement, if the string is not one of the three that
must occur initially in the pattern definition, the default case sets it to FALSE.
After leaving the switch statement, the function calls the Get_SubPattern
function to process data for one of three pattern types. If this function i s
successful, the n oyaram parameter has the appropriate bit added to it, the found
parameter is reset to TRUE, and the address of the sub-pattern put into a list
pointed to by the child parameter.
1 53
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
When the loop i s completed, the function displays an error message and
terminates the program if found is false. Otherwise, it checks the value of
no_param to make sure all required parameters were read from the file. If so,
the parameter should be 1 5 . If not, an error message is d isplayed and the
program terminates. Otherwise, the pattern address is linked to the pattern list
and the function ends.
1 54
C O M M U N I C AT I N G W I T H T H E R AY T R A C E R
terminates. Otherwise, the color data is transferred to the pattern structure and
the function returns the address of the sub-pattern.
Two parameters are mandatory : the name of the instance, and the location at
which the instance is to be generated. A switch statement is used to check for
these mandatory parameters (using the no_yaram variable to assure that both
occur) for the multiplier vector (which is optional), and for the right parenthesis.
The found parameter is used to cause the program to display an error message
1 55
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +
This function checks the name just read against every instance name in the
list of instances. If no match occurs, an error message is displayed and the
program terminates. If a match does occur, the function calls Move_Instance.
This function first sets up a new object to match the object in the instances file.
It copies all of the data for that object from the instances file to the new object.
It then calls itself recursively to perform the same operations for any child
objects or succeeding objects in the instances list that are part of the named
instance. Then, the Get_Instance_Of function calls the Scale_Instance function
to apply the multiplier vector to the object. Thi s function differs for each
different type of object under consideration. It will be discussed in detail in
Chapter l 0. Finally, the Get_Instance_Of function calls the Offset_Instance
function which moves the object location from that specified in the instance to
that read in above for this particular instance. It recursively does the same for all
objects associated with this instance.
The Make_BBox function then applies the minimum function to the object
lower bounding box and the new lower bound and the maximum function to the
1 56
C O M M U N I C AT I N G W I T H T H E R AV T R A C E R
object upper bound and the new upper bound. Here, minimum and maximum
mean that we take the minimum or maximum of each coordinate to create a new
set of coordinates. When the process is completed, all objects are encompassed
within the bounding box.
1 57
CHAPTER 9
FILE NAM E
In order to specify the name of the output file for the scene data, the string
FILE_NAME must appear in the data stream. It must be followed by at least one
non- string type character and may be followed by as many non- string type
characters as desired. The next string must be an MS-DOS compatible type file
name.
1 59
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +
PATTERN
The PATTERN string is used to initiate the description of a pattern. (The
pattern is projected onto the surface of whatever object has a pattern of this
name.) The string must be followed by at least one string type character and
may be fol l owed by as many non- string type characters as desired. The
following strings may follow the PATTERN string:
X_SIZE This denotes the size of the pattern in the x direction. It must be
followed by one or more non-string type characters, followed by a number
representing the x pattern size, then followed by one or more non-string type
characters.
Y_SIZE This denotes the size of the pattern in the y direction. It must be
followed by one or more non-string type characters, followed by a number
representing the y pattern size, and followed by one or more non-string type
characters.
NAME This denotes the name of the pattern. It must be followed by one or
more non-string type characters, followed by a string giving the pattern name,
which must be followed by one or more non-string type characters.
The above three strings are mandatory for the PATTERN description .
Follow ing them one or more group s of strings must occur to prov ide a
description of the pattern. The first entry in each group must be one of the
following three strings RECTANGLE, which denotes a rectangle pattern,
CIRCLE, which denotes a circle pattern, or POLYGON, which denotes a
polygon pattern. The string must be followed by one or more non-string type
characters. Following all of the information that makes up one of these three
types of patterns, a right parenthesis must occur to complete the pattern data.
1 60
U S I N G T H E R AY T R A C I N G D E F I N I T I O N L A N G U A G E
EN D_X This denotes the end x position of the rectangle pattern. It must be
followed by one or more non-string type characters, which must be followed by
a number corre sponding to the x pattern ending position, which must be
followed by one or more non-string type characters.
E N D_Y This denotes the end y position of the rectangle pattern. It must be
followed by one or more non-string type characters, which must be followed by
a number corre sponding to the y pattern ending position, which must be
followed by one or more non-string type characters.
Color I nformation Any of the items which make up the color data may be
specified in the rectangle pattern data. These are described in the next section.
Note that there is no specific order in which the acceptable strings need to be
listed. You may arrange them at your convenience. After all information for the
rectangle has been supplied, a right parenthesis must occur to terminate the
rectangle pattern data.
RADIUS This denotes the radius of the circle pattern. It must be followed
by one or more non-string type characters, which must be followed by a number
corresponding to the x pattern beginning position, which must be followed by
one or more non-string type characters.
1 61
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +
Color I nformation Any of the items which make up the color data may be
specified in the circle pattern data. These are described in the next section. Note
that there is no specific order in which the acceptable strings need to be listed.
You may arrange them at your convenience. After all information for the circle
has been supplied, a right parenthesis must occur to terminate the rectangle
pattern data.
POI NT This denotes that the coordinates of one point of the polygon pattern
will follow. It must be followed by one or more non-string type characters,
which must be followed by a number corresponding to the x coordinate of the
polygon, which must be followed by one or more non-string type characters,
which must be followed by a number corresponding to the y coordinate of the
polygon, which must be followed by one or more non-string type characters.
The POINT string and its associated numbers must occur at least three times to
define a polygon.
Color Information Any of the items which make up the color data may be
specified in the polygon pattern data. These are described in the next section.
Note that there is no specific order in which the acceptable strings need to be
listed. You may arrange them at your convenience. After all information for the
polygon has been supplied, a right parenthesis must occur to terminate the
rectangle pattern data.
COLOR
Color information may be supplied in two ways. First, there is a default set
of color information which will be used for an object or pattern if other color
information is not furnished. This default color information may be set by
placing the s tring COLOR in the data fi l e . Any of the items of c o l or
information shown below may then occur. When all color information is
complete, the color section must be completed by a right parenthesis. The other
way of supplying color information is to include it in the description of an
1 62
U S I N G T H E R AY T R A C I N G DEFINITION LANGUAGE
object or pattern. Any of the color information items shown below may be
included in an object or pattern description and will then supersede the default
information for this object or pattern only. The strings that may be included as
color information are as follows (the order is immaterial):
AMB This denotes the character of the ambient light impinging upon the
object or pattern. It must be followed by one or more non-string type characters,
which must be followed by three numbers (separated by one or more non-string
type c h arac ters) w h i c h make up the ambient l ight red , green, and blue
components. The last number must be followed by one or more non-string type
characters.
DIFF This denotes the character of the light diffused by the object or
pattern. It must be followed by one or more non-string type characters, which
must be followed by three numbers (separated by one or more non-string type
characters) which make up the diffused light red, green, and blue components.
The last number must be followed by one or more non-string type characters.
M I R ROR This denotes the amount of light directly reflected by the object
or pattern. It must be followed by one or more non-string type characters, which
must be followed by three numbers (separated by one or more non-string type
characters) which make up the reflecting red, green, and blue characteristics.
The last number must be followed by one or more non-string type characters.
1 63
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
$RE FLECT This denotes the specular reflection coefficient for an object or
pattern. It must be followed by one or more non-string type characters which
must be followed by a floating-point number which is the specular reflection
coefficient, which must be followed by one or more non-string type characters.
BEGIN BBOX
The BEGIN_BBOX string marks the beginning of a box that will enclose
several objects. It must be followed by at least one non-string type character. It
is followed by descriptions of all of the objects which are to be enclosed within
the box. The box is terminated by the string END_BBOX, which is followed by
one or more non-string type characters.
1 64
U S I N G T H E R AY T R A C I N G D E F I N I T I O N LANGUAGE
BEGIN_INSTANCES
The BEGIN_INSTANCES string marks the beginning of an object or group
of objects that are to appear as a group at several places throughout a scene. It
must be followed by one or more non-string type characters. This must be
followed by the descriptions of one or more objects which make up the instance.
The instance description is terminated by the string END_INSTANCE S ,
followed b y one o r more non-string type characters. The BEGIN_INSTANCES
and END_INSTANCES strings may occur only once in a data file. All instances
to be used in the scene must be included between these two strings in their one
occurrence.
SPHERE
The S PHERE string denotes data for an object which is a sphere. It is
followed by one or more non-string type characters. This is followed by any of
the sphere descriptive items shown below. Finally, the sphere description is
terminated by a right parenthesis. The legitimate strings for a sphere are:
LOC This denotes the location of the sphere. It must be followed by one or
more non-string type characters, which must be followed by three numbers
( separated by one or more non- string type characters) which make up the
location vector. The last number must be followed by one or more non-string
type characters.
RADIUS This denotes the radius of the sphere. It must be followed by one
or more non-string type characters, which must be followed by a floating-point
number which is the sphere radius, which must be followed by one or more non
string type characters.
1 65
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
NAME This denotes a name for the sphere. It is used only when the sphere
is part of an instance. It must be followed by one or more non-string type
characters , which are followed by a string which is the name of the sphere,
which must be followed by one or more non-string type characters.
Color I nformation Any of the items which make up the color data may be
specified in the sphere object data. These are described in the previous section.
Note that there is no specific order in which the acceptable strings need to be
listed. You may arrange them at your convenience. After all information for the
sphere has been suppl ied , a right parenthesis must occur to terminate the
rectangle pattern data.
TRIANG LE
The TRIANGLE string denotes data for an object which is a triangle. It is
followed by one or more non-string type characters. This is followed by any of
1 66
U S I N G T H E R AY T R A C I N G D E F I N I T I O N L A N G U A G E
the triangle descriptive items shown below. Finally, the triangle description is
terminated by a right parenthesis. The legitimate strings for a triangle are:
LOC This denotes the location of the triangle. It must be followed by one or
more non-string type characters, which must be followed by three numbers
( separated by one or more non-string type characters) which make up the
location vector. The last number must be followed by one or more non-string
type characters.
V1 This denotes one of the apexes of the triangle. It is assumed that the
first apex of the triangle is indicated by the location vector. This is the second
apex. Its position is given with respect to the first apex. It must be followed by
one or more non-string type characters , which must be fol lowed by three
numbers (separated by one or more non-string type characters) which make up
the apex coordinates. The last number must be followed by one or more non
string type characters.
V2 This denotes one of the apexes of the triangle. It is assumed that the
first apex of the triangle is indicated by the location vector. This is the third
apex. Its position is given with respect to the first apex. It must be followed by
one or more non-string type characters, which must be followed by three
numbers (separated by one or more non-string type characters) which make up
the apex coordinates. The last number must be followed by one or more non
string type characters.
1 67
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
NAME This denotes a name for the triangle. It is used only when the sphere
is part of an instance. It must be followed by one or more non-string type
characters, which are followed by a string which is the name of the triangle,
which must be followed by one or more non-string type characters.
Color I nformation Any of the items which make up the color data may be
specified in the triangle object data. These are described in a previous section.
Note that there is no specific order in which the acceptable strings need to be
listed. You may arrange them at your convenience. After all information for the
triangle has been supplied, a right parenthesi s must occur to terminate the
triangle pattern data.
RING
The RING string denotes data for an object which is a ring. It is followed by
one or more non-string type characters. This is followed by any of the ring
descriptive items shown below. Finally, the ring description is terminated by a
right parenthesis. The legitimate strings for a ring are:
1 68
U S I N G T H E R AV T R A C I N G D E F I N I T I O N L A N G U A G E
LOC This denotes the location of the ring. It must be followed by one or
more non-string type characters, which must be followed by three numbers
( separated by one or more non-string type characters) which make up the
location vector. The last number must be followed by one or more non-string
type characters.
V1 This denotes one of two vectors which define the plane of the ring. Its
position is given with respect to location vector. It must be followed by one or
more non-string type characters , which must be followed by three numbers
(separated by one or more non-string type characters) which make up the vector.
The last number must be followed by one or more non-string type characters.
V2 This denotes the second of two vectors which define the plane of the
ring. Its position is given with respect to location vector. It must be followed
by one or more non-string type characters , which must be followed by three
numbers (separated by one or more non-string type characters) which make up
the vector. The last number must be followed by one or more non-string type
characters.
RAD_1 This denotes the inner radius of the ring. It must be followed by
one or more non-string type characters, which must be followed by a floating
point number which is the inner ring radius, which must be followed by one or
more non-string type characters.
RAD_2 This denotes the outer radius of the ring. It must be followed by
one or more non-string type characters, which must be followed by a floating
point number which is the outer ring radius, which must be followed by one or
more non-string type characters.
1 69
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +
NAME This denotes a name for the ring. It is used only when the ring is
part of an instance. It must be followed by one or more non-string type
characters, which are followed by a string which is the name of the ring, which
must be followed by one or more non-string type characters.
PAR E N This is the right parenthesis which terminates the ring description.
Color Information Any of the items which make up the color data may be
specified in the ring object data. These are described in a previous section. Note
that there is no specific order in which the acceptable strings need to be listed.
You may arrange them at your convenience. After all information for the ring
has been supplied, a right parenthesis must occur to terminate the ring pattern
data.
PARALLELOG RAM
The PARALLELOGRAM string denotes data for an object which is a
parallelogram. It is followed by one or more non-string type characters. This is
followed by any of the parallelogram descriptive items shown below. Finally,
1 70
U S I N G T H E R AY T R A C I N G D E F I N I T I O N L A N G U A G E
1 71
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
NAME This denotes a name for the parallelogram. It is used only when the
parallelogram is part of an instance. It must be followed by one or more non
string type characters, which are followed by a string which is the name of the
paral l e l ogram , which m u s t be fo l l owed by one or more non- s tring type
characters.
Color I nformation Any of the items which make up the color data may be
specified in the parallelogram object data. These are described in a previous
section. Note that there is no specific order in which the acceptable strings need
to be listed. You may arrange them at your convenience. After all information
for the parallelogram has been supplied, a right parenthesis must occur to
terminate the parallelogram pattern data.
1 72
U S I N G T H E R AV T R A C I N G D E F I N I T I O N L A N G U A G E
QUADRATIC
The QUADRATIC string denotes data for an object which is expressed by a
quadratic equation. The equation to denote this object is: A x 2 + B y2 + C z2 +
Ez = D (Equation 9- 1 ). The string is followed by one or more non-string type
characters. This is followed by any of the quadratic descriptive items shown
below. Finally, the quadratic description is terminated by a right parenthesis.
The legitimate strings for a quadratic are:
LOC This denotes the location of the quadratic. It must be followed by one
or more non-string type characters, which must be followed by three numbers
(separated by one or more non- string type characters) which make up the
location vector. The last number must be followed by one or more non-string
type characters.
1 73
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
XMIN This denotes the minimum value for the x coordinate in the quadratic
equation. It must be followed by one or more non-string type characters, which
must be followed by a floating-point number which is the minimum x value,
which must be followed by one or more non-string type characters.
XMAX This denotes the maximum value for the x coordinate in the
quadratic equation. It must be followed by one or more non-string type
characters, which must be followed by a floating-point number which i s the
maximum x value, which must be followed by one or more non-string type
characters.
YMIN This denotes the minimum value for the y coordinate in the quadratic
equation. It must be followed by one or more non-string type characters, which
must be followed by a floating-point number which is the minimum y value,
which must be followed by one or more non-string type characters.
YMAX This denotes the maximum value for the y coordinate in the
quadratic equation. It must be followed by one or more non-string type
characters, which must be followed by a floating-point number which is the
maximum y value, which must be followed by one or more non-string type
characters.
ZMIN This denotes the minimum value for the z coordinate in the quadratic
equation. It must be followed by one or more non-string type characters, which
must be followed by a floating-point number which is the minimum z value,
which must be followed by one or more non-string type characters.
1 74
USING THE R AV T R A C I N G DEFINITION LANGUAGE
ZMAX This denotes the maximum value for the z coordinate in the quadratic
equation. It must be followed by one or more non-string type characters, which
must be followed by a floating-point number which is the maximum z value,
which must be followed by one or more non-string type characters.
DIR This denotes a vector which indicates the direction of the axis of the
quadratic. It must be followed by one or more non-string type characters, which
must be followed by three numbers (separated by one or more non-string type
characters) which make up the direction vector. The last number must be
followed by one or more non-string type characters.
NAME Thi s denotes a name for the quadratic. It is used only when the
quadratic is part of an instance. It must be followed by one or more non-string
1 75
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
type characters , which are followed by a string which i s the name of the
quadratic, which must be followed by one or more non-string type characters.
Color i nformation Any of the items which make up the color data may be
specified in the quadratic object data. These are described in a previous section.
Note that there is no specific order in which the acceptable strings need to be
listed. You may arrange them at your convenience. After all information for the
quadratic has been supplied, a right parenthesis must occur to terminate the
quadratic pattern data.
CON E
The CONE string denotes data for an object which i s expressed by a
quadratic equation of the form :
where r is the radius of the cone at its base and h is the height of the cone. The
string is followed by one or more non-string type characters. This is followed by
any of the cone descriptive items shown below. Finally, the cone description is
terminated by a right parenthesis. The legitimate strings for a cone are:
LOC This denotes the location of the cone. It must be followed by one or
more non-string type characters, which must be followed by three numbers
(separated by one or more non- string type characters) which make up the
location vector. The last number must be followed by one or more non-string
type characters.
This denotes the radius of the cone at its base. It must be followed
RADIUS
by one or more non-string type characters , which must be followed by a
floating-point number which is the radius value, which must be followed by one
1 76
USING THE R AY T R A C I N G DEFINITION LANGUAGE
DIR This denotes a vector which indicates the direction of the axis of the
cone. It must be followed by one or more non-string type characters, which must
be followed by three numbers (separated by one or more non-string type
characters) which make up the direction vector. The last number must be
followed by one or more non-string type characters.
NAME This denotes a name for the cone. It is used only when the cone is
part of an instance. It must be followed by one or more non-string type
characters, which are followed by a string which is the name of the cone, which
must be followed by one or more non-string type characters.
1 77
F R A C TA L P R O G R A M M I N G A N D R A Y T R A C I N G W I T H C + +
PAREN This is the right parenthesis which terminates the cone description.
Color I nformation Any of the items which make up the color data may be
specified in the quadratic object data. These are described in a previous section.
Note that there is no specific order in which the acceptable strings need to be
listed. You may arrange them at your convenience. After all information for the
cone has been supplied, a right parenthesis must occur to terminate the cone
pattern data.
S KY
The SKY string denotes data for color of the sky. It is followed by one or
more non-string type characters. This is followed by any of the sky descriptive
items shown below. Finally, the sky description is terminated by a right
parenthesis. The legitimate strings for the sky are:
This denotes the color of the sky at the zenith. It must be followed
ZEN ITH
by one or more non-string type characters, which must be followed by three
numbers (separated by one or more non-string type characters) which make up
the red, green, and blue components of the color. The last number must be
followed by one or more non-string type characters.
HORIZ This denotes the color of the sky at the horizon. It must be followed
by one or more non-string type characters, which must be followed by three
numbers (separated by one or more non-string type characters) which make up
the red, green, and blue components of the color. The last number must be
followed by one or more non-string type characters.
PAREN This is the right parenthesis which terminates the sky description.
1 78
USING THE R AY T R A C I N G DEFI NITION LANGUAGE
FOC_LENGTH
The FOC_LENGTH string denotes the focal length of a 35 millimeter lens to
give the equivalent perspective to the picture. It must be followed by one or
more non-string type characters, which are followed by a floating-point number
giving the focal length of the lens, which is followed by one or more non-string
type characters.
LAM P
The LAMP string denotes data fo r a light source. I t i s followed by one or
more non-string type characters. This is followed by any of the lamp descriptive
items shown below. Finally, the lamp description is terminated by a right
parenthesis. The legitimate strings for the lamp are:
LOC This denotes the location of the light source. It must be followed by
one or more non-string type characters , which must be followed by three
numbers (separated by one or more non-string type characters) which make up
the location vector. The last number must be followed by one or more non-string
type characters.
RADIUS This denotes the radius of the light source. It must be followed by
one or more non-string type characters, which must be followed by a floating
point number which is the radius of the light source, which must be followed by
one or more non-string type characters.
DIST This denotes the distance from the light source at which the lighting of
objects will be at a normal intensity. Objects closer than this will be overlit
(washed out) while objects farther away will be darker than normal. The string
must be followed by one or more non-string type characters, which must be
followed by a floating-point number which is the distance of the light source,
which must be followed by one or more non-string type characters.
1 79
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
This denotes the direction for the observer. It must be followed by one
UP
or more non-string type characters, which must be followed by three numbers
(separated by one or more non-string type characters) which make up the UP
vector. The last number must be followed by one or more non-string type
characters.
XRES
The XRES string denotes the x resolution of the display. It must be followed
by one or more non-string type characters, which are followed by a floating
point number giving the x resolution, which is followed by one or more non
string type characters.
1 80
U S I N G T H E R AV T R A C I N G D E F I N I T I O N L A N G U A G E
Y RES
The YRES string denotes the y resolution of the display. It must be followed
by one or more non-string type characters, which are followed by a floating
point number giving the y resolution, which is followed by one or more non
string type characters.
NAM E
The NAME string denotes a name. It must be followed by one or more non
string type characters, which are followed by a string designating a name, which
is followed by one or more non-string type characters.
Sample Fi les
Figure 9- 1 i s a small sample file of data for a scene written in the QRT
language format. This file can be read and processed with the ray-tracing
program described in this book. For comparison, Figure 9-2 lists the same file,
showing the minimum that is required for processing the file with the input
functions described in this chapter. You can see that you have a lot of flexibility
w i th a d d i ng n o n - s tring type c h aracters to create a format that you are
comfortable with and which still can be read with these functions.
F I L E_ N A M E = S p h e r e RAW
.
PATT E R N ( x_s i z e = 60 ,
y_s i z e = 60 ,
n a me = CHECK ,
R E C TA N G L E (
s t a r t_x = 0,
s t a r t_y = 0,
e n d_x = 30 ,
e n d_y = 30 ,
di ff = ( .1,1.0, .1) ,
di ther = O,
)
RECTANG LE (
s t a r t_x 30 ,
s t a r t_y 30 ,
1 81
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
e n d_x = 60 ,
e n d__y = 60 ,
di ff = ( .1,1.0, .1) ,
di ther = 0,
)
LAMP ( l oc = ( 1 20 , 1 20 , - 50 ) ,
radi us = 5,
di st = 80
)
LAMP ( l oc = ( 1 20 , 1 5 0 , 80 ) ,
ra d i us = 5,
di st = 70
)
S KY ( hori z = ( . 2 , . 2 , . 55 ) ,
zen i t h ( . 1 , . 1 , . 25 ) ,
di ther = 1
)
1 82
U S I N G T H E R AY T R A C I N G D E F I N I T I O N L A N G U A G E
XRES 320
Y RES 200
FOC L E NGTH 80
F I L E_ N A M E S p h e r e . R A W
P A T T E R N ( x_ s i z e 60
y_s i z e 60
n a me C H E C K
R E C TA N G L E
sta rt x O
s t a r t_y 0
e n d_x 30
e n d_y 30
d i ff . 1 1 . 0 . 1
di ther 0
)
RE CTAN G L E )
s t a r t_x 30
s t a r t_y 30
e n d_x 60
e n d_y 60
d i ff . 1 1 . 0 . 1
di ther O
)
P A RA L L E L O G R A M
l oc - 1 0000 0 - 1 0000
vl 20000 O 0
v2 0 0 20000
d i ff . 8 . 8 0
di ther O
pa t t e r n CH EC K
xm u l t 2
ymu l t 2
1 83
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
SPHERE (
l Qc 200 90 80
radi us 35
di ff . 3 . 3 . 8
amb . 32 . 32 . 32
refl ect . 60
s refl ect 20
xmu l t 1 . 0
ym u l t 1 . 0
)
LAMP
l QC 120 1 20 - 50
radi us 5
d i s t 80
)
LAMP
l QC 120 1 50 80
radi us 5
di st 70
)
S KY (
hQri z . 2 . 2 . 55
zen i t h. 1 . 1 . 25
di ther 1
)
XRES 320
YRES 200
F O C_ L E N G T H 80
1 84
CHAPTER 1 0
object. Test();
cl ass S h a pe
. . . c l a s s memb e r d e f i n i t i on s ;
1 85
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
} ;
. . . c l a s s membe r d e f i n i t i on s ;
i nt Test ( i nt a , fl oat b ) ;
} ;
The fact that the name of the class is followed by a colon, the word public,
and the name of a previously defined class, makes this class a derived class,
which inherits all of the characteristics of the base class and may include various
special members of its own. If you want to use the common function (Test in the
example) you must include in the definition of Sphere a prototype of the function
which is the same as that for the Virtual function in the base class, except that the
word Virtual is omitted. The same procedure for the definition of the classes is
the Cone and Cube.
Next, you must have a definition for each of the functions. This includes a
definition for the function for the base class, which must be defined, even if there
is nothing in it. For example,
1 86
F U N C T I O N S T H AT M AT C H A N O B J E C T: V I R T U A L F U N C T I O N S
ope ra t i on c ;
ope ra t i on d :
i n t C u be : : Te s t ( i n t a. f l oa t b )
ope ra t i on e :
ope ra t i on f ;
Note the format for the first line of each function definition. The type of the
variable returned by the function comes first. It must be the same as it was in the
prototype definition. Next comes the name of the particular class for which the
function is being defined. It is followed by two colons, the name of the function
and the variables that are passed by it. This part of the definition must be the
same for each definition of the function and match the prototype definition.
Finally comes the body of the definition which may be different for each of the
definitions. Once you have done this groundwork, you can use this function
throughout your program as we discussed at the beginning of the chapter. Call
the function by preceding the normal function call with the name of an object,
followed by a dot. The function will have access to the members of the named
1 87
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
object. The program will automatically look at the object, determine to what
class it belongs, and use the definition of the function which matches that class
to perform the function operations.
Constructors
The constructor is a special kind of function automatically called by the
program to initialize an object, each time an object is defined. It is identified by
the same name as the class. Thus, a typical constructor would look like:
Sphe re : : Sphe re ( )
{
membe r d e f i n i t i o n s . :
The objects.cpp file begins with the definition of a constructor for each of
the five different types of objects. You can look at them in the listing of Figure
l 0- 1 . There is nothing particularly unusual about them. They simply specify the
initial values the members of the object should have. Mostly they are NULLS .
The type in each case corresponds to the proper number for the type of object.
The multipliers are set to default values of one. The color information is set to
the default values.
Destructors
Whenever you define a class member, the required memory space remains
assigned to that class member forever unless you deallocate it. If you want to
deallocate the memory assigned to this class member when you are through
1 88
F U N C T I O N S T H AT M AT C H A N O B J E C T: V I R T U A L F U N C T I O N S
using it, you must call a destructor function. Similarly, if you assign space for a
class member with new, thi s memory will be reserved forever unless you
deallocate it with the function delete. Since almost all of our class members in
this program are allocated using new, we don't use destructors. If you need them
for your program, refer to the C++ manual for details on how to create them.
/*
obj e c t s . c Fun c t i ons bel ong i ng to e a c h of the c l a s ses
d e r i v e d f r om t h e O b j e c t c l a s s .
By R o g e r T. Stevens 3 / 1 /90
* / ll====!I
/*
Sphere Constructor
*/
Sphere : : Sphere ( )
{
ty p e = SPHERE ;
nextobj = NULL ;
chi l d = NU LL ;
pattern = NULL ;
remov e = NU L L ;
n a me [ O ] = NU LL ;
xmu l t l;
ymu l t l;
upper Vector ( ) ;
l ow e r Vector ( ) ;
1 89
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
/*
T ri a ng e Const ructor
== l ===!.I
��
============ ====================================
*/
/*
Ri ng Con st ructor
I�=====================================================!J
*/
Ri ng : : Ri ng ( )
{
ty p e = R I N G :
next obj = NU L L :
chi l d = NULL ;
pa t t e rn = NU L L :
remo v e = N U L L :
n a me [ O ] = N U L L ;
xmu l t 1:
ymu l t l·
uppe r Vector ( ) ;
l owe r Vector( ) ;
1 90
F U N C T I O N S T H AT M AT C H A N O B J E C T: V I R T U A L F U N C T I O N S
*
/
Pa ra l l e l ogram Co n s t ructor
*
/
Pa ra l l e l og ram : : P a r a l l e l ogram( )
{
t y p e = P A R A L L E L O G RA M ;
nextobj = N U L L ;
chi l d = NULL ;
pattern = NULL ;
remov e = NU L L ;
n a me [ O J = N U L L ;
xmu l t l;
ymu l t l;
uppe r Vector ( ) ;
l owe r Vector ( ) ;
vect3 Vector( ) ;
}
*
/
ua at c o t ructor
'
� ====Q===
d=r ==i==C==n=
s===== �I
============ ==============
*/
Qu a d r a t i c : : Quadrat i c ( )
{
t y p e = Q U A D RAT I C ;
nextobj = NU L L ;
chi l d = NULL ;
pattern = NU LL ;
remo v e = N U L L ;
n a me [ O J = N U L L :
c t e rm O;
y t e rm O;
xm u l t l;
ymul t l;
upper Vector( ) ;
l owe r Vector ( ) ;
1 91
F R A C TA L P R O G R A M M I N G A N D R A Y T R A C I N G W I T H C + +
L
I
�
*
/
No rma l f i nder for gen e r i c obj ect
========"
*
/
v o i d O bj e c t : : F i n d N o rm ( V e c t o r * n o rma l . Vector * po s i t i on )
{
)
*
/
N o rma l fi nder for sphere
*
/
*
/
N o rma l fi nder for pa ra l l el ogram
*
/
*
/
N o rma l fi nder for tri angl e
*
/
1 92
F U N C T I O N S T H AT M AT C H A N O B J E C T: V I R T U A L F U N C T I O N S
v o i d T r i a n g l e : : F i n d N o rm ( V e c t o r * n o rma l . Vector * po s i t i on )
{
* n o rm a l = n o rm :
*
/
*
/
v o i d R i n g : : F i n d N o rm ( V e c t o r * n o rma l . V e c t o r * po s i t i on )
{
* n o rma l = n o rm :
L
I =======o!ll
*
/
No rma l fi nder for quadrati c
� ·.
*
/
v o i d O u a d r a t i c : : F i n d N o rm ( V e c t o r * n o rm a l . Vector * pos i t i on )
{
V e c t o r n ew p o s . n ewd i r :
n ewpos = * po s i t i o n - l o c :
i f ( ( v e c t l . x == 0 ) & & ( v e c t l . y 1 ) && ( vectl . z 0) )
{
* n o rm a l v e c t 2 * n ew p o s :
* n o rma l - * n o rma l :
el se
{
n ew p o s = n ew p o s . Ro t a t e ( c o s l . si nl . cos 2 . s i n2 ) ;
n ewd i r = v e c t 2 * n ewp o s :
* n o rma l = n ewd i r . Re v_Rot a t e ( c o s l . si nl . cos2 . s i n2 ) :
I
}
1 93
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
L
I
�
/*
F i nd Bound i n g Box for Gen e r i c Obj ect
======="
*I
/*
Fi nd Bound i ng Box for Sphere
*/
I*
Fi nd Bound i ng Box for Pa r a l l el ogram
*/
1 94
F U N C T I O N S T H AT M AT C H A N O B J E C T: V I R T U A L F U N C T I O N S
v l - > y =M I N ( v l - > y . l o c . y ) ;
v l - > z =M I N ( p o i n t 2 . z . p o i n t 3 . z ) ;
v l - > z =M I N ( v l - > z . p o i n t 4 . z ) ;
v l - > z =M I N ( v l - > z , l o c . z ) ;
v 2 - > x= M A X ( p o i n t 2 . x , p o i n t 3 . x ) ;
v 2 - > x= M A X ( v 2 - > x , p o i n t 4 . x ) ;
v 2 - > x=M A X ( v 2 - > x . l o c . x ) ;
v 2 - >y=MAX ( p o i n t 2 . y , p o i n t 3 . y ) ;
v 2 - > y =M A X ( v 2 - > y . p o i n t 4 . y ) ;
v 2 - >y=MAX ( v 2 - >y , l o c . y ) ;
v 2 - > z =M A X ( p o i n t 2 . z , p o i n t 3 . z ) ;
v 2 - > z=MAX ( v 2 - > z . p o i n t4 . z ) ;
v 2 - > z =M A X ( v 2 - > z . l o c . z ) ;
I*
F i n d B o u n d i n g Box fo r T r i a n g l e
*/
1 95
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
/*
Fi nd Bound i ng Box for Bound i ng Box
*/
/*
Fi nd Bound i ng Box for Ri ng
*/
/*
F i nd Bound i ng Box for Qu a d r a t i c
*/
1 96
F U N C T I O N S T H AT M AT C H A N O B J E C T: V I R T U A L F U N C T I O N S
/*
C h a n g e s c a l e of u s e r defi ned generi c Obj ect
*/
v o i d O b j e c t : : S c a l e_ I n s t a n c e ( V e c t o r * m u l t , i n t f f l a g )
{
}
I
L
/*
Change s ca l e of u s e r defi ned Sphere
� ========!I
*/
v o i d S p h e r e : : S c a l e_ I n s t a n c e ( V e c t o r * m u l t , i nt ffl ag )
{
fl oat s i ze ;
I * rr======;i
C hange s c a l e of u s e r defi ned Pa ra l l el ogram
*I
v o i d P a r a l l e l o g r a m : : S c a l e_ I n s t a n c e ( V e c t o r * m u l t , i nt ffl ag )
{
l o c = l o c * *m u l t ;
v e c t l = v e c t l * *m u l t ;
v e c t 2 = v e c t 2 * *m u l t ;
c h i l d - > S c a l e_ I n s t a n c e ( m u l t , F A L S E ) ;
1 97
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
i f ( ! ffl a g )
n e x t o b j - > S c a l e_ I n s t a n c e ( m u l t , F A L S E ) ;
I*
C hange s ca l e of u s e r defi ned Ri ng
*I
v o i d R i n g : : S c a l e_ I n s t a n c e ( V e c t o r * m u l t , i nt ffl ag )
{
fl oat s i ze ;
/*
C hange s ca l e of user defi ned Tri angl e
*I
v o i d T r i a n g l e : : S c a l e_ I n s t a n c e ( V e c t o r * mul t . i nt ffl ag )
{
l a c = l a c * *m u l t ;
v e c t l = v e c t l * *m u l t ;
v e c t 2 = v e c t 2 * *m u l t ;
c h i l d - > S c a l e_ I n s t a n c e ( m u l t , F A L S E ) ;
i f ( ! ffl a g )
n e x t o b j - > S c a l e_ I n s t a n c e ( m u l t , F A L S E ) ;
1 98
F U N C T I O N S T H AT M AT C H A N O B J E C T: V I R T U A L F U N C T I O N S
I*
C hange s ca l e of u s e r defi ned Quadra t i c
*/
v o i d Q u a d r a t i c : : S c a l e_ I n s t a n c e ( V e c t o r * m u l t , i nt ffl ag )
{
fl oat s i ze ;
u p p e r = u p p e r * *m u l t ;
l ow e r = l ow e r * *m u l t ;
l o c = l o c * *m u l t ;
c h i l d - > S c a l e_ I n s t a n c e ( m u l t , F A L S E ) ;
i f ( ! ffl ag )
n e x t o b j - > S c a l e_ I n s t a n c e ( m u l t , F A L S E ) ;
/*
D e t e rm i n e p o s i t i o n v a r i a b l e s f o r g e n e r i c obj e c t
*/
/*
D e t e rm i n e p o s i t i on v a r i a b l e s f o r s p h e re
*I
Vector del ta ;
del t a = * l ocati on - l oc :
1 99
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
/*
Dete rmi n e pos i t i on v a r i a b l es for t r i a n g l e
*/
Vector del ta ;
fl oat l ength l , l ength2 ;
del ta * l oc a t i on - l oc ;
l engt h l s q rt ( vectl % vectl ) ;
l ength2 sqrt ( vect2 % vect2 ) ;
*pos l ( del ta % vectl ) l ength l ;
/
*pos2 = ( del ta % vect2 ) l ength2 ;
/
/*
D e t e rm i n e po s i t i on v a r i a b l e s f o r p a r a l l e l og r a m
*/
Vector del ta ;
fl oat l engthl , l ength2 ;
de l t a * l oc a t i on - l oc ;
l engt h l sqrt ( vectl % vectl ) ;
l ength2 sqrt ( vect2 % vect2 ) :
*pos l ( del ta % vect l ) l ength l ;
/
*pos2 = ( del ta % vect2 ) l ength2 ;
/
200
F U N C T I O N S T H AT M AT C H A N O B J E C T: V I R T U A L F U N C T I O N S
/*
Det e rm i n e po s i t i on v a r i a b l e s for r i ng
*
/
Vector del ta ;
fl oat l engt h l , l ength2 ;
del ta = * l oc a t i on - l ac ;
l eng t h l sqrt ( vectl % vectl ) ;
l ength2 sqrt ( vect2 % vect2 ) ;
*pos l ( de l ta % vect l ) l engt h l ;
/
*pos2 = ( del ta % vect2 ) l ength2 ;
/
/*
Dete rmi ne pos i t i on v a r i a b l es for q u a d ra t i c
*
/
V e c t o r n ewp o s ;
n ew p o s = * l o c a t i o n - l ac ;
*pos l n ewpos . x ;
*pos2 = n ew p o s . y ;
/*
Gen e r i c i n tersect i on test
201
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
*/
/*
Test for i n tersecti on of l i ne wi th sphere
*/
t emp = l o c - l i n e - > l o c ;
c ( t emp % t emp ) - n l ;
b - 2 * ( l i n e - > d i r % t em p ) ;
a l i ne - >di r % l i ne - >di r ;
d b*b - 4 . 0*a *c ;
i f ( d <=O )
retu rn ( FALSE ) ;
d = s q r t ( d ) ; * t= ( - b +d ) / ( a + a ) ;
t l= ( - b - d ) I ( a+a ) ;
i f ( * t <=SMA L L && t l <=SMA L L )
retu rn ( FALS E ) ;
i f ( t l > *t )
{
i f ( * t < SMA L L )
*t = t l ;
el se
i f ( t l > SMA L L )
*t = tl ;
r e t u r n ( T RU E ) ;
202
F U N C T I O N S T H AT M AT C H A N O B J E C T: V I R T U A L F U N C T I O N S
/*
Test for i n t e r s ec t i on of l i n e wi th t r i a n g l e
*I
Vector del ta , l oc a t i on ;
fl oat dot . pos l , pos2 , gu [ 3 J , gv [ 3 J ;
i nt i , j , c r o s s i n g_n o ;
d o t = n o rm % l i n e - > d i r ;
i f ( f a b s ( d o t ) < S MA L L )
ret u rn ( FALS E ) ;
pos l = n l ;
p o s 2 = n o rm % l i n e - > l oc ;
* t= ( p o s l - p o s 2 ) / d o t ;
l oc a t i on = l i ne - > l oc + ( l i ne - >di r * *t ) ;
del ta = l oc a t i on - l ac ;
i f ( ( f a b s ( n o rm . x ) > fa b s ( n o rm . y ) ) && ( fa b s ( n o rm . x ) >
f a b s ( n o rm . z ) ) )
gu [OJ -
del ta . y ;
gv [OJ - del ta . z ;
gu [ l ] vect l . y del ta . y ;
gv [ l ] vectl . z del ta . z ;
gu[2J vect2 . y del ta . y ;
gv [2J vect2 . z del ta . z ;
el se
{
i f ( f a b s ( n o rm . y ) > f a b s ( n o rm . z ) )
{
gu[OJ - del ta . x ;
gv [ O J - del ta . z ;
gu [ l ] vectl . x del ta . x ;
gv [ l ] vectl . z del ta . z ;
gu [ 2 J vect2 . x del ta . x ;
gv [ 2 ] vect2 . z del ta . z ;
203
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
el se
{
gu[OJ - del ta . x ;
gv [OJ - del ta . y ;
gu[ l ] vectl . x - del ta . x ;
gv [ l ] vectl . y - del ta . y ;
gu[2] vect2 . x - del ta . x ;
gv [ 2 J vect2 . y - del ta . y ;
c r o s s i n g_n o = O ;
f o r ( i =O ; i <3 ; i ++ )
{
j = (i + 1) % 3;
i f ( ( ( gv [ i ] < 0 ) && ( g v [ j ] >= 0) ) 1 1 ( ( gv [ j ] < 0 ) && ( gv [ i ]
>= 0) ) )
i f ( ( c r o s s i n g_n o % 2 ) == 0)
r e t u r n ( FA L S E ) ;
r e t u r n ( T RU E ) ;
204
F U N C T I O N S T H AT M AT C H A N O B J E C T : V I R T U A L F U N C T I O N S
I*
Te s t f o r i n t e r s e ct i on o f l i n e wi t h pa ra l l e l o g r a m
*/
d o t = n o rm % l i n e - > d i r ;
i f ( fa b s ( d o t ) < S MA L L )
r e t u r n ( FA L S E ) ;
pos l = n l ;
p o s 2 = n o rm % l i n e - > l oc ;
* t= ( p o s l - p o s 2 ) / d o t ;
l oc a t i on = l i n e - > l oc + ( l i n e - >d i r * *t ) ;
del ta = l ocati on - l ac ;
i f ( ( fa b s ( n o rm . x ) > f a b s ( n o rm . y ) ) && ( f a b s ( n o rm . x ) >
f a b s ( n o rm . z ) ) )
gu [O] - del ta . y ;
gv [OJ - del ta . z ;
gu[ l ] vectl . y del ta . y ;
gv [ l ] vect l . z del ta . z ;
gu[2J vect2 . y + vect l . y - del ta . y ;
gv [2J vect2 . z + vectl . z - del ta . z ;
gu[3J vect2 . y - del ta . y ;
gv[3J vect2 . z del ta . z ;
el se
{
i f ( fa b s ( n o rm . y ) >= f a b s ( n o rm . z ) )
{
gu[OJ - del ta . x ;
gv [OJ - del ta . z ;
gu [ l ] vectl . x del ta . x ;
gv [ l ] vectl . z - del ta . z ;
gu[2J vect2 . x + vect l . x del ta . x ;
gv [2J vect2 . z + vect l . z - del ta . z ;
205
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
el se
{
gu[OJ -
del ta . x ;
gv [OJ - del ta . y ;
gu [ l ] vectl . x - del ta . x ;
gv [ l ] vectl . y del ta . y ;
-
c r o s s i n g_n o = O ;
f o r ( i =O ; i <4 ; i ++ )
{
j = (i + 1) % 4;
if ( ( (gv[i J < 0 ) && ( g v [ j ] >= 0) ) I I ( ( gv [ j ] < 0 ) &&
( g v [ i ] >= 0) ))
i f ( ( c r o s s i n g_n o % 2) 0)
r e t u r n ( FA L S E ) ;
206
F U N C T I O N S T H AT M AT C H A N O B J E C T : V I R T U A L F U N C T I O N S
ret u r n ( T RU E ) ;
===;i
I * r.=
Test fo r i n tersect i on of l i ne wi th r i ng
*/
i nt Ri ng : : Co l l i s i onTes t ( Li ne * l i ne , fl oat *t )
{
Vector del ta , l oc a t i on ;
fl oat dot , rad , pos l , po s 2 ;
dot = n o rm % l i n e - > d i r ;
i f ( fa b s ( d o t l < SMA L L )
r e t u r n ( FA L S E ) ;
pos l = n l ;
p o s 2 = n o rm % l i n e - > l oc ;
* t= ( p o s l - p o s 2 ) / d o t :
l oc a t i on = l i n e - > l oc + ( l i n e - >d i r * *t ) ;
del t a = l oc a t i on - l oc ;
rad = sqrt ( del ta % del ta ) ;
i f ( rad< ( vect3 . x ) I I rad> ( vect3 . y ) )
r e t u r n ( FA L S E ) ;
ret u rn ( T RU E ) ;
I*
Te s t f o r i n t e r s e ct i on o f l i n e wi t h q u a d ra t i c
*I
newl i ne . l oc = l i ne - > l oc - l oc ;
i f ( ( v e c t l . x == O l && ( vectl .y 1 ) && ( vectl . z 0))
n ew l i n e . d i r = l i n e - > d i r ;
207
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
el se
{
n ew l i n e . d i r = l i n e - > d i r . Ro t a t e ( c o s l , sinl , cos2 , s i n2 ) ;
n ew l i n e . l a c = n ew l i n e . l o c . Re v_R o t a t e ( c o s l , sinl , cos2 ,
s i n2 ) ;
i f ( y t e r m == 0 )
{
c = - ( c t e rm ) + v e c t 2 . x * n ew l i n e . l o c . x * n ew l i n e . l o c . x +
v e c t 2 . y * n ew l i n e . l o c . y * n ew l i n e . l o c . y +
v e c t 2 . z * n ew l i n e . l o c . z * n ew l i n e . l o c . z :
b = 2 * ( v e c t 2 . x * n ew l i n e . l o c . x * n ew l i n e . d i r . x +
v e c t 2 . y * n ew l i n e . l o c . y * n ew l i n e . d i r . y +
v e c t 2 . z * n ew l i n e . l o c . z * n ew l i ne . d i r . z ) ;
a = vect2 . x * newl i n e . d i r . x * n ew l i n e . d i r . x +
v e c t 2 . y * n ewl i n e . d i r . y * newl i ne . di r . y +
v e c t 2 . z * n ewl i n e . d i r . z * n ew l i n e . d i r . z ;
el se
{
c - ( c t e rm ) + v e c t 2 . x * n e w l i n e . l o c . x * n ew l i n e . l o c . x -
y t e rm * n ew l i n e . l o c . y +
v e c t 2 . z * n ew l i n e . l o c . z * newl i n e . l o c . z :
b = 2 * ( v e c t 2 . x * n ew l i n e . l o c . x * n ewl i n e . d i r . x -
y t e rm * n ew l i n e . d i r . y +
v e c t 2 . z * n ew l i n e . l o c . z * n ewl i n e . d i r . z ) ;
a = v e c t 2 . x * n ew l i n e . d i r . x * n ew l i n e . d i r . x +
v e c t 2 . z * n ew l i n e . d i r . z * n ew l i n e . d i r . z ;
}
d b * b - 4 . 0*a *c ;
i f ( d<O )
return ( FALSE ) :
d = s q rt ( d ) :
* t = ( - b+d ) / ( a + a ) ;
t l = ( - b - d ) / ( a+a ) ;
l o c a t i o n = n ew l i n e . l a c + ( n ewl i n e . d i r * *t ) ;
l oc l = newl i n e . l ac + ( n ewl i n e . d i r * t l ) ;
i f ( ( l o c a t i o n . x < l owe r . x ) I I
( l oc a t i on . x > u p pe r . x ) I I
( l o c a t i o n . y < l owe r . y ) I I
( l oca t i on . y > uppe r . y ) I I
( l o c a t i o n . z < l owe r . z ) I I
208
F U N C T I O N S T H AT M AT C H A N O B J E C T : V I R T U A L F U N C T I O N S
el se
i f ( t 1 > SMA L L )
*t = t 1 ;
r e t u r n ( T RU E ) ;
/*
Te s t f o r i n t e r s e ct i on of l i n e wi t h bound i n g box
*/
* t= l O ;
i f ( f a b s ( l i n e - > d i r . x ) < SMA L L )
{
i f ( ( l owe r . x < l i n e - > l o c . x ) &&
( upper . x > l i ne - > l oc . x l l
{
tmi nx - 3e30 ;
tma xx 3e30 ;
209
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
el se
r e t u r n ( FA L S E ) ;
el se
{
t l = ( l owe r . x - l i n e - > l o c . x ) / l i n e - > d i r . x ;
t2 = ( uppe r . x - l i ne - > l oc . x ) / l i ne - >di r . x ;
tmi nx = M I N ( t l , t2 ) ;
tma xx = MAX ( t l , t2 ) ;
i f ( tm a x x < O )
r e t u r n ( FA L S E ) ;
tmi ny = - 3e30 ;
t m a x y =3 e 3 0 ;
el se
r e t u r n ( FA L S E ) ;
el se
{
t l = ( l owe r . y - l i n e - > l o c . y ) / l i n e - > d i r . y ;
t 2 = ( uppe r . y - l i ne - > l oc . y ) / l i ne - >d i r . y ;
tmi ny = M I N ( t l , t 2 ) ;
t m a xy = M A X ( t l , t 2 ) ;
i f ( t m a xy < O )
r e t u r n ( FA L S E ) ;
tmi nz = - 3e30 ;
t m a x z =3 e 3 0 ;
el se
r e t u r n ( FA L S E ) ;
21 0
F U N C T I O N S T H AT M AT C H A N O B J E C T : V I R T U A L F U N C T I O N S
el se
{
tl = ( l owe r . z - l i n e - > l o c . z ) / l i n e - > d i r . z ;
t2 = ( u ppe r . z - l i ne - > l oc . z ) / l i ne - >d i r . z ;
tmi nz = M I N ( tl , t2 ) ;
tma xz = MA X ( t l , t 2 ) ;
if ( tm a x z < O l
retu rn ( FALS E ) ;
tmi n = M a x ( t m i n x , tm i ny , tm i n z ) ;
tma x = M i n ( t m a x x . t m a xy , t m a x z ) ;
if ( tm a x < tm i n )
retu rn ( FALS E ) ;
r e t u r n ( T RU E ) ;
For the surfaces represented by quadratic equations, things are a little more
complicated. Usually, the quadratic surfaces are oriented around the y axis. If
any other orientation is desired, it is specified in the vector vectl . We first define
a vector newpos, which is the vector from the center (loc) of the object to the
position where we are on the surface. Then check vectl ; if it is a unit vector in
the y direction, the normal vector is the normalized value of a vector which is the
cross product of the vector vect2 (a vector created from the coefficients of x2-, y2,
21 1
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
and z 2 in the quadratic equation) and the vector newpos. If vectl indicates that
the quadric is rotated in some direction other than normal, first rotate the newpos
vector to correspond with the normal orientation of the solid then find the
normal, and reverse rotate it back to get the actual normal for the rotated solid.
The parallelogram is defined by the loc vector, which marks the set of
coordinates for the first comer of the parallelogram, and by two other vectors,
vectl and vect2 , which represent the location of two other corners of the
parallelogram with respect to the first comer. The fourth comer is defined from
the other three and the fact that pairs of sides of the figure are parallel. The
function to find the bounding box computes the second, third, and fourth comers
of the parallelogram in absolute coordinates (not referenced to loc) and then
takes the maximum and minimum values of each of the three coordinates for the
box comers.
The function to find the bounding box for the triangle works exactly the
same as for the parallelogram, except there are only three comers for the figure
instead of four.
The function to find the bounding box for the ring simply adds the outer
radius of the ring to each of the three coordinates to obtain the maximum box
comer and subtracts it from the coordinates to obtain the minimum box comer.
This is not too efficient, since it generates a box which will hold the ring, no
21 2
F U N C T I O N S T H AT M AT C H A N O B J E C T : V I R T U A L F U N C T I O N S
matter which direction it is oriented in. Taking into consideration the actual
orientation of the ring, a much tighter bounding box can be generated. You may
want to attempt this improvement.
For the quadratic, the upper and lower bounds of x, y, and z are specified at
the time when data for the quadratic is entered. These bounds are simply taken
to generate the bounding box.
21 3
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +
the Parallelogram class. For an object of class Ring, vectors vectl and vect2
define the plane of orientation of the ring, with respect to the toe vector, and
these are multiplied by the multiplier vector. The parameter vect3 .x is the inner
radius of the ring and vect3 .y is the outer radius. Both are scaled by multiplying
by the minimum of the three coordinate multipliers. For an object of class
Quadratic, the upper and lower limits are scaled by multiplying by the multiplier
vector. Finally, each Scale_Instance function recursively calls itself to scale any
child functions and if a flag is passed to the function, it also recursively calls
itself to scale any function addressed in the nextobj parameter.
For the Ring, Parallelogram, and Triangle objects, the posl value is the
projection of the vector from the center of the object-oriented coordinate system
to the intersection on one of the vectors that defines the plane of the object. Pos2
is the projection of that same vector upon the other vector that defines the object
plane. Finally, for the Quadratic object, posl and pos2 are simply the x and y
coordinates at the point of intersection in the object-oriented coordinate system.
21 4
CHAPTER 1 1
Here we describe the ray.cpp file, which traces each ray throughout the
picture. Before doing that, however, we need to discuss how to determine where
a ray actually hits an object. Given that we are working backwards, starting at
the observer 's eye and tracing a ray of light back to the screen, we determine at
some point in our computations exactly where on an object 's surface the ray may
be hitting. A function for this action is found in ray.cpp, while the functions that
determine the exact intersection for each class of object are a part of objects.cpp,
which was described in the previous chapter. However, at that time , we
deliberately neglected these functions, choosing to describe the whole operation
here in a separate chapter.
21 5
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
object. The first thing the function does is reinitialize the closest-object address
and the shortest-time variable, if necessary. A value of TRUE in init_flag is the
criterion for reinitialization. The time is initialized to a very large value and the
address of the closest object to a null.
Next, the function starts a loop through every object in the object list. At the
beginning of the loop, we call CollisionTest, which determines whether an
intersection occurs. If there is no intersection, this function returns a FALSE;
otherwise, it returns TRUE and the v ariable t contains the time when the
intersection takes place. (Throughout our consideration of intersections, we use
a parametric method wherein we follow the ray from its beginning along the
direction in which it is oriented until an intersection occurs. Since the ray
direction vector is normalized, multiplying this vector by the time provides the
coordinates of the position we have reached by following the ray.)
After thi s , we increment a stati stics variable that tracks the number of
intersection tests made. Next, if an intersection occurred, we check to make
sure that the time parameter t returned was not too small. This eliminates a
computation problem that occurs when we start a ray at the surface of some
object, intending to follow reflected or refracted light from that point on. If our
computer had absolute precision, we could compute our next intersection
without a problem. When precision is not absolute, we may find that the next
intersection is very close by, where in fact we are just finding the intersection
that we started from all over again. This not only wastes time, it can become an
infinite loop where we keep finding the same intersection and never escape. To
avoid this, we specify a minimum length of the ray before the intersection is
considered valid. This minimum is greater than the possible computation error,
thus eliminating erroneous cases.
21 6
F I N D I N G W H E R E T H E R AY H I TS A N O B J E C T
remove parameter for that object i s active. If so, we compute the point of
intersection and put it in the vector toe and call the function Find_ Color.
Normally, this function determines whether a pattern color must be used to
replace the usual color of the object. In this case, the pattern is actually a part of
the object to be removed. If the function returns to a pattern intersection, we
eliminate this object from consideration, set the address of the object to be
checked to the next object in the list, and start another iteration of the loop. If
the remove parameter was not active or if it was active but we intersected a part
of the object that is not to be removed, we increment the statistical variable that
counts the number of ray intersections with objects that are not bounding boxes.
There are two kinds of rays whose intersections may be investigated with the
Intersect function. One of these is called shadow rays, which go from the object
to a light source. The other kind of ray goes from the observer to the screen to
the object. We distinguish between the two cases by passing the parameter
shadow_flag as TRUE for shadow rays and FALSE for the other types of rays.
For the shadow rays, if t is less than one and the transmission characteristics of
the object are all less than the threshold values, we assign this object to be the
closest object and terminate the function. Otherwise, the light-attenuation factor
increases according to the transmission characteristic for the object.
21 7
F R A C TA L P R O G R A M M I N G A N D R A Y T R A C I N G W I T H C + +
a parametric form. In particular, the equations for the coordinates of the ray are:
(Equation 1 1 - 1 )
Y = y t t + YO (Equation 1 1 -2)
z = z 1 t + zo (Equation 1 1 -3)
The coordinates (xo , YO · zo ) are the coordinates of the starting point of the
ray; the coordinates (x 1 Y I · z 1 ) represent a unit vector in the direction in which
.
the ray is travelling. The parameter t can be taken as time. Thus, at zero time,
the ray is at its origin. As time passes, the ray travels farther along its path. We
are interested in determining the time at which the ray intersects an object; in
particular, if we scan through a list of objects, we would like to know which
object the ray hits first (the intersection for which t is the smallest). We compute
the intersection of the ray with an object by inserting the ray equation into the
equation for the object's surface and solving the resulting equation. For this
computation, we 'll use a coordinate system that is referenced in some convenient
way to the surface of the object we are testing.
(Equation 1 1 -4)
If we substitute the parametric equations of the ray into this equation (using
for the ray the coordinate system whose origin is the center of the sphere) we
obtain the following:
21 8
F I N D I N G W H E R E T H E R AY H I T S A N O B J E C T
(Equation 1 1 -5)
We begin by converting the line origin to the sphere 's coordinate system and
storing the result in the vector temp. We have precomputed the square of the
sphere 's radius; it is stored in nl . Next, we use some vector mathematics to
determine the coefficients of t2 (a in the function), t (b in the function), and the
constant term (c in the function). We then perform a straightforward solution of
the quadratic equation to obtain two roots, one of which is tl and the other
placed in the space addressed by t. (The address of t is passed to the function so
that the final value is available to the calling program rather than only being
local to this function.)
We first check to see whether ti i s both greater than the minimum and
smaller than the contents of t. If it meets these conditions, we replace it as the
contents of t, then check that the contents of t are greater than the minimum.
(This check is necessary in case we didn 't make a switch in the above test.) If
the contents meet the condition, we have a legitimate root and we return TRUE,
with the time corresponding to the closest root stored in the location pointed to
by t. Otherwise, we return a FALSE to indicate that there is no legitimate root
and we don 't really care what time it is.
21 9
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
hyperboloid of two sheets, and ellipsoid. These shapes are shown in Plate 9. All
of these shapes are represented by the following generalized equation:
ax2 + 2 bxy + 2 cxz + 2dxw + ey2 + 2fyz + 2gyw + hz2 + 2 izw + jw2 = 0
(Equation 1 1 -6)
Although the above equation covers every possible kind of quadric curve, it
is too complex to be handled easi l y by this simple ray-tracing program .
Fortunately, most of the common quadric surfaces can be treated by a subset of
this equation, namely:
Shape A B c D E Color
Elliptic cone + -
+ 0 -
Cyan
Cylinder + 0 + + -
Green
Elliptic paraboloid + -
+ 0 -
Purple
Hyperbolic paraboloid +
- -
0 -
Blue
Ellipsoid + + + + -
White
220
F I N D I N G W H E R E T H E R AV H ITS A N O B J ECT
We further impose the restriction that only one y term may occur in the equation
for any given surface (there may be either a y term or a y2 term, but not both). Table
1 1 - 1 l i s t s t h e v ar i o u s s h a p e s and g i v e s the s i g n of e a c h c o e ffi c ient
required for that particular shape, along with the color of the shape in Plate 9.
For the quadric that has y term instead of a y2 term, the corresponding equation
is:
(Equation 1 1 -9)
Look at the function listed in Table 1 1 - 1 . It first converts the origin of the ray to
the quadric-centered coordinate system and places the result in newline.toe. Next, it
checks the orientation of the quadric by looking at the contents of vectl . If this is a
unit vector pointed in the y direction, the orientation of the quadric is standard, so the
ray direction is placed in newline.dir. If the vector in vectl indicates a different
orientation for the quadric, the ray direction is rotated to correspond to the orientation
of the quadric coordinate system. This is done with the function Rotate , using the
sines and cosines for rotation precomputed for the particular quadric. The result, after
rotation, is placed in newline.dir.
The function next uses vector mathematics to generate the coefficients for the
quadratic equation of the intersection. This equation is then solved to obtain two
roots. Next, the location of each root is computed in terms of the quadric coordinate
221
F R A C TA L P R O G R A M M I N G A N D R A V T R A C I N G W I T H C + +
system. The upper and lower limits for each coordinate of the quadric are stored
in terms of its own coordinate system. The location of each intersection is
compared with these limits. If the root falls within the limits, it is an acceptable
intersection; if not, set the time parameter for that root to - 1 to assure that it will
not be considered a valid intersection in the tests that follow, then proceed with
the testing process. As with the sphere, the goal is to find the smaller of the two
intersection times, providing that the time selected must exceed the threshold
parameter SMALL . The function returns TRUE for a valid intersection and
FALSE if there is no valid intersection. If there is a valid intersection, t points to
the time for that intersection.
ax + by + cz + d = 0 (Equation 1 1 - 1 0)
ax()±Jll'.o+cz()_±_d
t = ax + by +cz + d (Equation 1 1 - 1 1 )
1 1 1
222
F I N D I N G W H E R E T H E R AY H I TS A N O B J E C T
equation is the dot product of the normal to the plane and the line direction. As
for the numerator, it is the dot product of the normal to the plane with the
difference between the origin of the plane coordinate system and the origin of
the line. We have already computed the dot product of the normal and the origin
of the plane coordinate system; it is stored in nl , so all that needs to be done is to
subtract from nl the dot product of the normal to the plane and the line origin,
then plug the results into the intersection equation and obtain a value for the time
until intersection.
Next, determine the point on the ray at which it intersects the plane, called
the location , then find the vector delta , which is the vector from the plane
coordinate origin to the point of intersection. The length of this vector is the
square root of the dot product of the vector and itself. We call this length rad. If
rad falls between the values of the inner radius of the ring and the outer radius of
the ring, we have a valid intersection with the ring and return TRUE. Otherwise,
there is no valid intersection and we return FALSE.
We are now ready to determine whether the intersection is actually inside the
parallelogram. This turns out to be a lot more work than determining whether
the intersection with the plane occurs, and more work than doing the same thing
for the ring (which is a rather trivial case). We are going to use the Jordan curve
theorem, which states that if we project a line from the intersection point in an
arbitrary direction and the line has an odd number of intersections with the line
segments that are the sides of the parallelogram, the intersect point is inside the
223
F R A C TA L P R O G R A M M I N G A N D R A Y T R A C I N G W I T H C + +
To make things easier, we first project both the parallelogram and the
intersect point onto a plane defined by two axes of the coordinate system. We
must decide which of the three coordinate axes should be discarded, namely the
one with the largest value for any of the vertices of the parallelogram. This is
the dominant axis. We then perform the projection onto the plane formed by the
other two coordinates by throwing away the values of the dominant coordinate
for each of the parallelogram's vertices, then compute the location of each vertex
in the new system with respect to the parallelogram coordinate system. The first
vertex is always at (0, 0) by definition.
If both gu[i] and gu[j] are positive, then we know that the crossing of the u
axis is also a crossing of the test line, and we therefore increment crossing_ no.
If one of the vertex u coordinates is positive and the other is negative, we must
compute the value of the u coordinate for the intersection of the line segment
with the u axis. If this is positive, we have an intersection with the test line and
therefore increment the number of crossings; if negative, there is no intersection
with the test line, so the number of crossings is unchanged.
224
P l a t e 1 . Newto n ' s M e t h o d f o r x 5 - 1 = 0
P l ate 4. B r i c k Wa l l a n d S p h e re s
P l a t e 5 . C o n e s a n d M i rro red S p h e res
P l a t e 1 0 . T h e Troj a n H o rse
Plate 1 1 . T h e M i rro red Blimp
After completing the loop for all adjacent line segment pairs, we take the
value of crossing_no modulo 2, which gives us a zero for an even number of
crossings and a one for an odd number of crossings. If the number of crossings
is odd, we know that the intersection is within the parallelogram and return
TRUE when the function terminates; if the number of crossings is even, there is
no intersection within the parallelogram so we return FALSE when the function
terminates.
This function will work equally well for any quadrilateral. It is restricted to
parallelograms because of the way we handle the input data, namely inputting
the location of the parallelogram (which is one vertex) and then the location of
two other vertices in relation to the first vertex . The fourth vertex of the
parallelogram is computed internally. You might want to create a new type
called QUADRILATERAL, which allows three arbitrary vertices to be entered
rather than two. After input and the proper initial calculations, the new object is
considered a type PARALLELOGRAM.
225
F R A C TA L PROGRAMMING AND R AY T R A C I N G W I T H C++
If the component exceeds the threshold SMALL, times are calculated for the
ray to hit the upper and lower x limits of the box. If the maximum time is less
than zero, the function termin ate s , reporting no intersection. The same
procedure takes place for the y and z components of the ray. Overall maximum
and minimum times are taken, the maximum time being the minimum of the
three maximum components and the minimum time being the maximum of the
three minimum components. If the overall maximum is less than the overall
minimum, the function terminates and reports no intersection ; otherwise, it
reports that an intersection did occur.
226
CHAPT E R 1 2
We have completed the portions of our ray-tracing program that support the
main task: tracing the path of each ray of light that makes up the picture. This
job is done by the functions that make up the file called ray.cpp. This file is
l isted in Figure 1 2 - 1 . Bear in mind that each l ight source emits rays that
illuminate all of the objects in the picture. The objects, in tum, absorb, reflect, or
refract the light rays, and some return through the viewing screen to the observer.
The rays of light striking the observer 's eyes determine the appearance of the
scene. These rays are a small fraction of the actual light rays in the world. In the
interest of reducing our computer processing to a reasonable amount, rather than
trace each ray of light from the light source, we trace backwards only those rays
that strike the observer's eyes.
We start at the observer's eye and follow a ray to a pixel on the screen. We
then continue to follow the ray in a straight line until it finally hits some object.
Then we follow reflected and refracted rays, as necessary, to their sources and
combine all that information to determine the color that this particular light ray
has when it reaches the eye. In doing ray tracing in this reverse manner, we
avoid the multitude of rays that don't contribute to the light seen by the observer
or to the picture.
227
F R A C TA L PROG RAM MING AND R AY T R A C I N G W I T H C + +
is displayed, giving the user some idea of how far the program has progressed,
since ray tracing takes a considerable amount of time. Then the function
determines the parameter yf, which is the y coordinate for the current scan line in
WORLD coordinates. It enters another for loop, which reiterates for each pixel
on the line. At each iteration, this loop begins by calculating xf, which is the
equivalent value of x in WORLD coordinates for the pixel being processed. The
function then computes the vector giving the direction of the ray ( line->dir)
from the observer to the WORLD coordinates of the current pixel at the screen.
The function Trace_Ray is run to follow the ray for the rest of its path and return
the colors of the ray. These are stored in character arrays of red, green , and blue.
After the inner for loop has been completed, the function Dump_Line is called to
send all of the data for the colors of one line to the output file. When the outer
for loop is finished, Trace Scene terminates and returns to the main program.
/*
ray . cpp = Functi ons r e l a ted to r a y t r a c i n g
B y Rog e r T . Stevens 2 - 1 2 - 90
*I
i nt l evel :
I*
Trace Scene ( ) Ray t r a c i n g of en t i re scene
*I
v o i d T r a c e_S c e n e ( )
i nt x , y ;
c h a r r e d [ m a x _p i x e l ] , g r e e n [ m a x _p i x e l ] , b l u e [ m a x_p i x e l ] ;
228
T R A C I N G T H E R AY
Vector col or ;
Li ne l i ne ;
fl oat xf . yf ;
D u m p_ L i n e ( y , r e d , g r e e n , b l u e l ;
}
I*
T r a c e_ R a y ( ) Ray t r a ce s for a l i ne of d i s p l ay
*I
i n t T r a c e_ R a y ( L i n e * l i n e . V e c t o r * c o l o r . f l o a t m u l t i p l i e r )
(
V e c t o r n e w_p o s i t i o n , n e w_d i r e c t i o n , c l o s e _o b j _ l o c . c l o s e_o b j _n o r m ;
f l o a t S h o r t e s t_t i m e . di v i so r ;
O b j e c t * C l o s e s t _o b j e c t ;
c o l o r_d a t a c o l _d a t a ;
*col or = Vector ( ) ;
l e v e l ++ ;
if ( l evel > 48 )
return ( FALS E ) ;
229
F R A C TA L P R O G R A M M I N G AND R AY T R A C I N G W I T H C++
if ( mu l t i p l i e r < WORLD . t h re s h o l d )
r e t u r n ( FA L S E ) :
C l o s e s t _o b j e c t = l n t e r s e c t ( W O R L D . s t a c k , l i n e , & S h o r t e s t _t i m e , F A L S E .
T RU E , NULL ) ;
i f ( C l o s e s t _o b j e c t ! = N U L L )
{
c l o s e_o b j _ l o c = l i n e - > l o c + ( l i n e - > d i r * S h o r t e s t _t i m e ) :
C l o s e s t _o b j e c t - > F i n d N o r m ( & c l o s e_o b j _n o r m , & c l o s e_o b j _ l o c ) :
i f ( ( c l o s e_o b j _n o r m % l i ne - >d i r ) >O )
c l o s e_o b j _ n o r m = - c l o s e_o b j _n o r m ;
F i n d_C o l o r ( C l o s e s t _o b j e c t , C l o s e s t _o b j e c t - > p a t t e r n ,
& c l o s e_o b j _ l o c , & c o l _d a t a ,
C l o s e s t_o b j e c t - > x m u l t , C l o s e s t _o b j e c t - > y m u l t ) ;
A m b i e n t C o l o r ( c o l o r , & c o l _d a t a , & c l o s e_o b j _n o r m ,
& c l o s e_o b j _ l o c ) :
D i f f u s e C o l o r ( c o l o r , & c o l _d a t a , & c l o s e_o b j _n o r m ,
& c l o s e_o b j _ l o c , l i n e ) ;
T r a n s p a r e n t C o l o r ( c o l o r , & c o l _d a t a , & c l o s e_o b j _n o r m ,
& c l o s e_o b j _ l o c , l i n e , m u l t i p l i e r ) ;
R e f l e c t C o l o r ( c o l o r , & c o l _d a t a , & c l o s e_o b j _n o r m ,
& c l o s e_o b j _ l o c , l i n e , m u l t i p l i e r ) ;
D i t h e r ( c o l o r . & c o l _d a t a ) ;
el se
S ky C o l o r ( l i n e , c o l o r ) ;
i f ( co l o r - > x > C N UM II c o l o r - >y > C N U M II col o r - >z > CNUM )
r e t u r n ( C l o s e s t _o b j e c t ! = N U L L ) ;
I*
I ntersect ( ) F i n d s f i r s t o b j e c t h i t by r a y
*I
230
T R A C I N G T H E R AY
s t a t i c O b j e c t * C l o s e s t_o b j e c t ;
Vector l oc ;
Obj ect * obj ;
s h o r t c o l l i s i on ;
stat i c s hort stop ;
fl oat t ;
obj = C u r rObj ;
i f ( i n i t _f l a g )
{
* S h o r t e s t_t i m e =3 e 3 0 ;
C l o s e s t_o b j e c t = N U L L ;
s t o p= F A L S E ;
W O R L D . b b o x_ i n t e r s e c t s ++ ;
I n t e r s e c t ( o b j - > c h i l d , l i n e , S h o r t e s t_t i me ,
s h a d o w_f l a g , F A L S E , a t t e n ) ;
el se
{
i f ( o bj - > r emo v e ! = NU L L )
{
l oc = l i ne - > l oc + l i ne - >d i r * t ;
i f C F i n d_C o l o r ( o b j , o b j - > r e m o v e , &l oc , NU L L , 1.0,
1. 0) )
obj =obj - > n extobj ;
conti nue ;
W O R L D . r a y _ i n t e r s e c t s ++ ;
i f ( s h a d o w_ f l a g & & t < l l
{
i f ( ( o b j - > c o l _d a t a - > t r a n s . x <
W O R L D . i n t_t h r e s h o l d ) & &
( o b j - > c o l _d a t a - > t r a n s . y <
W O R L D . i n t_t h r e s h o l d ) & &
231
F R A C TA L P R O G R A M M I N G AND R AY T R A C I N G W I T H C++
C l o s e s t_o b j e c t = o b j ;
ret u r n C obj ) :
el se
i f ( atten ! = NU L L )
*a tten = *atten *
( o b j - > c o l _d a t a - > t r a n s *
o b j - > c o l _d a t a - > t r a n s )
( f l o a t ) ( C NUM * CNUM ) ;
o b j =o b j - > n e x t o b j ;
r e t u r n C C l o s e s t_o b j e c t ) ;
I*
*I
v o i d Am b i e n t C o l o r C V e c t o r * c o l o r , c o l o r_d a t a * c o l _d a t a , Vector *
n o rm .
Vector * l ac )
232
T R A C I N G T H E R AY
I*
*I
v o i d D i f f u s e C o l o r ( V e c t o r * c o l o r , c o l o r_d a t a * c o l _d a t a , V e c t o r *
n o rm . V e c t o r * l o c , Li ne * ol i ne )
Li ne l i ne ;
Obj ect * C u r rObj ;
Lamp * l a mp ;
fl oat dot , di stance , t i me , tl , t2 ;
Vector refl ect , attenuate ;
l i ne . l ac = *l oc ;
l amp = W O R L D . l a m p s ;
whi l e ( l a m p ! =N U L L )
(
l i n e . d i r = l a mp - > l o c - *l oc ;
a ttenuate = Vector ( l , 1 , 1 ) ;
C u r r O b j = l n t e r s e c t ( WO R L D . s t a c k , & l i n e , & t i me , T RU E ,
T RU E . & a t t e n u a t e ) ;
W O R L D . t o_ l a m p++ ;
i f C C u r r O b j == N U L L )
(
d i s t a n ce = l i ne . d i r % l i n e . d i r ;
l i ne . di r = - l i ne . di r ;
i f C c o l _d a t a - > d i f f . x > O II c o l _d a t a - > d i f f . y > O II
c o l _d a t a - > d i f f . z > O )
t l = * n o rm % l i n e . d i r ;
i f C t l >O l
(
t 2 = l a mp - >d i s t a n ce* t l / sq r t ( d i s t a n ce ) ;
*col or = *col or + ( ( attenuate *
c o l _d a t a - > d i f f ) * t 2 ) ;
233
F R A C TA L P R O G R A M M I N G AND R AY T R A C I N G W I T H C++
d o t = l i n e . d i r % * n o rm :
re f l e c t = - l i n e . d i r + * n o rm * d o t + * n o rm * d o t :
t l = - ( refl ect % ol i ne - >di r ) :
i f ( tl>0 . 6 )
{
t 2 = p o w ( t l , c o l _d a t a - > s r e f l e c t )
* l amp - >d i s t a n c e / s q r t ( d i s t a n ce ) :
t 2 *= C f l o a t ) c o l _d a t a - > r e f l e c t :
*col or = *col or + a ttenuate * t2 :
l a m p = l a m p - > n e x t_l a m p :
I*
Transpa rentCol o r ( ) T r a c e s r a y t h r o u g h t r a n s p a r e n t me d i um
*I
L i n e n ew l i n e :
Vector col l , refract , di stance , d i s p l a c eme n t , attenua t i on :
f l o a t g l a s s d i s t , c u r r e n t_i n d e x , mul ti pl i e r , si del ;
i n t ma x t r a n s ;
s t a t i c V e c t o r o l d_po s i t i o n ;
c u r r e n t _ i n d e x = c o l _d a t a - > i n d e x / W O R L D . g l o b i n d e x ;
d i s p l a c e me n t = * l a c - o l d_po s i t i o n ;
g l a s s d i s t = s q r t ( d i s p l a c eme n t % d i s p l a c eme n t ) :
el se
I
234
T R A C I N G T H E R AY
c u r r e n t_i n d e x = W O R L D . g l o b i n d e x / c o l _d a t a - > i n d e x ;
o l d_p o s i t i o n = * l o c ;
newl i ne . l oc = *l oc ;
s i d e l = * n o rm % ( - l i ne - >di r ) ;
ref r a ct = - ( * n o rm * s i de l ) - l i ne - >di r ;
refract = refract * ( 1 - c u r r e n t_i n d e x l ;
newl i ne . d i r = l i ne - >d i r + refract ;
n ew l i n e . d i r = _ newl i ne . d i r ;
m a x t r a n s = M a x ( c o l _d a t a - > t r a n s . x , c o l _d a t a - > t r a n s . y ,
c o l _d a t a - > t r a n s . z ) ;
newl i ne . fl ag = ! C l i ne - >fl ag ) ;
mul t i p l i e r = i nmu l t * C fl oat lmaxt ran s / C fl oat l CNUM ;
T r a c e_R a y C & n e w l i n e , & c o l l , m u l t i p l i e r ) ;
W O R L D . r e f l _ t r a n s ++ ;
*col or = *col or + col l ;
i f C l i ne - >fl ag )
!
a t t e n u a t i o n = c o l _d a t a - > d e n s i t y * ( * c o l o r * g l a s s d i s t ) ;
*col or = *col or - a t t e n u a t i on . mi n ( * col o r ) ;
/*
Re f l e c t C o l o r ( ) Traces ray boun ced off obj ect
*I
v o i d R e f l e c t C o l o r C V e c t o r * c o l o r , c o l o r_d a t a * c o l _d a t a . V e c t o r *
n o rm . V e c t o r * l oc , Li ne * l i ne . fl oa t i nmul t l
Vector col l ;
L i 11 e n e w l i n e ;
fl oat mul t i p l i e r . dot ;
i nt maxmi rror ;
235
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +
m a x m i r r o r = M a x ( c o l _d a t a - > m i r r o r . x , c o l _d a t a - > m i r r o r . y ,
c o l _d a t a - > m i r r o r . z ) ;
mul t i pl i e r = i nmul t * ( f l o a t ) ma xm i r r o r / C N U M ;
T r a c e_ R a y ( & n e w l i n e , & c o l l , m u l t i p l i e r ) ;
W O R L D . r e f l _t r a n s ++ ;
*col or = *col or + col l * ( c o l _d a t a - > m i r r o r I ( fl oa t ) CNUM ) ;
I*
S ky C o l o r ( ) C o m p u t e s s ky c o l o r
*/
v o i d S ky C o l o r ( L i n e * l i n e . V e c t o r * c o l o r )
l en g t h l i ne - >d i r % l i ne - >d i r ;
zen i t h l i n e - >d i r . y * l i n e - >d i r . y I l ength ;
hori z ( l i ne - >d i r . x * l i ne - >d i r . x + l i ne - >di r . z * l i ne - >di r . z ) /
l ength ;
* c o l o r = * c o l o r + W O R L D . s k y c o l o r_z e n i t h * z e n i t h +
W O R L D . s k y c o l o r_ h o r i z * h o r i z ;
D i t h e r ( c o l o r , W O R L D . s k y_d i t h e r ) ;
I*
Di ther( ) Col o r d i theri ng funct i ons
*I
#de f i n e M I N C O L 1 0
if ( d i t h e r ==O ) return ;
if ( di ther>O )
!
r= ( ( f l o a t ) r a n d ( ) / 1 6 3 8 3 ) l ;
g=( ( f l oa t ) ra nd ( ) / 1 6383 ) l ;
236
T R A C I N G T H E R AY
b= ( ( f l o a t ) r a n d ( ) / 1 6 3 8 3 ) - l ;
i f C co l o r - >x<M I NCO L )
r=f a b s ( r ) ;
i f C co l o r - >y<M I NCO L )
g=f a b s ( g ) ;
i f C co l o r - > z < M I NCO L )
b=fa b s C b ) ;
* c o l o r= * c o l o r + V e c t o r ( r * d i t h e r , g * d i t h e r , b* d i t h e r ) ;
v o i d D i t h e r ( V e c t o r * c o l o r , c o l o r_d a t a * c o l _d a t a )
fl oat r , g , b ;
i f C c o l _d a t a - > d i t h e r ==O )
return ;
i f C c o l _d a t a - > d i t h e r > O l
{
r= ( ( f l o a t l r a n d C l / 1 6383 ) l ;
g= ( ( f l o a t ) r a n d ( ) / 1 6 3 8 3 ) l ;
b= C C f l o a t ) r a n d ( ) / 1 6 3 8 3 ) l ;
i f C col o r - >x<M I NCO L l
r=f a b s ( r ) ;
if C c o l o r - >y < M I NCO L )
g=f a b s ( g ) ;
if C col o r - >z<M I NCO L )
b= f a b s C b ) ;
* c o l o r = * c o l o r + V e c t o r ( r * c o l _d a t a - > d i t h e r ,
g * c o l _d a t a - > d i t h e r , b * c o l _d a t a - > d i t h e r ) ;
el se
{
r=C C f l oa t l ra n d C l / 1 6383 ) - l ;
i f C C c o l o r - > x+ c o l o r - > y + c o l o r - > z l > C 3 * M I N C O L ) )
r=f a b s ( r ) ;
* c o l o r = * c o l o r + V e c t o r ( r * c o l _d a t a - > d i t h e r ,
r * c o l _d a t a - > d i t h e r ,
r * c o l _d a t a - > d i t h e r ) ;
237
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
/*
D u m p_ L i n e ( ) Sends a l i ne of data to d i s k fi l e
*/
/*
Fi nd Col o r ( ) F i nds t h e col o r of a poi n t on a n obj ect
surface , return i n g e i t h e r pattern or
d e f a u l t c o l o r i n f o rma t i o n
*I
Pattern *patt ;
fl oat x , y , posl , pos2 ;
i n t modx , mody ;
f l o a t r a d i u s_sq , x_ c i r , y_ c i r , xl , x2 , yl , y2 ;
P a t t e r n * l i n e_ s e g m e n t ;
i n t n umbe r = O ;
i f ( p a t t e r n == N U L L )
* c_d a t a = * ( o b j - > c o l _d a t a ) ;
r e t u r n ( FA L S E ) ;
238
T R A C I N G T H E R AV
mody = ( i n t l ( p o s 2 I ( pa t t e r n - >y s i z e l l ;
if ( pos2<0 l
m o d y- ;
x = pos l - ( ( f l o a t ) modx * p a t t e rn - > x s i z e ) ;
y = pos2 - ( ( f l o a t ) mody * p a t t e r n - >y s i z e ) ;
patt = pattern - >chi l d ;
whi l e ( p a t t ! =N U L L )
{
W O R L D . p a t t e r n _m a t c h e s ++ ;
swi t c h ( pa t t - >type )
{
c a s e R E C TA N G L E :
if ( ( x>patt - > sta rtx ) && ( x< pa tt - endx ) &&
( y > p a t t - > s t a r ty ) & & ( y < p a t t - > e n dy ) )
* c_d a t a = p a t t - > c o l _d a t a ;
r e t u r n ( T RU E l ;
brea k ;
c a s e C I RC L E :
x ci r = x patt - > rad i us ;
y_c i r = y patt - > radi us ;
r a d i u s_ s q x c i r * x c i r + y_c i r * y_c i r ;
i f ( r a d i u s_sq <= ( p a tt - > ra d i us*pa tt - > rad i us ) )
{
* c_d a t a = p a t t - > c o l _d a t a ;
return ( TRUE l ;
brea k ;
c a s e P O L Y GO N :
whi l e ( l i n e_ s e g m e n t - > l i n k ! = NU L L )
{
x l = l i n e_segme n t - > s t a r t x - x ;
x 2 = l i n e_ s e g me n t - > l i n k - > s t a r t x x;
y l = l i n e_segme n t - > s t a r ty - y ;
y 2 = l i n e_s egme n t - > l i n k - > s t a r ty y;
i f ( ( x l <=O ) && ( x 2 < =0 ) )
{
i f ( ( y l �O ) && ( y 2�0 ) )
n umbe r++ ;
el se
239
F R A C TA L P R O G R A M M I N G A N D R A Y T R A C I N G W I T H C + +
if ( y l *y 2 < = 0)
i f C xl - ( y l * ( x2 - xl ) / ( y 2 - y l l l > 0 )
n u m b e r++ ;
l i n e_s e g m e n t = l i n e_ s e g m e n t - > l i n k :
i f ( ( n umbe r % 2 ) == 0)
brea k ;
el se
!
* c _d a t a = p a t t - > c o l _d a t a ;
r e t u r n ( T RU E ) :
pa t t patt - >si bl i ng ;
* c_d a t a = * ( o b j - > c o l _d a t a l :
ret u r n ( FALS E ) :
Tracing a Ray
The function Trace_Ray performs the actual ray-tracing operation for a
single ray. It begins by zeroing the vector color, which will contain the color
information for this ray. Next, the function looks at the parameter multiplier,
w h i c h h a s b e e n p a s s e d to i t , and c o m p are s it w i t h the thre s h o l d
WORLD.threshold.
The multiplier parameter is set to one when the Trace_Ray function is first
entered. It is used to multiply the color parameters. It darkens the colors during
repeated reflections and transmiss ions through a transparent medium. The
parameter decreases with each reflection or refraction, thereby darkening the
colors. When the parameter is reduced below the threshold, any further ray
contributions are unimportant, so the ray-tracing function ceases. Obviously,
this never happens when the Trace _Ray function is called by Trace_Scene.
However, Trace_Ray is also called recursively by some of the functions that are
240
T R A C I N G T H E R AY
The Trace_Ray function then calls the function Find_Color. This function,
described below, determines whether a pattern is superimposed upon the object
surface. If there is, and our intersection occurs at a point that should be the
pattern color rather than the native color of the object, the function changes the
color accordingly. The functions AmbientColor, DiffuseColor, TransparentColor,
and ReflectColor are then called to trace reflected and refracted rays and add in
their color contributions. Finally, we call the function Dither, which dithers the
color information if necessary. If no intersection with an object is found, the
function calls the function SkyColor and colors the pixel with the appropriate
color for the sky. Finally, the function verifies that none of the color components
exceeds the maximum allowable color number. If so, the color information for
that pixel is scaled within the color limits. The function then terminates.
WORLD stores two colors for the background (or sky), one at the horizon
and one at the zenith (directly overhead). The SkyColor function determines
241
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
from these what color to use for the sky-colored pixel. It squares the length of
the ray being traced (from the observer to the screen), then uses this to normalize
the components of the ray direction in the y and x-z plane directions. The color
for the zenith is multiplied by the square of the y component, horizon color is
multiplied by the square of the x-z component, and the result is added to give the
final background color. Try a few examples to satisfy yourself that if you use the
same color for both horizon and zenith, this process will result in that same
color, regardless of the direction of the normalized direction vector.
The function finally calls Dither with the color vector address and the
World.sky_dither value as parameters. Dither begins with three random numbers
between - 1 and + 1 . For each component of the sky color, if the component is
less than a minimum value of 1 0, the random number is made positive. Finally,
each random number is multiplied by the dither parameter and the results are
added to the three color components.
Ambient Color
Suppose we have a collision between the light ray and an object. At the
moment, our color vector is still set to zero. The first thing we do is call the
function AmbientColor. The ambient color is the general light illuminating the
scene; it does not come from any of the light sources. We multiply this light
color by the diffuse color, which is the natural color of the object, and the result
is scaled to the number of permitted color shades (64). The product is added to
the current color vector value of the pixel.
242
T R A C I N G T H E R AY
243
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
This procedure for diffuse and specular color reflection repeats for each light
source in the list. When all light sources are exhausted, the loop terminates and
the function ends.
The function then creates a new line, with its beginning at the point of
intersection. The angle of refraction determines the direction of the line as it
c o n t i n u e s from t h e p o i n t of i n t e rs e c t i on . B a s e d on the transparency
characteristics of the trans vector of the object, a multiplier is computed. The
flag for this new line is the opposite of the current flag. In other words, if the
flag indicates that we are outside a transparent object, we are inside after the
intersection, and vice versa. Trace_Ray is called recursively to trace the new ray.
The returned color information is added to the color vector. Finally, if we have
been travelling inside the transparent object, a new attenuation vector is
calculated as the product of the distance travelled within the transparent object
and the density vector, which is part of the object information.
Reflections
The function ReflectColor determines the reflections on a mirrored surface
and begins by determining whether any of the coefficients of the object 's mirror
vector are above the preset threshold. If none are, there is no reflection and the
244
T R A C I N G T H E R AY
function returns without further action. If there is some reflection, a new line is
set up with its origin at the point of intersection. We then calculate the direction
at which the ray we are tracing reflects off the surface. A multiplier is computed
based upon the maximum mirror coeffic ient of the object. The function
Trace_Ray then recursively traces this new ray. The result, multiplied by the
mirror vector, is added to the color vector.
245
CHAPTER 1 3
We now have all of the files necessary for ray tracing. (An additional file for
fractals is in Chapter 1 5 and is included in the make files discussed in this
chapter, but is not necessary for ordinary scene rendering.) Tying these files
together could be a complicated job but is simplified by u s ing the make
capability that is available in many languages including most versions of C, and
in Zortech C++ and Turbo C++. There is, however, a difference between them.
The advantage of the make capability is that it tracks the date and time when
each file was created. (You need to make sure your system clock is working and
is set to the correct time.) When you use make, the program automatically checks
each object file that you link together to make up the finished program to assure
that it is the latest version. If so, it is linked without recompiling. If you have
performed editing since an object file was last generated, it will be recompiled.
Thus, only the minimum amount of recompiling is necessary. You don 't need to
recompile everything to be safe. If you really want to recompile a file, you first
type :
t o u c h f i l e n a me
where filename is the name of the file you 're interested in recompiling, and a
flag is set that forces recompilation of this file when you next run make. With
our ray-tracing program, render.hpp is a header file associated with every other
file, so if you use touch on it, every file will be recompiled when make is run.
247
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
There are two ways to run make. The first method applies if you intend to
use make on only one set of program data. You may then store all of the data
required by the make facility in a file called makefile, then invoke the capability
by typing :
ma ke
The program automatical ly searches out the makefile and uses the data to
perform its functions. Alternately, if you have several programs that require the
m a k e c a p ab i l i t y , y o u c an g i v e the data fi l e a d i ffe rent n a m e , s u c h as
zraymake.mak. The make capability is then invoked by typing:
ma ke - fz r ayma ke . ma k
where the name following the -f is that of the file where your make data is stored.
The first line of the file begins by specifying the name of the executable file
to be created, followed by the name of each object file to make up the program.
This data must not exceed 1 27 characters because of DOS limitations. Then
there 's the statement to define l inking of the program . It must be indented;
otherwise, make may think it is part of the previous data. It too is limited to 1 27
characters and begins by blink followed by a space, followed by the names of all
the object files to be linked by + signs. At the end of the line is the option lnoi,
which tells the linker to be case-sensitive. Each object file created by the make
capability is followed by two lines of code. At the beginning of the first line for
each object file is the name of the object file followed by a colon. The .c or .cpp
file is compiled to produce the object file followed by the names of all other
source files. The second line begins with ztc, invoking the compiler, followed by
248
P U TT I N G I T A L L TOG E T H E R W I T H T H E M A K E C A PA B I L I T Y
any desired options and the name of the source file to be compiled.
b l i n k r e n d e r+ v m a t h + i n p u t + f r a c t a l + o b j e c t s + r a y / n o i
Let 's take a look at the options used in compiling programs. The -c option is
needed for each compile statement, since it tells the compiler to compile only
and not link. This is necessary because we will do the linking with a separate
link command l ine once a l l of the neces s ary updated object modu les are
identified by the make facility. The -! option tells the compiler to generate in
line instructions for the math coprocessor. If you have a math coprocessor, you
need this option for every compile; if not, it should not be included.
The -ml option indicates that the large memory model should be used. This
is necessary for all modules for this program because it is large and complex and
249
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
uses a lot of memory for data storage. The -o option tells the compiler to use the
global optimizer to optimize the code. Ideally, this should be used for every
m o d u l e to o b t a i n o p t i m u m c ode fo r the fi n a l program . H o w e v er, the
complexities of some files caused the global optimizer to become confused and,
for example, reject a simple if statement as illegal. If you use the optimizer
option only for those files shown, you ' l l be safe. You may want to try it on
additional files one at a time, but you do so at your own peril.
Finally, the -w- option turns off warnings from the compiler. S ince the
compiler tends to generate a warning every time it encounters an external
variable, there can be quite a stack of warning messages, most of them useless.
If you get into trouble trying to compile, you may want to remove this option
and display the warning messages for your review.
Look at the instructions for compiling the fractal file. Although this file is
not too big, it has some complicated multiple recursion in it. As a result, if you
use the normal Zortech ztc compile command, you are apt to get an out of
memory message. Zortech has a more complex but slower compiler that must be
invoked in two steps, as shown. This compiler is able to handle the fractal
module without difficulty.
Once you run the make facility, you should have a fully compiled program
that will perform whatever ray tracing you desire.
There are some differences that have to be considered for Turbo C++. First,
where Zortech C++ uses the include file stream .hpp, Turbo C++ uses the file
250
P UTTI NG I T A L L T O G E T H E R W I T H T H E M A K E C A PA B I L I T Y
iostream .h, so you will have to go through the files and change this statement
wherever it occurs-hopefully, once, in the render.hpp file. If there were a few
other places I missed, you will find them quickly enough when you try to
compile.) Figure 1 3-2 lists the makefile for Turbo C++. First, look at the linking
command, and note that while the Zortech command line linker automatically
finds any library files needed and links them in, the Turbo C++ command line
linker does not. Instead, you have to specify several of these library files on the
linker command line. The Turbo C++ command line linker doesn 't recognize
any instructions for the location of include or library files in the integrated
environment, so you have to specify the full path for each library file if it is not
in the same directory with the rest of your program. When you installed Turbo
C++, your linker and compiler were put in the sub-directory bin , whereas the
library files were put into the subdirectory lib. Unfortunately, if you include a
full path command for each library file, such as:
you are likely to find that when you attempt to link, you get an error message
like :
Note that the compile statements use a compiler tee instead of the zte
compiler used by Zortech. All of the compile options used are the same, except
for the additional ones Y and Yo used by Turbo C++. Now we get to the good
and bad aspects of Turbo C++. The Zortech C++ compiler is apparently much
more e fficient than the Turbo C++ compiler, since the ray tracing program
compiles to a little over l OOk bytes with Zortech while Turbo C++ requires 1 22k
251
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
bytes. Unfortunately, we need all that extra memory consumed by Turbo C++
for our data, so the program runs out of memory. That's the bad side. The good
side is that Turbo C++ has a sophisticated overlay capability that reduces the
amount of memory required by the program at any given time. Note the use of
lo in the link command which separates the program modules that remain
resident at all times from those that may be overlaid. In addition, in the compile
section, -Y is used with each module that is to remain resident and -Yo with each
module that may be overlaid. Once the program is compiled and linked with
these overlay options specified, it is capable of tracing the sample pictures
without difficulty.
rende r . exe : rende r . obj vma t h . obj i n put . obj obj ects . obj
f r a c ta l . obj ray . obj
252
P U TTI N G I T A L L TO G E T H E R W I T H T H E M A K E C A PA B I L I T Y
253
CHAPTER 1 4
The result of using the ray-tracing program is a disk file which contains a lot
more detailed color information than we can ever use with the VGA monitor on
a personal computer. Because of the large amount of information in the file, it
takes a lot of space; in fact, we can only get one of these files onto a standard
360k floppy disk. This chapter looks at how we convert from the file generated
by the ray tracer to the best possible VGA display, how that display is stored in a
reasonably sized disk file, and how to restore that disk file to a screen display. If
you ' re lucky enough to have a color printer, you m ay want to make some
printouts of these displays. There is a program commercially available called
Pizazz Plus, which can capture any display screens you will generate and print to
many different color printers with reasonably good quality.
255
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
number of colors for scenes in this book ranges from 350 to 3500, even when
realistic shading, reflections, and shadows are included. This is a much greater
number than the 256 handled by the VGA, but fortunately many of these colors
are used in shading a surface and are thus very close to each other, so that the
number of colors can be reduced to 256 without major degradation of the picture.
Of course, we could have a prettier, more realistic picture if we had more colors
to work with, but by using a few tricks we can make the VGA display look
pretty good.
256
D I S P L AY I N G A N D S AV I N G S C R E E N S
/*
col p roc P rog ram to P roce s s C o l o r D a t a f o r VGA
*/
v o i d g o t o xy ( i n t x , i nt y ) ;
v o i d pl ot ( i nt x , i nt y , i nt col or ) ;
v o i d s etMode ( i n t mode ) :
v o i d s e t V GAp a l e t t e ( u n s i g n e d c h a r * b u f f e r ) :
v o i d s o rt ( u n s i gned i n t s t a rt . un s i gned i n t end ) :
ty p e d e f s t r u c t
{
c h a r Red :
cha r G reen ;
c h a r B l ue :
RGB ;
e n um { r e d =O , g r n = l . b l u=2 };
u n i on REGS reg ;
s t ruct S REGS i n reg :
u n s i g n e d i n t C o l _A r r a y [ 2 5 6 ] [ 2 ] ;
u n s i g n e d c h a r P a l _A r r a y [ 2 5 6 J [ 3 J :
RGB Co l o r , C ol o r 2 ;
i n t i , k , x res . y re s . l a s t_c o l o r , s c a n l i n e , r l , r 2 , g l , g 2 , b l , b 2 :
u n s i g n e d c h a r r [ MA X X R E S J , g [ MA X X R E S ] , b [ MA X X R E S J ;
F I L E * f i l e_ l ;
u n s i g n e d c h a r f a r * c o l o r_ h i s t ;
l o n g i n t c o l o r_n o ;
unsi gned i nt j :
u n s i g n e d c h a r f re q u e n cy [ 8 1 9 2 J ;
un s i gned i nt hues [8192 J :
v o i d ma i n ( a rgc , a rg v )
257
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +
i nt a rgc :
char *argv [ J :
i nt i ndex :
i nt rgbi ndex :
i nt yl :
u n s i g n e d i n t d l , t em p_d ;
unsi gned cha r d2 :
s etMode ( 3 ) :
i f ( a rgc ! = 2 )
{
p r i n t f ( " V GA C o l o r P r o c e s s o r by R o g e r S t e v e n s \ n " ) ;
p r i n t f ( " U s a g e : % s f i l e n a m e . RAW \ n " , a r g v [ O J ) :
exi t ( l ) ;
i f ( ( f i l e_ l = f o p e n ( a r g v [ l ] , " r b " ) ) == N U L L )
{
p r i n t f ( "Cou l dn ' t open fi l e %s \ n " , a rg v [ l ] ) :
exi t ( l ) ;
c o l o r_h i s t = f a r m a l l o c ( 3 2 7 6 8 ) :
f o r ( i =O : i < 2 5 6 : i ++ )
{
P a l _A r r a y [ i J [ r e d J O;
P a l _A r r a y [ i J [ g r n J 0:
P a l _A r r a y [ i J [ b l u J 0:
)
f o r ( j =O : j < 3 2 7 6 8 ; j ++ )
c o l o r_h i s t [ j J = 0 :
xres = y res = 0 :
f r e a d ( & x r e s . s i z e o f ( i n t ) . 1 . f i l e_l ) :
f r e a d ( &y r e s , s i z e o f ( i n t ) , l , f i l e_l ) :
p r i n t f ( " V GA c o l o r p o s t - p r o c e s s o r by Ro g e r S t e v e n s \ n " ) :
p r i n t f ( " I m a g e f i l e r e s o l u t i o n i s : % d by % d \ n " , x r e s , y r e s ) :
yl = 0 :
pri ntf( "Col l ecti ng col or data ]") :
w h i l e ( ! f e o f ( f i l e_l ) )
{
258
D I S P L AY I N G A N D S AV I N G S C R E E N S
f r e a d ( & s c a n l i n e , s i z e o f ( i n t ) , l , f i l e_l ) :
i f ( s c a n l i n e >= y r e s )
{
p r i n t f ( " F a u l ty data fi l e . \ n " ) :
ex i t ( l ) ;
g o t o xy ( 2 4 , 3 ) :
p r i n t f ( "%d " , scanl i ne ) ;
f r e a d ( & r [ O J , s i z e o f ( c h a r ) , x r e s . f i l e_l ) ;
f r e a d ( & g [ O J . s i z e o f ( c h a r ) , x r e s , f i l e_l ) ;
f r e a d ( & b [ O J . s i z e o f ( c h a r ) , x r e s , f i l e_l ) ;
f o r ( i n d e x=O ; i n d e x < x r e s ; i n d e x++ )
{
C o l o r . Re d ( r [ i ndexJ & Ox3e ) ;
Col or . Green ( g [ i ndex J & Ox3 e ) ;
Col or . Bl ue ( b [ i ndex ] & Ox3e ) ;
c o l o r_n o = ( C o l o r . R e d > > 1 ) I ( C o l o r . G r e e n
<< 4 ) I ( Col o r . Bl ue << 9 ) ;
i f ( c o l o r_h i s t [ c o l o r_n o ] < 2 5 5 )
c o l o r_h i s t [ c o l o r_n o ] ++ ;
y l += l ;
l a st col or = - 1 ;
f o r ( j =O ; j < 3 2 7 6 8 ; j ++ )
{
i f ( c o l o r_h i s t [ j ] > 0 )
{
l a s t_c o l o r++ ;
h u e s [ l a s t_c o l o r ] j;
f r e q u e n cy [ l a s t_c o l o r ] c o l o r_h i s t [ j ] :
259
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
g o t oxy ( 2 5 . 7 ) ;
pri ntf( "%5d" . i ) ;
dl = 32768 ;
f o r ( j =O ; j < 2 5 6 ; j ++ )
{
C o l o r . Red = ( h ue s [ i ] < < 1 ) & Ox3 E ;
Col o r . Green = ( h ue s [ i ] >> 4 ) & Ox3 E ;
C o l o r . B l ue = ( h ue s [ i J >> 9 ) & Ox3 E ;
C o l o r 2 . Red = ( h u e s [ j ] < < 1 ) & Ox3 E ;
C o l o r 2 . Green = ( h ues [ j ] >> 4 ) & Ox3 E ;
Col o r 2 . B l ue = ( h ues [ j ] >> 9 ) & Ox3 E ;
t e m p_d = ( C o l o r . R e d - C o l o r 2 . R e d ) * ( C o l o r . Re d -
C o l o r 2 . Re d ) + ( C o l o r . G r e e n -
Col or2 . Green ) * ( Col o r . Green -
Col o r 2 . G reen ) +
( Co l o r . B l ue - C o l o r2 . B l u e ) * ( Co l o r . B l ue -
Col or2 . Bl ue ) ;
i f ( t em p_d < d l )
{
dl t e m p_d ;
d2 j;
f r e q u e n cy [ i ] = d 2 ;
f o r ( j =O ; j < 2 5 6 ; j ++ )
{
C o l o r . Red = ( h u e s [ j ] < < 1 ) & Ox3 E ;
C o l o r . G reen = ( h ue s [ j ] >> 4 ) & Ox3 E ;
C o l o r . B l ue = ( h ues [ j ] >> 9 ) & Ox3 E ;
P a l _A r r a y [ j ] [ O J C o l o r . Red ;
P a l _A r r a y [ j ] [ l ] Col o r . G reen ;
P a l _A r r a y [ j ] [ 2 ] Col or . Bl ue ;
setMode ( Ox l 3 ) ;
s e t V G A p a l e t t e ( & P a l _A r r a y [ O J [ O J ) ;
f o r ( j =O ; j < 3 2 7 6 8 ; j ++ )
c o l o r_h i s t [ j ] = O ;
f o r ( j =O ; j < = l a s t_c o l o r ; j ++ )
c o l o r_h i s t [ h u e s [ j J J = f r e q u e n cy [ j J ;
r e w i n d ( f i l e_ l ) ;
yl = O ;
260
D I S P L AY I N G A N D S AV I N G S C R E E N S
f r e a d ( & x r e s . s i z e o f ( i n t ) , l , f i l e_l ) :
f r e a d ( &y r e s , s i z e o f ( i n t ) , l , f i l e_l ) :
w h i l e ( ! f e o f ( f i l e_l ) )
{
f r e a d ( & s c a n l i n e , s i z e o f ( i n t ) , l , f i l e_l ) :
i f ( s c a n l i n e >= y r e s )
{
p r i n t f ( " F a u l ty d a t a f i l e . \ n " ) :
ex i t ( l ) ;
f r e a d ( & r [ O J , s i z e o f ( c h a r ) , x r e s , f i l e_l ) :
f r e a d ( & g [ O J , s i z e o f ( c h a r ) , x r e s , f i l e_l ) :
f r e a d ( & b [ O J , s i z e o f ( c h a r ) , x r e s . f i l e_l ) ;
f o r ( i n d e x=O : i n d e x < x r e s : i n d e x++ )
{
C o l o r . Re d ( r [ i ndexJ & Ox3e ) :
Col o r . G reen ( g [ i ndex ] & Ox3e ) ;
Col or . Bl ue ( b [ i ndex ] & Ox3e ) :
c o l o r_n o = ( C o l o r . Re d > > 1 ) I ( C o l o r . G r e e n
<< 4 ) I ( Col o r . Bl ue << 9 ) :
p l o t ( i n d e x , y l , c o l o r_h i s t [ c o l o r_n o J ) ;
y l += 1 :
getc h ( ) ;
setMode ( 3 ) :
f c l o s e ( f i l e_l ) ;
/*
setMode ( ) Sets V i deo Mode
I*
v o i d s etMode ( i n t mode )
{
reg . h . a h 0:=
reg . h . a l = mode :
i nt86 ( Ox l O , & reg , & reg ) ;
261
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
*/
pl ot ( ) F u n c t i o n t o p l o t p o i n t t o V GA 2 5 6 C o l o r S c r e e n
*/
voi d pl ot ( i n t x , i nt y , i nt col o r )
(
uns i gned i nt offset ;
c h a r fa r * a d d r e s s ;
offset = 320 * y + x ;
a d d r e s s = ( c h a r fa r * ) ( OxAOOOOOOOL + offset ) ;
*address = col or ;
/*
setVGApa l ette ( ) Funct i on to set a l l 256 col o r reg i s t e r s
*/
/*
sort ( ) Q u i c k s o r t t o s o r t c o l o r s by f r e q u e n cy
*/
i f ( st a r t < ( end - 1 ) )
(
262
D I S P L AY I N G A N D S AV I N G S C R E E N S
i = sta rt ;
j = end ;
pi vot ( f r e q u e n cy [ i ] + f r e q u e n cy [ j ] +
f r e q u e n cy [ ( i +j ) / 2 ] ) / 3 ;
do
{
w h i l e ( f r e q u e n cy [ i ] > p i v o t )
i ++ ;
w h i l e ( f r e q u e n cy [ j ] < p i v o t )
j-;
if (i < j)
{
t e m p = f r eq u e n cy [ i ] ;
f r e q u e n cy [ i ] = f r e q u e n cy [ j ] ;
f r e q u e n cy [ j ] = t e m p ;
temp2 = hues [ i ] ;
h u e s [ i ++ J = h u e s [ j ] ;
h u e s [ j -J = t e m p 2 ;
wh i l e ( i < j ) ;
i f ( j < end )
{
s o rt ( sta rt , j ) ;
sort ( j+l , end ) ;
i f ( f r e q u e n cy [ e n d J > f r e q u e n cy [ s t a r t J )
{
t e m p = f r e q u e n cy [ s t a r t ] ;
f r e q u e n cy [ s t a r t ] = f r e q u e n cy [ e n d ] ;
f r e q u e n cy [ e n d ] = temp ;
temp2 = hues [ s ta rt J ;
h ues [ s t a rt ] = hues [ end J ;
h u e s [ e n d J = t em p 2 ;
)
v o i d g o t o xy ( i n t x , i n t y )
{
reg . h . a h = 2 ;
reg . h . bh = O ;
reg . h . d h = y - 1 ;
263
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +
reg . h . dl = x-1 :
i n t86 ( 0x l 0 , & reg , & reg ) ;
Now, let's look at the program in detail . First, I should point out that to
make the program independent of graphics routines that differ from one version
of C to another, I have included functions that perform the graphics tasks needed
to create the display. There are three and they are all fairly simple.
The function setMode makes use of the ROM BIOS video services to set the
display mode . The function properly sets up the register contents and then
generates the interrupt that calls the proper ROM BIOS service. We are really
only interested in two display modes, mode 3 which is the normal text mode, and
mode 1 9 ( 1 3H) which is the VGA graphics mode.
The second function is plot, which plots a pixel at the appropriate point on
the display. The VGA memory board contains memory for four color planes. In
many of the modes, color is determined by sending a single bit to the same
address in each of the four memory planes. This requires some complicated
manipulation of registers, since the memory planes cannot be addressed directly.
Fortunately for mode 1 9, a full byte is used to describe the color of each pixel
and each byte is at an adjacent memory address so that all we have to do is
compute the address at which the pixel resides in memory and send the byte to it.
(Actually, inside the VGA card, all sorts of funny things go on, with the bytes
being rotated through the four memory planes so that any one memory plane
only stores every fourth byte with the intervening memory locations being
empty. This is totally invisible to us. From the outside world, it looks as if we
were simply storing data in an ordinary memory array.)
The third function is setVGApalette. The VGA has 256 color registers that
store the color shades to be used for the display. The ROM BIOS video service
that is used in this function takes data from a buffer and stores it in all of these
264
D I S P L AY I N G A N D S AV I N G S C R E E N S
The final function used by this program is sort. This is a standard Quicksort
algorithm. Since it is described in many computer books including my book,
Graphics Programming in C, I won 't go into any detail. Suffice to say that it
sorts the contents of the array in which the frequency of occurrence of each color
is accumulated. It puts the indexes of this array (which represent the different
shades of color) into a new array in the order of the number of occurrences,
beginning with the most frequently occurring color.
The program starts by checking whether it was called with a file name
specified. If not, a message is printed out (with the display in text mode), which
indicates that a file name must be included to run the program. The program
then exits. If a file name was specified, an attempt is made to open the specified
file. If the file cannot be opened, the program prints out a message to this effect
and then exits. If the file is successfully opened, the program next allocates
memory for the array color_hist , which will be used to store the occurrences of
colors. The array of information for the color registers, Pal_Array , and the
color_hist array are then initialized to all zeroes. The first four bytes of the file,
which are the integer values for xres , the number of display pixels in the x
direction, and yres, the number of display pixels in the y direction, are then read.
The heading and the resolution data are then displayed on the screen. Next, the
program displays the line "Collecting color data [ ]" with a space for the line
number. The program then starts a while loop which will continue until the end
of the file is encountered.
The loop begins by reading the number of the scan line from the file. If it is
greater than the maximum line that was defined, there i s an error and the
265
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
program displays, "Faulty data file" and exits. If the scan line is acceptable, it is
displayed at the proper place on the screen. Next, the program reads first a line
of red data, then a line of green data, and then a line of blue data from the file.
These are stored in r, g, and b arrays. A for loop takes the red, green, and blue
v a l u e s for e a c h p i x e l ( n o t i n c l u d i n g the l e a s t s i g n i fi c an t b i t , thereby
accomplishing the division by two) then shifts and combines them into a unique
color number. This value is used as an index for the color_hist array and the
contents of that address is incremented.
Once the loop is complete, the program runs another for loop which scans
the color_hist array and increments a variable, last_color, each time a color
occurs at least once. The index for this color is placed in an array hues and the
frequency with which it occurs in an array frequency. Each of these arrays is of
size 8 1 92, assuming that there will be no more than 8 1 92 different colors in any
particular picture. If there are more than 8 1 92 colors, the program will probably
bomb. The next thing that happens is that a line is displayed telling how many
colors were in the picture, so if there are too many colors, you may get to see this
before anything goes haywire. Assuming there weren 't too many colors, the
program displays "Starting sort," then runs the sort function, and then displays
"Sort completed."
266
D I S P L AY I N G A N D S AV I N G S C R E E N S
with its color number. When the current color has been checked against all 256
initial colors, it is assigned the number of the color for which the sum of the
squares of the differences was smallest.
When the two loops are complete, all of the colors beyond the first 256 have
been assigned color numbers that correspond to the color for which the sum of
the squares of the differences was smallest. The graphics mode is set for the 256
color display and setVGApalette is run to set the VGA color values for the first
256 colors. Then we refill the color_ hist array with the number of the color
associated with each index value or with a zero if that index has no color and we
rewind the file. The file is then read all over again, beginning by reading the
xres and yres values and then entering a while loop that reiterates until the end of
file is encountered. For each iteration, the scan line number is read first followed
by the red, green, and blue data for a complete line. Then a for loop is run for
each pixel of the line. The color data for that pixel is combined into an index
number in the same manner as was done above. The color number for that index
is taken from the color_hist array and the pixel is plotted in that color at the
appropriate point on the screen. When both loops are complete, the full picture
is being displayed. The program waits for a character to be entered at the
keyboard. When this occurs, the screen is reset to the text mode, the file is
closed, and the program terminates.
Here we are going to give a program for producing a high resolution display
from ray tracing data using the Vega VGA 1 024i display card. This card supports
a number of extended high-resolution modes. The one we are going to use is
800 by 600 pixels with 256 colors. First, go into a ray-tracing data file and
267
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
change the XRES and YRES parameters to 800 and 600, respectively. Then run
render with this file to generate a new raw data file at the improved resolution.
(This is going to take longer than for a 320 by 200 display, since there are now
480,000 elements to process instead of 64,000.)
Run the program l isted in Figure 1 4-2, to convert the raw data file to a
display. The first thing to observe is that this program looks very similar to the
colproc program given in Figure 1 4- 1 . In fact, everything is the same except the
way the graphics mode is set up and the way to write to the screen. First, look at
the setMode function, which is used to set the display mode. Note that this
function now begins with an if statement. For modes less than 32H, the function
is just the same as the one used with the regular display modes. However, for the
extended graphics functions (modes beyond 32H), a different ROM BIOS call is
used, placing the mode in a different register, and sending an initializing output
to one of the VGA registers. Although this function uses the ROM BIOS, this
part of the ROM BIOS is contained in the VGA board, so that for a different
make of VGA board, the results could be completely different.
Let's look at the plot function. Before, we used the x and y pixel values to
create an offset which was added to the basic video memory address to create the
address where the pixel color was sent. Now we begin by creating the offset
(which can be larger because we now have 640 pixels in a line instead of 320).
However, this larger video memory is banked to be able to handle more memory
within the memory space allotted to the VGA. Thus, if the offset is greater than
65 5 3 6 (64k) , we must divide it by 655 3 6 to obtain the bank number. The
remainder is the new value of offset. The function keeps a record of the number
of the last active bank in global memory. If the desired bank is different from the
currently active bank, the function selects the new bank. The new bank number
is stored in active_bank. The function then provides outputs to several of the
VGA registers to select this new bank.
The way this is done is not very straightforward, but should be self-evident
from the program listing. Once the correct memory bank has been selected, the
268
D I S P L AY I N G A N D S AV I N G S C R E E N S
function creates a memory address from the offset and the base memory address,
and sends the pixel color there. (If the correct bank is already selected, the
function can skip all that bank selection stuff and simply create the address and
send the pixel. B asically, these two functions are all that need to be changed to
use the extended 640 pixel by 480 row by 256 color mode.
/*
800proc P r o g r a m t o P r o c e s s 8 0 0 x 6 0 0 C o l o r D a t a f o r V GA
*/
voi d g o t o xy ( i n t x , i n t y ) ;
voi d pl ot ( i nt x , i nt y , i nt col or ) ;
voi d s e tMode ( i n t mode ) ;
voi d s e t V GA p a l e t t e ( u n s i g n e d c h a r * b u f f e r ) ;
voi d s o rt ( u n s i gned i nt sta rt . u n s i gned i n t end ) ;
typede f s t ruct
{
c h a r Red ;
cha r Green ;
cha r B l ue ;
RGB ;
e n u m { r e d =O , g r n = l , b l u = 2 } ;
#d e f i n e MAX X RE S 800 I * s e t m a x h o r i z c o o r d e x p e c t ed * /
u n s i g n e d i n t C o l _A r r a y [ 2 5 6 J [ 2 J ;
u n s i g n e d c h a r P a l _A r r a y [ 2 5 6 ] [ 3 J ;
RGB Col o r , C o l o r 2 ;
i n t i , k , x res . y res .
l a s t_c o l o r . s c a n l i n e . r l , r 2 , g l , g 2 , b l , b 2 , b a n k=O , a c t i v e_b a n k=O ;
269
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +
u n s i g n e d c h a r r [ MA X X R E S J , g [ MA X X R E S J , b [ MA X X R E S J ;
F I L E * f i l e_ l ;
u n s i g n e d c h a r f a r * c o l o r_h i s t ;
l o n g i n t c o l o r_n o ;
unsi gned i nt j ;
u n s i g n e d c h a r f r e q u e n cy [ 8 1 9 2 J ;
u n s i gned i nt h ue s [ 8 1 92 J ;
v o i d ma i n ( a rg c , a rg v )
i nt a rgc ;
c h a r *a rgv [ J ;
i nt i ndex ;
i nt rgbi ndex ;
i nt yl ;
u n s i g n e d i n t d l , t em p_d ;
unsi gned cha r d2 ;
setMode ( 3 ) ;
i f ( a rgc ! = 2 )
I
p r i n t f ( " V GA C o l o r P r o c e s s o r by R o g e r S t e v e n s \ n " ) ;
p r i n t f ( " U s a g e : % s f i l e n a m e . RAW \ n " , a r g v [ O J ) ;
exi t ( l ) ;
c o l o r_h i s t = f a r m a l l o c ( 3 2 7 6 8 ) ;
f o r ( i =O ; i < 2 5 6 ; i ++ )
I
P a l _A r r a y [ i J [ r e d J O;
P a l _A r r a y [ i ] [ g r n ] O;
P a l _A r r a y [ i ] [ b l u ] O;
}
f o r ( j =O ; j < 3 2 7 6 8 ; j ++ )
c o l o r_h i s t [ j ] = O ;
xres = y res = O ;
270
D I S P L AY I N G A N D S AV I N G S C R E E N S
f r e a d ( & x r e s , s i z e o f ( i n t ) , l , f i l e_ l ) ;
f r e a d ( &y r e s , s i z e o f ( i n t ) , l , f i l e_ l ) ;
p r i n t f ( " V GA c o l o r p o s t - p r o c e s s o r by R o g e r S t e v e n s \ n " ) ;
p r i n t f ( " I m a g e f i l e r e s o l u t i o n i s : % d by % d \ n " , x r e s , y r e s ) ;
f o r ( i =O ; i < 2 5 6 ; i ++ )
{
P a l _A r r a y [ i J [ r e d J 0;
P a l _A r r a y [ i J [ g r n J O;
P a l _A r r a y [ i J [ b l u J O;
}
yl = O;
pri ntf( "Col l ecti ng col or data [ ]") ;
w h i l e ( ! f e o f ( f i l e_l ) )
{
f r e a d ( & s c a n l i n e , s i z e o f ( i n t ) , l , f i l e_l ) ;
i f ( s c a n l i n e >= y r e s )
p r i n t f ( " F a u l ty d a t a f i l e . \ n " ) ;
exi t ( l ) ;
}
g o t o xy ( 2 4 , 3 ) ;
p r i n t f ( "%d " , s c a n l i ne ) ;
f r e a d ( & r [ O J . s i z e o f ( c h a r ) , x r e s . f i l e_l ) ;
f r e a d ( & g [ O J . s i z e o f ( c h a r ) , x r e s . f i l e_l ) ;
f r e a d ( & b [ O J , s i z e o f ( c h a r ) , x r e s , f i l e_l ) ;
f o r ( i n d e x=O ; i n d e x < x r e s ; i n d e x++ )
{
C o l o r . Re d ( r [ i ndex J & Ox3e ) ;
Col o r . Green ( g [ i ndex J & Ox3e ) ;
Col or . Bl ue ( b [ i ndex J & Ox3e ) ;
c o l o r_n o = ( C o l o r . Re d > > 1 ) I ( C o l o r . G r e e n
<< 4) I ( Col or . Bl ue << 9 ) ;
i f ( c o l o r_h i s t [ c o l o r_n o ] < 2 5 5 )
c o l o r_h i s t [ c o l o r_n o ] ++ ;
y l += l ;
l ast col or = - 1 ;
f o r ( j =O ; j < 3 2 7 6 8 ; j ++ )
{
i f ( c o l o r_ h i s t [ j ] > 0 )
{
l a s t_ c o l o r++ ;
271
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +
h u e s [ l a s t_c o l o r ] = j ;
f r e q u e n cy [ l a s t_c o l o r ] c o l o r_h i s t [ j ] ;
f r e q u e n cy [ i ] d2 ;
f o r ( j =O ; j < 2 5 6 : j ++ )
{
C o l o r . Re d = ( h u e s [ j ] < < l l & O x 3 E ;
Col o r . Green = ( h ues [ j ] >> 4 ) & Ox3 E ;
C o l o r . Bl ue = ( h ues [ j ] >> 9 ) & Ox3 E ;
272
D I S P L AY I N G A N D S AV I N G S C R E E N S
P a l _A r r a y [ j J [ 0 J C o l o r . Red ;
P a l _A r r a y [ j J [ l J Col o r . Green ;
P a l _A r r a y [ j J [ 2 J Col or . B l ue ;
setMode ( Ox67 ) ;
s e t V GA p a l e t t e ( & P a l _A r r a y [ O J [ O J ) ;
f o r ( j =O ; j < 3 2 7 6 8 ; j ++ )
c o l o r_h i s t [ j ] = O ;
f o r ( j =O ; j < = l a s t_c o l o r ; j ++ )
c o l o r_ h i s t [ h u e s [ j ] J = f r e q u e n cy [ j ] ;
r e w i n d ( f i l e_l ) ;
yl = O ;
f r e a d ( & x r e s , s i z e o f ( i n t ) , l , f i l e_ l ) ;
f r e a d ( &y r e s , s i z e o f ( i n t ) , l , f i l e_ l ) ;
f o r ( y l ; y l < 4 8 0 ; y l ++ )
I
f r e a d ( & s c a n l i n e . s i z e o f ( i n t ) , l , f i l e_l ) ;
i f ( s c a n l i n e >= y r e s )
I
p r i n t f ( " F a u l ty d a t a f i l e . \ n " ) ;
exi t ( l ) ;
f r e a d ( & r [ O J , s i z e o f ( c h a r ) , x r e s , f i l e_l ) ;
f r e a d ( & g [ O J , s i z e o f ( c h a r ) , x r e s . f i l e_l ) ;
f r e a d ( & b [ O J , s i z e o f ( c h a r ) , x r e s . f i l e_l ) ;
f o r ( i n d e x=O ; i n d e x < x r e s ; i n d e x++ )
I
C o l o r . Red ( r [ i ndex J & Ox3e ) ;
Col or . Green ( g [ i ndex J & Ox3e ) ;
Col or . Bl ue ( b [ i ndex J & Ox3e ) ;
c o l o r_n o = ( C o l o r . Re d > > 1 ) I ( C o l o r . G r e e n
<< 4 ) I ( Col o r . Bl ue << 9 ) ;
p l o t ( i n d e x , y l , c o l o r_h i s t [ c o l o r_n o ] ) ;
getch ( ) ;
setMode ( 3 ) ;
f c l o s e ( f i l e_ l ) ;
273
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +
I�
/*
s etMode ( ) Sets V i deo Mode
� ==========!I
*/
v o i d s etMode ( i n t mode )
{
i f ( mode > Ox32 )
{
a c t i v e_b a n k = O ;
reg . x . a x = Ox6 F05 :
reg . h . b l = mode ;
i n t86 ( Ox l O , & reg , ® ) ;
o u t pw ( O x 3 C 4 , 0 x E A 0 6 ) ;
el se
{
reg . h . a h = 0 ;
reg . h . a l = mode ;
i n t86 ( Ox l O , & reg , & reg ) ;
pl ot ( ) F u n c t i on to p l ot p o i n t t o VGA 2 5 6 C o l o r S c reen
*/
voi d pl ot ( i nt x , i nt y , i nt col o r )
{
l ong i nt offset :
c h a r fa r *addres s ;
i n t temp , t emp2 ;
274
D I S P L AY I N G A N D S AV I N G S C R E E N S
o u t pw ( O x 3 C 4 , r e g . x . a x ) ;
t e m p = i n pw ( O x 3 C C ) ;
t emp = temp & Ox D F :
i f ( ( ba n k & Ox02 ) ! = 0 )
t em p = t e m p I O x 2 0 ;
o u t pw ( O x 3 C 2 . t em p ) ;
outp ( Ox3C4 , 0x F6 ) ;
t e m p = i n pw ( O x 3 C 5 ) ;
t emp = temp & Ox FO :
t emp2 = ( ( ba n k & OxOC ) > > 2 ) I ( ba n k & OxOC ) ;
temp = temp I temp2 ;
outp ( Ox3C 5 , temp ) ;
a d d r e s s = ( c h a r fa r * ) ( OxAOOOOOOO L + offset ) ;
*add ress = col or :
/ *rr=======;i
s e t V GA p a l e t t e ( ) F u n c t i on t o s e t a l l 2 5 6 col o r reg i s t e r s
*I
v o i d s e t V GA p a l e t t e ( u n s i g n e d c h a r * b u f f e r )
{
reg . x . a x = Oxl01 2 :
segread ( & i n reg ) ;
i n reg . es i n reg . d s :
reg . x . bx O;
reg . x . cx 256 ;
reg . x . dx ( i nt ) &buffer [OJ ;
i n t86x ( Ox l 0 , & reg , & reg , & i n reg ) ;
I*
sort ( ) Q u i c k s o r t t o s o r t c o l o r s by f r e q u e n cy
*I
v o i d s o r t ( u n s i g n e d i n t s t a r t . u n s i g n ed i n t end )
{
u n s i gned i n t pi vot , temp2 :
un s i gned c h a r temp ;
275
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
whi l e ( i < j ) ;
i f ( j < end )
{
s o rt ( s t a rt , j ) ;
sort ( j+l , end ) ;
i f ( f r e q u e n c y [ e n d ] > f r e q u e n cy [ s t a r t ] )
{
temp = f r e q u e n cy [ s t a r t ] ;
f r e q u e n cy [ s t a r t ] = f r e q u e n c y [ e n d ] ;
f r e q u e n cy [ e n d ] = t emp ;
t em p 2 = h u e s [ s t a r t ] ;
h ue s [ s t a rt ] = h ues [ e nd ] ;
h ue s [ end ] = temp2 ;
276
D I S P L AY I N G A N D S AV I N G S C R E E N S
v o i d g o t o xy ( i n t x , i n t y )
!
reg . h . a h= 2;
reg . h . bh = O;
reg . h . d h= y-1 ;
reg . h . d l= x-1 ;
i n t86 ( 0x l 0 , & reg , & r eg ) ;
The program begins exactly like the preceding one, checking to see whether
a file name is specified on the call line and if not, displaying an error message
and exiting. Similarly, it then tries to open the file if one is specified, and if
unsucces sfu l , d i splays an error m e s s age and quits. If the file i s opened
successfully, the program strips off that part of the file name preceding the dot
and appends . PCX to it. It then opens this new file and sends the proper
information for the . PCX format file header to it. Next, the program does
exactly what the preceding program did to collect information on the occurrence
of colors, assign the 256 color register values, and find the least squares fit for
those colors not among the first 256. The program then rewinds the file, reads
the xres and yres values, and enters a while loop that continues until the end of
file is encountered.
At the beginning of each iteration of the loop, the program reads the scan
line number from the file and, if it exceeds the allowable maximum value,
displays an error message and exits. If the scan line value is OK, a line of red,
277
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
green, and blue pixel data is read to the appropriate arrays. For each pixel in the
line, the proper index is created from the color data and used to obtain the pixel
color from the col_hist array. This data is then encoded in the .PCX format.
Essentially, this format simply outputs the byte to the file if it is a single
occurrence and does not have the two most significant bits as ones. Otherwise
two bytes are output. The first has its two most significant bits set to one and the
remaining bits give a count (between 1 and 63) of the number of sequential
occurrences of the same byte value.
/*
pcxgen P rogram to P roce s s C o l o r Data for VGA and
s a v e to a . PC X d i s k fi l e .
I n c l u d e s 3 2 0 x 2 0 0 a n d 6 4 0 x4 8 0 m o d e s
B y Rog e r T . S t e v e n s 5/5/90
*/
voi d g o t o xy ( i n t x , i n t y ) ;
voi d pl ot ( i nt x , i nt y , i n t col o r ) ;
voi d s etMode ( i n t mode ) ;
voi d s e t VGApa l e t te ( un s i gned c h a r *buffe r ) ;
voi d s o rt ( un s i gned i n t s t a rt , u n s i gned i nt end ) ;
ty p e d e f s t r u c t r g b
{
c h a r Red ;
c h a r G reen ;
cha r Bl ue ;
RGB ;
278
D I S P L AY I N G A N D S AV I N G S C R E E N S
#de f i n e red 0
#de f i n e g r n 1
#d e f i n e b l u 2
u n s i g n e d i n t C o l _A r r a y [ 2 5 6 ] [ 2 J ;
u n s i g n e d c h a r P a l _A r r a y [ 2 5 6 J [ 3 J ;
RGB C o l o r , Co l o r 2 ;
i n t i , k , a d d l , a d d 2 , n u m b e r , l i n e_l e n g t h , e n d , s t a r t_l i n e , e n d_l i n e ,
x r e s , y r e s , l a s t_c o l o r , s c a n l i n e , r l , r 2 , g l , g 2 , b l , b 2 ;
u n s i g n e d c h a r P A L E TT E [ l 6 J =
{ 0 , 1 , 2 , 3 , 4 , 5 , 2 0 , 7 , 56 , 5 7 , 58 , 59 , 60 , 6 1 , 6 2 , 63 ) ;
u n s i g n e d c h a r c h , c h l , o l d_c h , n u m_o u t , r e d_p , g r e e n_p , b l u e_p ;
u n s i g n e d c h a r r [ MA X X R E S ] , g [ MA X X R E S ] , b [ MA X X R E S ] ;
F I L E * f i l e_ l , * f s a v e ;
u n s i g n e d c h a r f a r * c o l o r_h i s t ;
l o n g i n t c o l o r_n o , j ;
u n s i g n e d c h a r f r e q u e n cy [ 8 1 9 2 ] ;
u n s i g n ed i n t h ue s [ 8 1 92 J ;
c h a r f i l e n a me [ l 5 J ;
ma i n ( a rgc , a rg v )
i nt a rgc ;
cha r *a rgv [ J ;
s etMode ( 3 ) ;
cout «
279
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
..
" II I I\ n :
cout «
..
" II I I\ n :
cout «
" II P rogram to P roce s s Col o r D a t a f o r VGA a n d I l\ n " ;
cout «
" II s a v e to a . PCX d i s k fi l e . I l\ n " ;
cout «
" II I n c l u d e s 3 2 0 x 2 0 0 a n d 640x480 mod e s I l\ n " ;
cout «
" II I l\ n " ;
cout «
" II By R o g e r T . S t e v e n s 5 / 5 / 90 I l\ n " ;
i f ( a rgc ! = 2 )
{
cout «
..
" II I I\ n :
cout «
..
" II U s e a g e : p c x g e n f i l e n a me . RAW I I\ n :
}
cout «
" II I l\ n " ;
cout «
" II I l\ n " ;
i f ( a rg c ! = 2 )
exi t ( l ) ;
i f ( ( f i l e_ l = f o p e n ( a r g v [ l ] , " r b " ) ) == N U L L )
{
p r i n t f ( "Cou l dn ' t open fi l e % s \ n " , a rg v [ l ] ) ;
exi t ( l ) ;
f o r ( i =O ; i < 2 5 6 ; i ++ )
{
P a l _A r r a y [ i J [ r e d J O;
P a l _A r r a y [ i ] [ g r n ] O;
280
D I S P L AY I N G A N D S AV I N G S C R E E N S
P a l _A r r a y [ i ] [ b l u ] = O ;
c o l o r_h i s t = f a r m a l l o c ( 3 2 7 6 8 ) ;
f o r ( j =O ; j < 3 2 7 6 8 ; j ++ )
c o l o r_h i s t [ j ]
= O;
xres = y res = O ;
f r e a d ( & x r e s , s i z e o f ( i n t ) , l , f i l e_ l ) ;
f r e a d ( &y r e s , s i z e o f ( i n t ) , l , f i l e_ l ) ;
c o u t < < " \ n \ n l m a g e f i l e r e s o l u t i o n i s : " < < x r e s < < " by " < <
y res « " \ n " ;
i f ( ! ( ( ( xres 3 2 0 ) & & ( y r e s == 2 0 0 ) ) I I ( ( x r e s 6 4 0 ) &&
( y r e s == 4 8 0 ) ) ) )
281
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
fput c ( OxOO , fs a ve ) ;
fput c ( OxOl , fs a ve ) ;
fput c ( Ox40 , fs a ve ) ;
fput c ( OxOl , fs a ve ) ;
l i n e_l e n g t h = x r e s ;
end = xres ;
f o r ( i =6 8 ; i < l 2 8 ; i ++ )
fputc ( OxOO , fs a ve ) ;
yl = O ;
p r i n t f ( " C o l l e c t i n g c o l o r d a t a f r om s c a n l i n e [ ]") ;
w h i l e ( ! f e o f ( f i l e_l ) )
{
f r e a d ( & s c a n l i n e , s i z e o f ( i n t ) , l , f i l e_ l ) ;
i f ( s c a n l i n e >= y r e s )
{
p r i n t f ( " F a u l ty d a t a f i l e . \ n " ) ;
ex i t ( l ) ;
g o t o xy ( 3 9 , 1 3 ) ;
p r i n t f ( "%3d " , s c a n l i ne ) ;
f r e a d ( & r [ O J , s i z e o f ( c h a r ) , x r e s , f i l e_l ) ;
f r e a d ( & g [ O J , s i z e o f ( c h a r ) , x r e s , f i l e_l ) ;
f r e a d ( & b [ O J , s i z e o f ( c h a r ) , x r e s , f i l e_l ) ;
f o r ( i n d e x=O ; i n d e x < x r e s ; i n d ex++ )
{
C o l o r . Red ( r [ i ndexJ & Ox3e ) ;
Col o r . G reen ( g [ i ndexJ & Ox3e ) ;
Col or . Bl ue ( b [ i ndexJ & Ox3e ) ;
c o l o r_n o = ( C o l o r . Re d > > 1 ) I ( C o l o r . G r e e n
< < 4) I ( Co l o r . Bl ue << 9 ) ;
i f ( c o l o r_h i s t [ c o l o r_n o ] < 2 5 5 )
c o l o r_h i s t [ c o l o r_n o ] ++ ;
y l += l ;
282
D I S P L AY I N G A N D S AV I N G S C R E E N S
l a s t_c o l o r = - 1 ;
f o r ( j =O ; j < 3 2 7 6 8 ; j ++ )
{
i f ( c o l o r_ h i s t [ j ] > 0 )
{
l a s t_c o l o r++ ;
h u e s [ l a s t_c o l o r ] j;
f r e q u e n cy [ l a s t_c o l o r ] c o l o r_h i s t [ j J ;
283
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
f r e q u e n cy [ i ] = d 2 ;
f o r ( j =O ; j < 2 5 6 ; j ++ )
{
C o l o r . Red = ( h u e s [ j ] < < 1 ) & Ox3E ;
C o l o r . G reen = ( h u e s [ j ] > > 4 ) & Ox3 E ;
C o l o r . Bl ue = ( hues [ j ] >> 9 ) & Ox3 E ;
P a l _A r r a y [ j ] [ O J C o l o r . Red ;
P a l _A r r a y [ j ] [ l ] Col or . Green ;
P a l _A r r a y [ j ] [ 2 J Col o r . Bl ue ;
f o r ( j =O ; j < 3 2 7 6 8 ; j ++ )
c o l o r_h i s t [ j ] = O;
f o r ( j =O ; j <= l a s t_c o l o r ; j ++ )
c o l o r_h i s t [ h u e s [ j ] J = f r e q u e n cy [ j ] ;
r e w i n d ( f i l e_l ) ;
yl = 0 ;
f r e a d ( & x r e s , s i z e o f ( i n t ) , l , f i l e_ l ) ;
f r e a d ( &y r e s , s i z e o f ( i n t ) , l , f i l e_l ) ;
w h i l e ( ! f e o f ( f i l e_l ) )
{
f r e a d ( & s c a n l i n e , s i z e o f ( i n t ) , 1 , f i l e_l ) ;
i f ( s c a n l i n e >= y re s )
{
p r i n t f ( " F a u l ty d a t a f i l e . \ n " ) ;
ex i t ( l ) ;
f r e a d ( & r [ O J , s i z e o f ( c h a r ) , x r e s , f i l e_ l ) ;
f r e a d ( & g [ O J , s i z e o f ( c h a r ) , x r e s , f i l e_l ) ;
f r e a d ( & b [ O J , s i z e o f ( c h a r ) , x r e s , f i l e_l ) ;
C o l o r . Red ( r [ O J & Ox3e ) ;
Col o r . Green = ( g [ O J & Ox3e ) ;
Col o r . Bl ue = ( b [ O J & Ox3e ) ;
c o l o r_n o = ( C o l o r . R e d > > 1 ) ( Co l o r . G reen < < 4 ) I
( Col o r . Bl ue << 9 ) ;
n umbe r = 1 ;
o l d_c h = c o l o r_h i s t [ c o l o r_n o ] ;
f o r ( i n d e x= l ; i n d e x <=x r e s ; i n d e x++ )
{
C o l o r . Red ( r [ i ndexJ & Ox3e ) ;
Col o r . G reen ( g [ i ndex J & Ox3e ) ;
Col o r . Bl ue ( b [ i ndex J & Ox3e ) ;
284
D I S P L AY I N G A N D S AV I N G S C R E E N S
y l += l ;
fputc ( OxOC , fs a ve ) ;
f o r ( i =O ; i < 2 5 6 ; i ++ )
f o r ( j =0 ; j < 3 ; j ++ )
f p u t c ( P a l _A r r a y [ i ] [ j ] * 4 , f s a v e ) ;
fcl ose ( fsave ) ;
f c l o s e ( f i l e_ l ) ;
c o u t < < " F i l e t r a n s f o rm a t i o n c o m p l e t e . \ n " ;
I*
s o rt ( ) Q u i c k s o r t t o s o r t c o l o r s by f r e
*/
v o i d s o rt ( u n s i g n e d i n t s t a rt , u n s i g n ed i n t end )
{
un s i gned i nt pi v ot , temp2 ;
u n s i g n e d c h a r t e mp ;
i f ( s t a r t < ( end - 1 ) )
{
285
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
i = sta rt ;
j = end ;
pi vot ( f r e q u e n cy [ i ] + f r e q u e n cy [ j ] +
f r e q u e n cy [ ( i +j ) / 2 ] ) / 3 ;
do
{
w h i l e ( f r e q u e n cy [ i ] > p i v o t )
i ++ ;
w h i l e ( f r e q u e n cy [ j ] < p i v o t )
j- ;
if (i < j)
{
t em p = f r e q u e n cy [ i ] ;
f r e q u e n cy [ i ] = f r e q u e n cy [ j ] ;
f r e q u e n cy [ j ] = t e m p ;
temp2 = h u es [ i ] ;
h u e s [ i ++ J = h u e s [ j ] ;
h u e s [ j -J = temp2 ;
whi l e ( i < j ) ;
i f ( j < end )
{
sort ( sta rt , j ) ;
s o rt ( j +l , end ) ;
i f ( f r e q u e n cy [ e n d ] > f r e q u e n cy [ s t a r t ] )
{
t em p = f r e q u e n cy [ s t a r t ] ;
f r e q u e n cy [ s t a r t ] = f r e q u e n cy [ e n d ] ;
f r e q u e n cy [ e n d ] = t em p ;
temp2 = hues [ st a rt ] ;
hues [ sta rt] = hues [end ] ;
h u e s [ end ] = temp2 ;
v o i d g o t o xy ( i n t x , i n t y )
{
reg . h . a h = 2 ;
reg . h . bh = O ;
reg . h . dh = y - 1 ;
286
D I S P L AY I N G A N D S AV I N G S C R E E N S
reg . h . d l= x-1 ;
i nt86 ( 0x l 0 , & reg , & r eg ) ;
/*
setMode ( ) Sets V i deo Mode
*/
v o i d s etMode ( i nt mode )
{
reg . h . a h = O;
reg . h . a l = mode ;
i nt86 ( 0x l 0 , & reg , ® ) ;
The second byte i s the value of the recurring byte. The program does this by
storing the previous byte value and comparing it with the current one. When
they agree and the number is within bounds, the number counter is incremented.
When they disagree, the information for the count and the previous byte is sent
to the file and the counter reset. When all of the input data is processed, the
information for setting the colors of the color registers is appended to the end of
the . PC X file in the proper format, both files are closed, and the program
term inates. The program works equally well with the standard 320 by 200
resolution or the extended 640 by 480 resolution. We have set things up so that
if anything other than these two specified resolutions is read in from the data file,
the program displays an error message and terminates.
287
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
simple barebones program, but if you can create the display with this program,
you know that the basic information is there in .PCX format, so it should work
with any other program that is truly .PCX compatible. The program is listed in
Figure 1 4-4.
/*
By R o g e r T . S t e v e n s 5/5/90
*/
i n t r e s t o r e_s c r e e n ( c h a r f i l e_n a m e [ J ) ;
v o i d g o t o xy ( i n t x , i n t y ) ;
voi d pl ot ( i nt x , i nt y , i nt col or ) ;
v o i d s etMode ( i n t mode l ;
voi d setVGApa l ette ( un s i gned c h a r *buffer ) ;
u n s i g n e d c h a r P a l _A r r a y [ 2 5 6 ] [ 3 J ;
i n t x r e s , y r e s , a c t i v e_b a n k , b a n k ;
ma i n ( a rg c , a rg v )
i nt a rgc ;
cha r *a rgv [ J ;
288
D I S P L AY I N G A N D S AV I N G S C R E E N S
s etMode ( 3 ) ;
i f ( a rg c ! = 2 )
{
r e s t o r e_ s c r e e n ( a r g v [ l ] ) ;
getch ( ) ;
s e tMode ( 3 ) ;
i n t r e s t o r e_s c r e e n ( c h a r f i l e_n a me [ J )
{
#i ncl ude <dos . h>
#i ncl ude <stdi o . h>
FI LE *fl ;
u n s i g n e d c h a r c h , c h l , r e d , g r e e n , b l u e , c o l o r , l i n e_l e n g t h , e n d ;
i n t l i n e_ e n d , i , j , k , m , p a s s , x l , y l , x 2 , y 2 ;
el se
{
c h = fgetc ( fl ) ;
i f ( c h ! = OxOA )
{
c o u t < < " \ n " < < f i l e_n a m e < <
" i s not a v a l i d Z Soft fi l e . \ n " ;
fcl ose ( fl ) ;
return ( l ) ;
289
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
f s e e k ( f l , - 7 6 9 L , S E E K_ E N D l :
c h = fgetc ( fl ) :
i f ( ch ! = OxOC l
{
c o u t < < " \ n " < < f i l e n a me < < " i s n o t a M o d e 1 9 f i l e . \ n " :
fcl ose( fl ) ;
return ( l ) ;
f o r ( i =O : i < 2 5 6 ; i ++ )
f o r ( j =O ; j < 3 : j ++ )
{
P a l _A r r a y [ i J [ j J fgetc ( fl ) ;
P a l _A r r a y [ i J [ j J P a l _A r r a y [ i ] [ j ] I 4 ;
f s e e k ( f l , 1 2 L , S E E K_S E T ) ;
frea d ( &x res , s i zeof ( i n t ) , l , f l ) ;
f r e a d ( &y r e s , s i z e o f ( i n t ) , l , f l ) ;
i f ( ( x r e s == 3 2 0 ) & & ( y r e s == 2 0 0 ) )
s etMode ( Ox l 3 ) ;
el se
{
i f ( ( x r e s == 6 4 0 ) & & ( y r e s 480 ) )
s etMod e ( Ox67 ) :
el se
{
c o u t < < " \ n " < < f i l e_n a m e < <
" i s not a Mode 13H or Mode 67H fi l e . \n" :
fc l o se ( f l ) ;
return ( l ) ;
s e t V GA p a l e t t e ( & P a l _A r r a y [ O J [ O J ) ;
f s e e k ( f l , 1 2 8 L , S E E K_S E T ) ;
f o r ( k=O ; k <y r e s ; k++ )
{
f o r ( i =O : i < x r e s ; i ++ )
{
c h l = fgetc ( fl ) ;
i f ( ( c h l & OxCO ) ! = OxCO l
{
290
D I S P L AY I N G A N D S AV I N G S C R E E N S
pl ot ( i , k , c h l ) ;
el se
I
c h l &= O x 3 F ;
pa s s = c h l ;
c h = fgetc ( fl ) ;
f o r ( m=O ; m < p a s s ; m++ )
I
p l o t ( i ++ , k , c h ) ;
i-;
fcl ose ( fl ) ;
ret u rn ( Q ) ;
I*
s e t V GA p a l e t t e ( ) F u n ct i on t o set a l l 256 c o l o r reg i s t e r s
v o i d s e t V GApa l e t t e ( u n s i g n e d c h a r *buffe r )
I
reg . x . a x = O x 1 0 1 2 ;
s e g r e a d ( & i n reg ) ;
i n reg . es i n reg . ds ;
reg . x . bx 0;
reg . x . cx 256 ;
reg . x . dx ( i nt ) &buffer [ O J ;
i n t86x ( Ox 1 0 , ® , & reg , &i n reg ) ;
v o i d g o t o xy ( i n t x , i n t y )
I
reg . h . a h = 2 ;
reg . h . bh = O ;
reg . h . d h = y - 1 ;
reg . h . d l = x - 1 ;
i n t86 ( 0x 1 0 , ® , & r eg ) ;
291
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
/*
setMode ( ) Sets V i deo Mode
*/
v o i d s etMode ( i n t mode )
{
i f ( mo d e > O x 3 2 )
{
a c t i v e_b a n k = O ;
reg . x . ax = Ox6F05 ;
r e g . h . b l = mo d e ;
i nt86 C Ox l O , & reg , ® ) ;
o u t pw ( O x 3 C 4 , 0 x E A 0 6 ) ;
el se
{
reg . h . a h = O ;
r e g . h . a l = mo d e ;
i n t86 ( Ox l O , ® , ® ) ;
/*
pl ot ( ) F u n ct i on t o p l ot p o i n t to VGA 2 5 6 C o l o r S c reen
*/
voi d pl ot ( i nt x . i nt y , i nt col o r )
{
l ong i nt offset ;
c h a r fa r * a d d r e s s ;
i n t t em p , t e m p 2 ;
292
D I S P L AY I N G A N D S AV I N G S C R E E N S
a d d r e s s = ( c h a r fa r * ) ( QxAOOOOOO O L + offset ) ;
*add ress = col or ;
293
CHAPTER 1 5
If you have been carefully observing the programs so far, you have probably
noticed a few references to fractals and wondered why nothing was said about
them in the description. Fractals are treated differently from other objects, and
introduce a number of unique problems. We have waited until this chapter to
cover all of their aspects in a single place.
(Equation 1 5- 1 )
where Y I and Y 2 are the heights of the two ends of the side. (In other words, the
mean of the random distribution is actually the mean altitude of the side.) The
variance of the random distribution is:
where L is the length of the side and H is the fractal dimension. After we have
performed this operation for all three triangle sides, we connect each vertex of
the triangle with the displayed midpoints of its adjacent sides, creating a set of
four new triangles. This procedure is then repeated with each of the four new
295
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
triangles. The process is repeated as many times as desired. The result is a fairly
realistic representation of a mountain.
In July 1 983, James T. Kajiya published a paper, "New Techniques for Ray
Tracing Procedurally Defined Objects" in Computer Graphics. Kajiya pointed
out that any fractal object generated by the midpoint displacement method in ray
tracing would have so many individual facets that attempting to check the
intersection of every ray with every facet would take an impossibly large amount
of computer time. Kajiya's solution to this dilemma was to begin only with the
initiating triangle. Around this, he placed what he called a "cheesecake" extent,
which was a triangular faced solid having a height such that it would include any
displacements that might occur in succeeding triangles generated by midpoint
d isplacement. (Actually, since a random process was involved, the extent
dimensions were set up to include all cases w i th better than 99 percent
probability; it was impossible to assure that every case would be within the
extent.) Now, if a ray being traced did not intersect this extent, it also wouldn't
intersect the fractal, so the ray tracing task was done. If there was an intersection
with the extent, Kajiya generated the next four midpoint displacement triangles,
placed extents around each of them, and checked for intersections with each
extent. He continued with this process, generating only those lower levels of the
fractal that were needed to check for actual intersections with the ray being
traced. This substantially reduced the number of intersection checks that needed
to be performed, and thus reduced the computer time to a reasonable amount.
Since then, other articles have appeared, using basically thesame technique, but
suggesting more efficient extents which could reduce the computer time even
further.
Actually, thi s technique slightly misses the mark. The cause of much wasted
computer time is the attempt to intersect each facet directly with the ray. It is
solved by placing extents around l arger and l arger subsets of the fractal .
Generating pieces of the fractal on demand doesn ' t really contribute to the
situation; since many facets will have to be generated more than once, the actual
fractal generation time will be larger than if all facets were generated initially.
296
R E N D E R I N G F R A C TA L S C E N E S
297
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
fractals. They are fractal_dim. fractal_scalar, and limit. The first is actually
twice the fractal dimension as given in Equation 1 5- 1 . It has been set at 0.9.
You can adjust it to change the "ruggedness" of the terrain, but be ready for
some surprises in the scenes that you generate. The second is a scalar that is
necessary to make sure that the fractal mountain is the right size to fit into the
picture. It has been initialized to 0.002. Be careful when you change these two
parameters; it is easy to get a mountain that takes up almost the whole picture,
which may require 1 0 to 1 2 hours to ray-trace the scene, even when using a 386
machine with a math coprocessor. The final parameter level cannot be any larger
than 4 unless you rework the program to allow more facets, without using up all
of the memory.
Next tum to the input.cpp file. In the Get_Object function, you ' ll see that
there is a case for getting a fractal object, which calls the function GetFractal.
Note that this function returns newobj which is of class Triangle so that once we
leave thi s function, there will never be any difference between this and an
ordinary triangle. (However, it gets a lot more complicated than this as we shall
see.) The next part of the function is just the same as that for a triangle, getting
the s ame parameters and performing the same checking to assure that all
necessary parameters have been read in.
Now we come to the first major difference when the function Fractal_comp
is called. This is part of the file fractal.cpp, which is listed in Figure 1 5- 1 . This
function does the same calculations that were performed for the triangle at the
end of the GetTriangle function and also calculates the variance to be used for
each midpoint displacement. These three variances are stored in the three
components of the vector vect3 . Next GetFractal calls MakeJractal_triangles,
passing it the data on the three vertices of the triangle; the variances, the address
of the current object, and the level. This function begins by creating four new
triangles, the color data for them, and a bounding box. If this is the top level, the
current object address is set up as the bounding box 's next object address, and
the address of the bounding box is stored to be returned when the function
terminates. If we are at some lower level, the bounding box 's next object
298
RENDERING F R A C TA L S C E N E S
address is set to NULL. The function then sets up the location vector for each of
the first three new triangles and computes the three bisectors of the sides of the
original triangle. Next, the altitude displacement for each bisector is computed.
A seed is generated for each side for the random number generator. This makes
the random number generator a little less than random. However, it is needed
because some of the triangle sides are common to two triangles. If different
values of altitude displacement were calculated for the two uses of the same side,
there would be objectionable discontinuities in the figure. The seed is based
upon the three coordinates of the bisect point in such a way that it is unique to a
particular position but will be the same each time that position occurs, so that the
same random number is produced. After the seed is generated, gauss is called to
generate the altitude displacement, which is multiplied by the variance and added
to the bisector altitude value. To avoid underground mountains, the new altitude
of the bisector is never allowed to fall below zero. Next, each of the three new
triangles has its color data set to the default color data. The remaining vectors
for the three new triangles and the information for the fourth triangle (which is
the connection of the three bisectors) are then computed. Then the function
Fractal_comp for all four new triangles is run to do the remaining computations,
including the variances for the next level bisectors. If the level has not reached
zero , we decrease the level by one and then call Make Jractal_triangles
recursively for each of the four new triangles to make four more new triangles at
the next lower level. The four next higher-level triangles are then deleted. If we
have reached the lowest (zero) level, we don't generate any more triangles, but
place the address of the four low level ones in the list of objects, increase the
object count by four and, return. The lowest level triangles are in the list, with
bounding boxes surrounding every set of four, and a bounding box surrounding
each set of four of these bounding boxes, and so forth, so that at the top is only a
single bounding box encompassing the entire fractal. The ray-tracing program
then treats these just as it would any other objects.
299
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
/*
f r a c t a l . cpp = F u n c t i on s to t re a t f r a c t a l s
By R o g e r T . S t e v e n s - 5 / 1 2 / 9 0
*I
gauss ( ) F u n c t i o n t o g e n e r a t e G a u s s i a n r a n d om v a r i a b l e
*/
f l o a t g a u s s ( u n s i g n e d i n t s e ed )
{
f l o a t x=O ;
i nt i ;
i f ( s eed ! = 0 )
s rand ( seed ) ;
f o r ( i =O ; i < l 2 : i ++ )
x += ( f l o a t ) ( r a n d ( ) ) / 3 2 7 6 8 . 0 ;
x -= 6.0;
return ( x ) ;
/*
M a k e_f r a c t a l _t r i a n g l e s ( ) C r e a t e f o u r n ew f r a c t a l
t r i a n g l e s f r om a t r i a n g l e
300
R E N D E R I N G F R A C TA L S C E N E S
O b j e c t * M a k e_f r a c t a l _t r i a n g l e s ( V e c t o r l o c , V e c t o r v e c t l , V e c t o r
vect2 , Vector vect3 , Obj ect *queue , i n t l evel )
V e c t o r b i s e c t l , b i s e c t 2 , b i sect3 , temp ;
u n s i g n e d i n t s e ed ;
f l o a t t e m p l , t e m p 2 , t e m p 3 , m u , m a x_h t ;
T r i a n g l e * n e w t r i O , * n ew t r i l , * n e w t r i 2 , * n ewt r i 3 ;
BBox * n ewobj ;
c o l _m a x Vector ( 63 , 63 , 63 ) ;
n ewt r i O new T r i a n g l e ;
newt r i l n ew T r i a n g l e ;
n ewt r i 2 new T r i a n g l e ;
n ewt r i 3 new T r i a n g l e ;
n ew t r i O - > c o l d a t a n e w c o l o r_d a t a ;
n ewt r i l - > c o l d a t a n e w c o l o r_d a t a ;
n ew t r i 2 - > c o l d a t a n e w c o l o r_d a t a ;
n ewt r i 3 - > c o l d a t a n ew c o l o r_d a t a ;
n ewobj = n ew BBox ;
n e w o b j - > ty p e = B B O X ;
i f ( l e v e l == W O R L D . l e v e l )
{
n ewobj - > nextobj = q ueue ;
q u e u e = n ewobj ;
el se
n ewobj - > n e x t o bj = N U L L ;
n ew t r i O - > l o c l oc ;
n ewt r i l - > l o c = l o c + v e c t l ;
n ew t r i 2 - > l o c = l o c + v e c t 2 ;
bi sectl l oc + vectl I 2 ;
bi sect2 = l oc + vect2 I 2 ;
b i s e c t 3 = n e wt r i l - > l o c + ( v e c t 2 - v e c t l ) I 2 ;
seed = ( ( u n s i gned i n t ) ( b i sect3 . x * 1 0000 + bi sect3 . y * 100 +
b i s e c t3 . z ) ) %32767 + 2 ;
b i s e c t 3 . y += g a u s s ( s e e d ) * v e c t 3 . z ;
b i s e c t 3 . y = MAX ( b i sect3 . y , 0 ) ;
301
F R A C T A L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
302
R E N D E R I N G F R A C TA L S C E N E S
M a k e_f r a c t a l _t r i a n g l e s ( n ew t r i O - > l o c ,
n ew t r i O - > v e c t l , n ew t r i 0 - > v e c t 2 ,
n ew t r i O - > v e c t 3 , q u e u e , l e v e l ) ;
n ew o b j - > c h i l d - > n e x t o b j - > n e x t o b j - > n e x t o bj - > n e x t o b j NU L L ;
d e l e t e n ew t r i O ;
d e l e t e n ew t r i l ;
d e l e t e n ew t r i 2 ;
d e l e t e n ew t r i 3 ;
el se
{
n ew t r i O - > n e x t o b j NULL ;
n ew t r i l - > n e x t o b j newtr i O ;
newt r i 2 - > n e x t obj n ew t r i l ;
n ew t r i 3 - > n e x t o b j n ew t r i 2 ;
n ew o b j - > n e x t o b j = N U L L ;
n ew o b j - > c h i l d = n ew t r i 3 ;
W O R L D . o b j c o u n t += 4 ;
i f ( l e v e l == W O R L D . l e v e l )
return ( queue ) ;
re t u r n ( n ewobj ) ;
/*
F r a c t a l _c om p ( ) C om p u t e s f r a c t a l p a r a me t e r s
*/
v o i d F r a c t a l _c om p ( T r i a n g l e * n ew o b j )
{
V e c t o r temp ;
t e m p = n ew o b j - > v e c t 2 - n ew o b j - > v e c t l ;
n ew o b j - > v e c t 3 . z = t e m p % t e m p ;
n ew o b j - > v e c t 3 . z = p ow ( n ew o b j - > v e c t 3 . z / 4 , WO R L D . f r a c t a l _d i m ) *
W O R L D . f r a c t a l _s c a l a r ;
n ew o b j - > v e c t 3 . x = n e w o b j - > v e c t l % n ew o b j - > v e c t l ;
n ew o b j - > v e c t 3 . x = p ow ( n e w o b j - > v e c t 3 . x / 4 , W O R L D . f r a c t a l _d i m ) *
W O R L D . f r a c t a l _s c a l a r ;
n ew o b j - > v e c t 3 . y = n ew o b j - > v e c t 2 % n ew o b j - > v e c t 2 ;
303
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
n ew o b j - > v e c t 3 . y = p ow ( n ew o b j - > v e c t 3 . y / 4 , WO R L D . f r a c t a l _d i m ) *
W O R L D . f r a c t a l _s c a l a r ;
n ew o b j - > n o rm = n ew o b j - > v e c t l A n ew o b j - > v e c t 2 ;
n ew o b j - > n o rm = - n ew o b j - > n o rm ;
n ew o b j - > n l = n e w o b j - > n o rm % n ew o b j - > l o c ;
newobj - > l e n l n ew o b j - > v e c t l % n ew o b j - > v e c t l ;
newobj - > l en2 = n ew o b j - > v e c t 2 % n ew o b j - > v e c t 2 ;
304
CHAPTER 1 6
axb=bxa (Equation 1 6- 1 )
The order i n which the numbers are multiplied doesn't matter; we get the
same result no matter what order is used. For quaternions, this is not true. In
fact, we find that if a and b are quaternions then:
a x b = - (b x a) (Equation 1 6-2)
qi , and qJ . directed along the mutually orthogonal axes identified by the unit
vectors i, }, and k. These vectors follow the rules for vector cross products in a
right-hand coordinate system, namely:
ij = k j i = -k
305
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
jk = i kj = -i
ki = j ik = -j (Equation 1 6-3)
and
(Equation 1 6-5)
or alternately as:
(Equation 1 6-6)
where the underlining means that the variable is a three-dimensional vector, or:
(Equation 1 6-7)
Probably you ' re wondering just what quaternions are for, besides being an
interesting mathematical exercise. One important use is in the dynamics of
flight. Suppose we represent the position of an aircraft by an ordinary three
dimensional coordinate system. In following the aircraft through complex
maneuvers, we often want to keep track of some quantities in a coordinate
system centered at and oriented to the aircraft and of other quantities in a
g ro u n d - b a s e d c o o r d i nate s y s t e m . T h i s i n v o l v e s a l o t o f c o o r d i nate
transformations and for certain rotations, singularities occur. These don't bother
an observer; when the aircraft angle is such that one coordinate system needs to
be rotated 90 degrees to get to another, we observe that particular angular
relationship without comment. But computers get confused when they try to
handle division by zero or find tangents that go to infinity. Thus with the usual
matrix transformations of one three-dimensional coordinate system to another,
306
Q U AT E R N I O N S A N D T H E I R M AT H E M AT I C S
In this book, we aren 't concerned with aircraft flight, although if you have
occasion to get into that field, you ' ll be glad to get a grounding in quaternion
mathematics. What we are going to do is apply quaternions to Julia and dragon
sets. It turns out that the same kinds of iterated equations that make use of
complex numbers to generate two-dimensional Julia and dragon sets, can be used
with quaternions to create four-dimensional Julia and dragon sets. We 'll get into
the deta i l s of t h i s later; first we have to become fam i l i ar w ith how the
mathematics of quaternions works.
307
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
where J!.g_and p_x_q are the vector dot product and vector cross product
respectively as defined in any text on vector analysis. This expression has two
scalar terms (which added give one scalar) and three three-dimensional vector
terms (which added give one three-dimensional vector). The result consists of a
scalar and a three-dimensional vector (which is a quaternion) so that the product
of two quaternions is a quaternion. Note that since one of these terms is not
commutative (J! x g_ = - g_ x J!) , the quaternion multiplication is also not
commutative. Next, we define the conjugate of a quaternion, Q* . The conjugate
of the quaternion Q =qo + q is defined as Q* = qo - q. Applying the rule for
quaternion multiplication, we find that:
(Equation 1 6-9)
(Equation 1 6- 1 0)
308
Q U AT E R N I O N S A N D T H E I R M AT H E M AT I C S
= q()! - (Q . r) + (g x r) (Equation 1 6- 1 1 )
Similarly,
Note that the dot product ordinarily produced by the multiplication drops
out, since our definition states that is perpendicular to g , making the dot
.s_
product of the pair zero. Since the result of our multiplication therefore does not
have a constant term, it is a vector, rather than a quaternion. The magnitude of
liQ is:
(Equation 1 6- 1 4)
(Equation 1 6- 1 5)
309
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
Thus the portion of Equation 1 6- 1 4 that is under the square root sign drops
out, which means that the magnitude of ii. is unchanged. Let 's look at Figure 1 6-
1 to see what the multiplication means geometrically. Suppose that ii. is in the
plane of the paper and that g is directed inward, perpendicular to the plane of the
paper. Since the cross product is perpendicular to both vectors, ii. x g is also in
the plane of the paper. The resultant, ii.Q is thus a rotation of s about the axis that
is defined by g. S ince the magnitude of ii. remains the same; it is a rotation only,
with no scaling. The amount of this rotation is tan - 1 l gl/q0. The direction of
rotation is that of a left-handed screw in the direction g. (Incidentally, if we
perform the multiplication Qii. instead of ii.Q, the only difference is that the
rotation is in the opposite direction.)
1Q = Q1 = q ol - (g . 1) (Equation 1 6- 1 6)
Q* 1Q = q o21 + g(g 1)
· (Equation 1 6- 1 7)
g(g . 1) = l gl 1 (Equation 1 6- 1 8)
Q* !Q = ! (Equation 1 6- 1 9)
31 0
Q U AT E R N I O N S A N D T H E I R M AT H E M AT I C S
Thus, this operation leaves l unchanged, resolving our worries about that
component of vector. Now we have to make sure that this operation does
nothing drastic to the s_ component. It turns out that pre-multiplication by Q* is
exactly the same as post-multiplication by Q, which means that the total effect is
to rotate s_ around g by twice the angle tan - 1 l gl /q0. So the operation Q*rQ can
be used to perform the rotation from one coordinate system to another without
any singularities occurring. An advantage is that the components of g are the
same in either coordinate system, so that the expression of the components of g
is independent of the coordinate system selected.
qo.s.
into paper
31 1
C H A PT E R 1 7
Quaternion Mathematics
with C++
In this chapter, we ' ll look in some detail a t using C++ t o define the class
Q u a te r n i o n of q u atern i o n s-tho s e m athe m a t i c al c u ri o s i t i e s d e s c ri b e d
theoretically in the previous chapter. A l l o f the information that is needed to
define quaternions for use in the ray-tracing of Julia sets and dragons is included
in two files. The first of these, qmath .hpp is a header file which contains the
definition of the class. It is listed in Figure 1 7- 1 . The second file, qmath .cpp,
contains the detailed definitions of all of the functions that are contained within
the class. It is listed in Figure 1 7-2. For the quaternion programs, the vector
mathematics has also been included in the two quaternion mathematics files, so
as to make it simpler to compile, link and execute these files. Since vector
mathematics has already been described in Chapter 4, it will not be described
here.
q = Quaternion(6,7 ,8,9)
31 3
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
where q is a quaternion which takes on the real value of 6 and the i, j, and k
values of 7, 8, and 9, respectively, and we can also have:
q = Quaternion()
I* r.======-i
qma t h . h pp H e a d e r F i l e f o r Q u a t e r n i o n M a t h em a t i c s
*I l!=======!I
Vector ( ) ;
Vector ( fl oat xl . fl oat y l , fl oat z l ) ;
Vecto r ( Vector & ) ;
V e c t o r o p e r a t o r+ ( V e c t o r & ) ;
Vector ope r a t o r - ( Vector & ) ;
Vector operato r - ( ) ;
V e c t o r o p e r a t o r= ( V e c t o r & ) ;
Vector ope rator* ( V ector & ) ;
Vector ope r a t o r* ( fl oat ) ;
Vector operator l ( fl oat ) ;
fl oat ope r a t o r% ( Vector & ) ; I I Dot product
Vector operatorA ( Vector & ) ; I I C ross product
V e c t o r o p e r a t o r- ( ) ; I I N o rm a l i z e v e c t o r
Vector mi n ( Vector & l ;
Vector ma x ( Vector & ) ;
V e c t o r Ro t a t e ( f l o a t c o s l , f l o a t s i n l , f l o a t co s 2 , f l o a t s i n 2 ) ;
V e c t o r Rev_Ro t a te ( f l o a t c o s l , f l o a t s i n l , f l o a t c o s 2 , f l o a t
s i n2 ) ;
f r i e n d o s t r e a m & o p e r a t o r < < ( o s t r e a m& , V e c t o r & ) ;
314
Q U AT E R N I O N M AT H E M AT I C S W I T H C + +
I ;
c l a s s Q u a t e r n i on
{
publ i c :
fl oat rea l , i , j , k ;
Q u a t e r n i on ( ) ;
Quatern i on ( fl oat rea l l , fl oat i l , fl oat j l , fl oat k l ) ;
Q u a t e r n i on ( Qu a t e rn i on & l ;
Q u a t e r n i o n o p e r a t o r+ ( Q u a t e r n i o n & l ;
Q u a t e r n i on ope r a t o r - ( Qu a t e r n i on & l ;
Q u a t e r n i on ope r a t o r - ( ) ;
Q u a t e r n i on ope r a t o r= ( Qua t e r n i on & l ;
Q u a t e r n i on ope r a tor* ( Qu a t e rn i on & l ;
Quatern i on ope r a t o r* ( fl oa t ) ;
Quatern i on operator/ ( fl oat ) ;
Q u a t e r n i on ope r a to r / ( Qu a t e rn i on & l ;
Q u a t e r n i o n o p e r a t o r- ( ) ; / / N o rm a l i z e q u a t e r n i o n
Quatern i on s q r ( ) ;
f r i e n d o s t r e a m & o p e r a t o r < < C o s t r e a m& , Q u a t e r n i o n & l ;
f r i end fl o a t ma g ( Quaterni on& l ;
f r i e n d f l o a t m a g_s q ( Q u a t e r n i o n & ) ;
I ;
c = -a;
where both c and a are quaternions. This will only work because the - operator
31 5
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +
Now, let's look at multiplication (* ) . You can trace through the code in the
previous chapter and see how the components of each variable in the quaternion
are calculated. Remember that quaternion multiplication is not commutative,
which you can check for yourself by tracing through the code.
The code for overloading of the division operator (/) is a little misleading if
you don 't examine it carefully. There are two temporary quaternions, temp] and
temp2 . Consider the denominator to be of the form a + b, where a is the real part
of the quaternion and b is the imaginary part. We begin by setting temp] to
equal a - b, then we set temp2 to be the product of the numerator and temp] . We
then recompute temp] so that it is the product (a + b)(a - b) or a2 - b2. Because
of the non-commutative nature of quaternion multiplication, it turns out that all
of the i, j, and k terms drop out of this result, so that, although it is a quaternion,
it has only a real part. This is the denominator of a fraction which is identical to
the old one, since we have multiplied numerator and denominator by the same
thing. We now get the final form of the numerator by dividing each term of
temp2 by the real part of temp] (which is the only part there is). This is a typical
technique for performing a division in complex numbers and then transforming
so that there is no complex part in the denominator. The thing that makes this
unusual is that one would think that when the non-real part of the denominator
had several orthogonal terms, the technique would fail. Fortunately, everything
that is not real cancels out in the denominator.
31 6
Q U AT E R N I O N M AT H E M AT I C S W I T H C + +
*/
/*
Qua te rn i on on s t ru cto r s
l �������
l� �C ��������==i
========= ==========
*/
31 7
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +
Q u a t e r n i on : : Q u a t e r n i on ( )
{
rea l = 0 ;
O;
j 0;
k 0;
Q u a t e r n i on : : Q u a t e r n i on ( f l o a t rea l l , f l o a t i l , fl o a t j l , f l o a t k l )
{
rea l = rea 1 1 ;
i1;
j jl;
k kl ;
Q u a t e r n i on : : Qu a t e r n i on ( Q u a t e r n i on & a r g )
{
rea l = a rg . real ;
a rg . i ;
j a rg . j ;
k a rg . k ;
I* r.=======;i
*/
Q u a t e r n i o n Q u a t e r n i o n : : o p e r a t o r+ ( Q u a t e r n i o n & a r g )
{
Quatern i on res ul t ;
res u l t . rea l = real + a r g . rea l ;
res ul t . i i + a rg . i ;
res u l t . j = j + a rg . j ;
res ul t . k = k + a rg . k ;
return res ul t ;
/*
Quatern i on O v e r l oad of - Ope r a t o r ( a - bl
*/
31 8
Q U AT E R N I O N M AT H E M AT I C S W I T H C + +
I*
Quatern i on Overl oad of - Operator ( - a )
Q u a t e r n i on Qua t e r n i on : : ope r a t o r - ( )
{
Q u a t e r n i on res u l t ;
res ul t . rea l = - rea l ;
resul t . i - i;
resul t . j = - j ;
res ul t . k = - k ;
return res ul t ;
I*
Q u a t e r n i on O v e r l o a d of * O pe r a t o r
( Qu a t e r n i on X a Q u a t e rn i on )
I 'f
Q u a t e r n i on Q u a t e r n i on : : o pe r a t o r* ( Q u a t e rn i on & a rg )
{
Quatern i on res u l t ;
res u l t . rea l = rea l * a rg . rea l - i * a rg . i - j * a rg . j - k *
a rg . k ;
resul t . i r e a l * a rg . i + i * a rg . r e a l + j * a rg . k k * a rg . j ;
res u l t . j = rea l * a rg . j + j * a rg . rea l + k * a rg . i - i * a rg . k ;
res u l t . k = real * a rg . k + k * a rg . rea l + i * a rg . j - j * a rg . i ;
return res ul t ;
I*
Q u a t e r n i on O v e r l oad of * Ope rator ( Quatern i on X a fl oat )
I 'f
31 9
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
Q u a te r n i on Q u a t e r n i on : : ope ra to r* ( f l oa t a rg )
{
Quatern i on res u l t ;
res ul t . rea l = real * a rg ;
res ul t . i i * a rg ;
res u l t . j = j * a rg ;
res ul t . k = k * a rg ;
return res ul t ;
/*
Q u a t e r n i on O v e r l o a d of I Ope r a t o r
( Qu a t e r n i on D i v i ded b y a Q u a t e rn i on )
*I
Q u a t e r n i on Q u a t e r n i on : : ope r a t o r / ( Q u a t e rn i on &a rg )
{
Q u a t e r n i o n t e mp l , t em p 2 , r e s u l t ;
temp l = Qua t e r n i on ( a r g . r ea l , - a r g . i , - a r g . j , - a rg . k ) ;
c o u t < < " N u me r a t o r : " < < * t h i s < < " \ n " ;
c o u t < < " D e n om i n a t o r : " < < a r g < < " \ n " ;
c o u t < < " M u l t i p l i e r : " < < t em p l < < " \ n " ;
temp2 = * t h i s * temp l ;
c o u t < < " N u me r a t o r p r o d u c t : " < < t em p 2 < < " \ n " ;
t em p l = a r g * t e m p l ;
c o u t < < " D e n om i n a t o r p r o d u c t : " < < t em p l < < " \ n " ;
res u l t . r e a l = temp2 . rea l I temp l . rea l ;
res ul t . i t e m p 2 . i I t em p l . r e a l ;
res u l t . j = temp2 . j I temp l . re a l ;
res u l t . k = temp2 . k I templ . re a l ;
return res ul t ;
/*
Quatern i on O v e r l oad of Ope rator
*/
Q u a t e r n i o n Q u a t e r n i o n : : o p e r a t o r= ( Q u a t e r n i o n & r v a l u e )
{
rea l = r v a l ue . real ;
320
Q U AT E R N I O N M AT H E M AT I C S W I T H C + +
rva l ue . i ;
j rval ue . j ;
k r v a l ue . k ;
return *thi s ;
/*
Q u a t e r n i on O v e r l o a d of - O pe r a t o r ( N o rma l i ze a Q u a t e rn i on )
*/
Q u a t e r n i o n Q u a t e r n i o n : : o p e r a t o r- ( )
{
Quatern i on res u l t ;
fl oat l ength ;
l en g t h = re a l *rea l + i * i + j *j + j *j ;
l ength = sqrt ( l ength ) ;
res ul t . rea l = rea l / l ength ;
resul t . i i / l ength ;
res ul t . j = j / l ength ;
res ul t . k = k/l ength ;
return res ul t ;
I*
I
P r i n t O u t Qua t e rn i on Contents
*/ l!========================================================!I
321
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +
/*
Functi on to squa re a Quatern i on
*I
Quatern i on Quatern i on : : s q r ( )
{
Quatern i on res u l t ;
f l o a t t em p ;
temp = 2 * rea l ;
res u l t . rea l = real * real - * i - j * j - k * k;
res ul t . i temp * i ;
res ul t . j t em p * j ;
res ul t . k temp * k ;
return ( re s u l t ) ;
/*
F u n ct i on to fi n d t h e s q u a re of t h e
ma g n i tude of a Q u a te r n i on
*/
f l o a t m a g_s q ( Q u a t e r n i o n & a r g )
{
fl oat res ul t ;
res u l t = a rg . rea l *arg . rea l + a rg . i *a rg . i ;
return res ul t ;
F u n ct i on to fi n d t h e ma g n i t ude of a Q u a t e r n i on
fl o a t ma g ( Q u a t e r n i on& a rg )
{
fl oat res ul t ;
res u l t = a rg . rea l *a rg . rea l + a rg . i *a rg . i + a rg . j * a rg . j +
a rg . k*a rg . k ;
return sqrt ( res ul t ) ;
322
Q U AT E R N I O N M AT H E M AT I C S W I T H C + +
/*
Vector Con s t ructors
*/
Vector : : Vecto r ( )
I
x =
0;
y 0;
z =
0;
y yl ;
z zl ;
=
/*
Vector O v e r l oad of + Ope r a t o r
*/
V e c t o r V e c t o r : : o p e r a t o r+ ( V e c t o r & a r g )
{
Vector resul t ;
res ul t . x x + a rg . x ;
res ul t . y =
y + a rg . y ;
res ul t . z =
z + a rg . z ;
return res ul t ;
323
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +
I * r.=======�
Vector O v e r l oad of - Operator ( a - b )
*/
res ul t . z z - a rg . z ;
=
return res u l t ;
/*
Vector O v e r l oad of - Ope r a t o r ( - a )
*/
res ul t . z - z;
=
return res ul t ;
/*
V e c t o r O v e r l o a d o f * O p e r a t o r ( V e c t o r T i me s a V e c t o r )
*I
324
Q U AT E R N I O N M AT H E M AT I C S W I T H C + +
res ul t . z z * a rg . z ;
=
return res ul t ;
*/
V e c t o r Vect o r : : ope r a t o r* ( fl o a t a rg )
{
Vector res u l t ;
res ul t . x x * a rg ;
res ul t . y = y * a rg ;
resul t . z = z * a rg ;
return res ul t ;
V e c t o r O v e r l o a d o f I O p e r a t o r ( V e c t o r D i v i d e d by a F l o a t )
*/
V e c t o r V e c t o r : : ope r a t o r / ( f l oa t a rg )
{
Vector res ul t ;
res ul t . x x I a rg ;
res ul t . y = y I a rg ;
res u l t . z = z I a rg ;
return res ul t ;
/*
Vector O v e r l oad of Ope rator
*/
325
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
V e c t o r V e c t o r : : o p e r a t o r= ( V e c t o r & r v a l u e )
{
x r v a l ue . x ;
y rva l ue . y ;
z rva l ue . z ;
return *thi s ;
/*
V e c t o r O v e r l o a d o f % O p e r a t o r ( D o t P r o d u c t o f Two V e c t o r s )
*I
I*
Vector Ove r l oad of A Ope rator ( C ro s s P roduct
of Two Vectors )
*/
V e c t o r V e c t o r : : o pe r a t o r A ( V e c t o r & a r g )
{
V e c t o r re s u l t ;
re s u l t . x y*a rg . z - z*a rg . y ;
res u l t . y = z*a rg . x - x*a rg . z ;
re s u l t . z = x*a rg . y y*a rg . x ;
ret u r n re s u l t ;
/*
V e c t o r O v e r l o a d of - Ope r a t o r ( N o rma l i z e a V e c t o r )
*/
326
Q U AT E R N I O N M AT H E M AT I C S W I T H C + +
V e c t o r V e c t o r : : o p e r a t o r- ( )
{
Vector resul t ;
fl oat l ;
l = *t h i s % *thi s ;
l = sqrt ( l ) ;
resul t . x x/l ;
res ul t . y = y / l ;
resul t . z = z/l ;
return resul t ;
/*
max Re t u r n t h e ma x i mum of t w o v e c t o r s
*I
/*
mi n Ret u r n t h e m i n i mum o f two v e c t o r s
*I
327
/
*
I�
I ========!I
Pri nt Out Vector Contents
*
/
o s t ream &ope r a t o r < < ( o s t re am& s . V e c t o r& a r g )
I
s << " ( " << a rg . x << << a rg . y <<" . " << a rg . z << " ) " ;
return s ;
328
CHAPTER 1 8
(Equation 1 8- 1 )
(Equation 1 8-2)
where both z and c are complex numbers in both equations. The results can be
plotted in the complex plane to give two-dimensional displays of unusual beauty
and i ntere s t . S i m i l ar equations c an be used to produce curves in four
dimensions, using quaternions . The corresponding equation for a quaternion
Julia set is:
(Equation 1 8-3)
(Equation 1 8-4)
where c and z are quaternions. The best we can do in plotting these curves is to
take a three-dimensional slice and project it onto our two-dimensional display.
We now have many more possibilities, since rotating the basic curve in four
dimensional space gives innumerable possible displays on the computer screen.
329
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
330
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S
The same parser, get_string , that was used for the ray tracing program is
u sed here . Refer to Chapter 8 for a description of how the parser works.
Although the parser is the same, the list of allowable inputs is quite different.
The function qin() processes the inputs from the data file, looping until the end
of the file is encountered. You will observe from the listing that the processing
for each input is rather simple. At the beginning of each loop through the
function, the function gets a string from the data file which identifies the type of
input. The function then enters a long switch routine and immediately goes to
the section for the particular input being processed. The actual processing is
very simple, usually involving getting one or more numbers in string form,
converting them to integer or floating point format, as needed, and storing the
result in the appropriate variable. The permissible input variable names and their
functions are described in the following sections.
*/
#d e f i n e B A C K G RO U N D 0
#d e f i n e AMB 1
#d e f i n e DI FF 2
#d e f i n e S R E F L E CT 3
#d e f i n e R E F L ECT 4
#d e f i n e F I L E_ N A M E 5
#d e f i n e FLIP 6
331
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
#de f i n e L I G H T_P H I 7
#d e f i n e L I G H T_T H E T A 8
#d e f i n e V I EW_P H I 9
#de f i n e XRES 10
#d e f i n e Y RES 11
#de f i n e XMAX 12
#d e f i n e XMI N 13
#d e f i n e Y MA X 14
#d e f i n e YMI N 15
#d e f i n e ZMAX 16
#d e f i n e ZM I N 17
#d e f i n e Q U AT E R N I O N 18
#de f i n e M A X_S I Z E 19
#d e f i n e M A X _ I T E RAT I O N S 20
#d e f i n e JULIA 21
#d e f i n e D RA G O N 22
#d e f i n e Nul l 23
#d e f i n e l a s t_n o 24
v o i d c om p u t e_c o l o r ( c h a r F i l e N a me [ 3 2 J ) ;
V e c t o r I n t e n s i ty ( i n t i . i n t j ) ;
i n t g e t_s t r i n g ( c h a r s t r i n g_b u f [ J ) ;
i nt q i n ( voi d ) ;
/*
Ma t h Defi n i t i on s
*I
Backg round
This denotes a vector that represents the red, green, and blue components of
the background color of the picture. The program is set up so that when the
height of any pixel is equal to zero, that pixel is painted in the background color.
332
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S
/*
*/
V e c t o r g e t_v e c t o r ( v o i d )
Q u a t e r n i o n g e t_q u a t e r n i o n ( v o i d )
i nt qi n ( voi d )
{
i n t Ty p e ;
333
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
Ty p e g e t_s t r i n g ( s t r i n g_b u f ) ;
s w i t c h ( Ty p e )
{
c a s e BACKGROUND :
backg round vector ( ) ;
brea k ;
c a s e AMB :
amb i e n t g e t_v e c t o r ( ) ;
b rea k ;
case D I F F :
di ffu s e g e t_v e c t o r ( ) ;
brea k ;
case SREF LECT :
g e t_s t r i n g ( s t r i n g_b u f ) ;
b = a t o i ( s t r i n g_b u f ) ;
brea k ;
c a s e REFLECT :
s pecul a r g e t_v e c t o r ( ) ;
brea k ;
c a s e F I L E_ N AM E :
g e t_s t r i n g ( s t r i n g_b u f ) ;
s t r c py ( O b j e c t F i l e , s t r i n g_b u f ) ;
brea k ;
case FLI P :
g e t_s t r i n g ( s t r i n g_b u f ) ;
F l i p = a t o i ( s t r i n g_b u f ) ;
brea k ;
c a s e L I G H T_ P H I :
g e t_s t r i n g ( s t r i n g_b u f ) ;
L i g h t P h i = a t o f ( s t r i n g_b u f ) ;
Li g h t P h i *= 0 . 0 1 7453925 ;
brea k ;
c a s e L I G H T_T H E T A :
g e t_s t r i n g ( s t r i n g_b u f ) ;
L i g h t T h e t a = a t o f ( s t r i n g_b u f ) ;
Li g h tTheta *= 0 . 0 1 7453925 ;
brea k ;
c a s e V I E W_ P H I :
g e t_ s t r i n g ( s t r i n g_b u f ) ;
V i e w P h i = a t o f ( s t r i n g_b u f ) ;
V i ewP h i *= 0 . 0 1 74539 2 5 ;
334
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S
b rea k ;
case XRES :
g e t_s t r i n g ( s t r i n g_b u f ) ;
X res a t o i ( s t r i n g_b u f ) ;
=
brea k ;
case Y RES :
g e t_s t r i n g ( s t r i n g_b u f ) ;
Y res a t o i ( s t r i n g_b u f ) ;
=
brea k ;
c a s e XMAX :
g e t_s t r i n g ( s t r i n g_b u f ) ;
Xmax = a t o f ( s t r i n g_b u f ) ;
brea k :
case XMI N :
g e t_s t r i n g ( s t r i n g_b u f ) ;
Xmi n = a t o f ( s t r i n g_b u f ) ;
brea k ;
case YMAX :
g e t_s t r i n g ( s t r i n g_b u f ) ;
Ymax = a t o f ( s t r i n g_b u f ) :
brea k ;
case YMI N :
g e t_s t r i n g ( s t r i n g_b u f ) ;
Ymi n = a t o f ( s t r i n g_b u f ) ;
brea k ;
c a s e ZMAX :
g e t_s t r i n g ( s t r i n g_b u f ) ;
Zma x = a t o f ( s t r i n g_b u f ) ;
brea k :
case ZMI N :
g e t_s t r i n g ( s t r i n g_b u f l :
Zmi n = a t o f ( s t r i n g_b u f ) ;
b rea k :
c a s e Q U AT E R N I O N :
c = g e t_q u a t e r n i o n ( ) ;
b rea k :
c a s e M A X_S I Z E :
g e t_s t r i n g ( s t r i n g_b u f ) :
d i v e r g e n c e_bo u n d a ry = a t o f ( s t r i n g_b u f ) ;
brea k :
c a s e M A X_ I T E RAT I O N S :
335
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
g e t_s t r i n g ( s t r i n g_b u f ) ;
m a x_i t e r a t i o n s = a t o i ( s t r i n g_b u f ) ;
brea k ;
case JULIA:
fl ag = O ;
brea k ;
c a s e D RA G O N :
fl ag = l ;
brea k ;
case Nul l :
brea k ;
defa ul t :
c o u t < < " I l l e g a l i n p u t p a r a m e t e r ty p e "
« Type « " buffe r : · "
« s t r i n g_b u f « " · . \ n " ;
ex i t ( O ) ;
fcl o s e ( fget ) ;
I*
g e t_s t r i n g ( ) Re a d s a s t r i n g o f d a t a f r om f i l e
*I
i n t g e t_s t r i n g ( c h a r s t r i n g_b u f [ J )
I
char ch ;
i nt fl a g = O , i , resul t , test ;
s t r i n g_b u f [ O J =NULL ;
r e s u l t = l a s t_n o ;
w h i l e ( ! feof ( fget ) )
{
c h = touppe r ( fgetc ( fget ) ) ;
i f ( fl ag 0)==
I
i f ( ( i s a l n um ( c h ) ) 1 1 ( c h . . l I I (ch .-. )
.
I I ( ch == . l. ll
336
J U L I A S E T S A N D D R A G O N S IN Q U AT E R N I O N S
s t r i n g_b u f [ O J ch :
brea k :
el se
{
i f ( ch -- .{.)
fl ag = 1 ;
el se
.
i f ( c h == . } )
fl ag = 0 :
f o r ( i = l : i < 3 2 : i ++ )
{
.
i f ( c h == ) ) .
{
s t r i n g_b u f [ l ] NULL :
brea k ;
s t r i n g_b u f [ i ] = c h ;
el se
!
s t r i n g_b u f [ i ] NULL ;
brea k ;
f o r ( i =O ; i < l a s t_n o : i ++ )
!
i f ( s t r c m p ( s t r i n g_b u f , s t r i n g_ty p e s [ i ] ) 0)
!
res ul t = i :
brea k :
I*
337
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
g e t_v e c t o r ( ) G e t v e c t o r f r om t h e f i l e
*I
V e c t o r g e t_v e c t o r ( v o i d )
{
Vector res ul t ;
g e t_s t r i n g ( s t r i n g_b u f ) ;
res ul t . x = a t o f ( s t r i n g_b u f ) ; g e t_s t r i n g ( s t r i n g_b u f ) :
resul t . y = a t o f ( s t r i n g_b u f ) ;
g e t_s t r i n g ( s t r i n g_b u f ) ;
res ul t . z = a t o f ( s t r i n g_b u f ) :
return ( resul t ) ;
I*
g e t_q u a t e r n i o n ( ) G e t Q u a t e r n i o n f r om t h e f i l e
*I
Q u a t e r n i o n g e t_q u a t e r n i o n ( v o i d )
I
Quatern i on resul t :
g e t_s t r i n g C s t r i n g_b u f ) :
resul t . real = a t o f ( s t r i n g_b u f ) ;
g e t_s t r i n g ( s t r i n g_b u f ) ;
res ul t . i = a t o f ( s t r i n g_b u f ) :
g e t_s t r i n g ( s t r i n g_b u f ) ;
resul t . j = a t o f ( s t r i n g_b u f ) :
g e t_s t r i n g ( s t r i n g_b u f ) ;
res ul t . k = a t o f ( s t r i n g_b u f ) :
ret u r n ( resul t ) :
338
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S
AMB
This denotes a vector that represents the color of ambient light which strikes
the quaternion object. This is the color that will appear on parts of the object
that are entirely shielded from the light source. It must be followed by one or
more non-string type characters, and be followed by three numbers (separated by
one or more non-string type characters) which are between zero and one.
DIFF
This denotes a vector that is the diffuse color of the object. This is the
inherent color of the object, which is sent to the observer when a light source
strikes the object. It must be followed by one or more non-string type characters
followed by three numbers (separated by one or more non-string type characters)
which are between zero and one.
SREFLECT
This denotes an integer that is the power used in computing Phong shading
of a curved object. It must be followed by one or more non-string type
characters, followed by an integer.
REFL ECT
This denotes a vector that represents the color of reflected light from the
quaternion object when the Phong shading is computed. It must be followed by
one or more non-string type characters followed by three numbers (separated by
one or more non-string type characters) which are between zero and one.
FI L E NAM E
This denotes a string that is the name of the file (without extension) which is
used for storage of intermediate results. The quater.cpp program generates a z
buffer file which it stores in filename.zbf, where filename is the name you
assigned using this command. The qrender.cpp file stores the color data in a file
named filenam e . raw. It must be followed by one or more non-string type
characters, followed by a string of no more than eight characters selected from
those characters which are acceptable as part of a DOS file name.
339
F R A C TA L P R O G R A M M I N G A N D R AV T R A C I N G W I T H C + +
FLI P
This denotes an integer that determines if the display will be flipped over in
the vertical direction. It must be followed by one or more non-string type
characters, followed by either a zero if the display is not to be flipped, or a one if
the display is to be flipped.
z p li ght
.·
y
V i ew i n g P l a n e
LIG HT_PHI
This denotes an integer that represents the angle in degrees of the light
source around the z (height) axis. The geometry of the situation is shown in
Figure 1 8-3. It must be followed by one or more non-string type characters,
followed by an integer.
340
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S
LIG HT_THETA
This denotes an integer that represents the angle in degrees of the light
source off the z (height) axis. The geometry of the situation is shown in Figure
1 8-3. It must be followed by one or more non-string type characters, followed
by an integer.
V I EW PHI
This denotes an integer which represents the angle in degrees of the x-y
plane with respect to the viewing plane. It must be followed by one or more
non-string type characters, followed by an integer.
XRES
This denotes an integer which represents the resolution of the display in
pixels in the horizontal direction. In the quaternion programs, this should be the
number of the maximum column in the x direction. As there is also a zero pixel,
the number is one less than the number of screen columns. It must be followed
by one or more non-string type characters, followed by an integer.
Y RES
This denotes an integer which represents the resolution of the display in
rows in the vertical direction. In the quaternion programs, it represents the
number of the last row. Since there is also a zero row, the number is one less
than the actual row resolution of the screen. It must be followed by one or more
non-string type characters, followed by an integer.
XMAX
This denotes a floating point number which represents the maximum value
of the real part of the quaternion for which computations are to be made. It must
be followed by one or more non-string type characters, followed by a floating
point number.
XMIN
This denotes a floating-point number which represents the minimum value
341
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
of the real part of the quaternion for which computations are to be made. It must
be followed by one or more non-string type characters, which must be followed
by a floating-point number.
Y MAX
This denotes a floating-point number which represents the maximum value
of the i part of the quaternion for which computations are to be made. It must be
followed by one or more non-string type characters, followed by a floating point
number.
Y MIN
This denotes a floating-point number which represents the minimum value
of the i part of the quaternion for which computations are to be made. It must be
followed by one or more non-string type characters, followed by a floating-point
number.
ZMAX
This denotes a floating-point number which represents the maximum value
of the j part of the quaternion for which computations are to be made. It must be
followed by one or more non-string type characters, followed by a floating point
number.
ZMIN
This denotes a floating-point number which represents the minimum value
of the j part of the quaternion for which computations are to be made. It must be
followed by one or more non-string type characters, followed by a floating-point
number.
QUATERNION
T h i s denotes the c o n stant quatern i o n w h i c h is u s e d in the iterated
calculations. It must be followed by one or more non-string type characters,
followed by four numbers (separated by one or more non-string type characters).
342
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S
MAX_SIZE
This denotes the floating-point number which is the size of the specialized
square of the iterated quaternion which is considered to be the divergence
boundary. When the quaternion reaches this value, it is considered to have
diverged and no further iterations are performed. It must be followed by one or
more non-string type characters, followed by a floating-point number.
MAX_ITERATIONS
J ULIA
This indicates that a quaternion Julia Set is to be computed.
DRAGON
This indicates that a quaternion dragon curve is to be computed.
I*
C++ Q u a t e r n i o n F r a c t a l G e n e r a t o r
Jul i a Sets = f( q ) = q * q + c
Dra gon Cu rves f(q) = c * q * (q - 1)
By R o g e r T . S t e v e n s 7 - 1 1 - 9 0
*I
343
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
voi d j ul i a ( voi d ) ;
voi d d ragon ( voi d ) ;
V e c t o r b a c k g r o u n d , a mb i e n t , d i f f u s e , s p e c u l a r ;
i nt X res , Y res , Zres ;
i nt Hei ght [800 J ;
i n t s c a l e_fa c t o r , d i v e r g e n c e_b o u n d a ry , m a x_i t e r a t i o n s , i , k , r ow
col .
n o_o f_i t e r a t i o n s . b , F l i p , f l a g , T y p e ;
f l o a t X m a x , X m i n , Y m i n , Y m a x , Z m i n , Z m a x , d x , dy , d z , x , y , z ,
del taZ .
z v a l . Z F a c t o r . L i g h t P h i , L i g h t T h e t a . V i ew P h i ;
F I LE *fs ave ;
cha r Obj ectFi l e [ 3 2 J ;
Q u a t e r n i o n q , c , q_s q ;
c h a r f i l e_ i n [ 3 2 J ;
/*
L
I
Ma i n P rogram
- ========!I
*/
ma i n ( i n t a r g c , c h a r * a rg v [ J )
{
s t r c py ( f i l e_i n , a r g v [ l ] ) ;
qi n ( ) ;
p r i n t f ( " X re s : %d Y res : %d\ n " , X res , Y res ) ;
pri ntf( "XMax : %f XMi n : %f\ n " , Xmax , Xmi n l ;
pri ntf ( "YMax : %f YMi n : %f\ n " , Ymax , Ymi n ) ;
p r i n t f ( "ZMa x : %f Z M i n : % f \ n " , Zm a x , Z m i n ) ;
strca t ( Obj ectFi l e , " . zbf" ) ;
Zres = 256 ;
q = Quater n i on ( 0 , 0 , 0 , 0 ) ;
s c a l e_fa c t o r = 32767 I Zres ;
Z Fa c t o r = ( f l o a t ) s c a l e_fa c t o r I ( 2 * ( Z m a x - Zm i n ) ) ;
fsave = f o p e n ( O b j e c t F i l e , " wb " ) ;
fw r i t e ( & X r e s , 1 , 2 , f s a v e ) ;
fw r i t e ( & Y r e s , 1 , 2 , f s a v e ) ;
fw r i t e ( & s c a l e_fa c t o r , 1 , 2 , f s a v e ) ;
344
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S
dx C f l o a t l C Xm i n - Xma x ) I X re s ;
dy C f l oa t ) ( Ym i n - Yma x ) I Y re s ;
dz ( f l o a t ) ( Zm a x - Z m i n ) I Z r e s ;
f o r C c o l =O ; c o l <=X r e s ; c o l ++ )
{
x = Xmax + col * dx ;
f o r C r ow=O ; r ow<=Y r e s ; r o w++ )
{
y = Y m a x + r o w * dy ;
d e l t a Z = 0 . 5 * C Zm a x - Z m i n ) ;
z = Zmi n ;
i f C f l a g == 0 )
j ul i a ( ) ;
el se
dragon ( ) ;
i f C n o_o f_i t e r a t i o n s < m a x_i t e r a t i o n s )
H e i g h t [ rowJ = Zmi n * Z Fa c to r ;
el se
{
z =Zma x ;
i f C f l a g == 0 )
j ul i a ( ) ;
el se
d ragon ( ) ;
i f C n o of i t e r a t i on s
m a x_i t e r a t i o n s )
H e i g h t [ r o w ] = Zma x * Z F a c t o r ;
el se
{
z -= del taZ ;
f o r ( k=O ; k < 7 ; k++ )
{
d e l t a Z *= 0 . 5 ;
i f ( f l a g == 0 )
j ul i a ( ) ;
el se
dragon ( ) ;
i f ( n o_o f_i t e r a t i o n s <
m a x_i t e r a t i o n s )
zval = z ;
z - = del taZ ;
345
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
el se
z += d e l t a Z ;
fw r i t e ( & H e i g h t , 2 , Y r e s + l , f s a v e l ;
c o u t < < " \ n P r oce s s i n g c o l umn # " < < c o l ;
cout « \n
\n"
« \n"
< " P r o c e s s i n g C om p l e t e . \n" ;
pri ntf ( " Data i n Fi l e : %12s \ n " , Obj ectFi l e l ;
cout « " \n"
..
<< " \n ;
fcl ose ( fsave ) ;
/*
j ul i a ( ) Funct i on to gen e r a te J u l i a Set
*/
voi d j ul i a ( voi d )
{
no of i terati ons = O ;
q = Ouatern i on ( x , y , z . 0 ) ;
w h i l e ( ( n o o f i te r a t i o n s < max i te r a t i o n s ) &&
( m a g_s q ( q ) < d i v e r g e n c e_bo u n d a ry ) )
q = q . sq r ( ) ;
q = q + c;
n o_o f_i t e r a t i o n s ++ ;
/*
346
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S
*/
voi d d ra gon ( voi d )
{
no of i terati ons 0;
=
q = Quatern i on ( x , y , z , 0 ) ;
w h i l e ( ( n o_of_i t e r a t i o n s < m a x_i t e r a t i o n s ) &&
( m a g_s q ( q ) < d i v e r g e n c e_b o u n d a ry ) )
q_s q = q . sq r ( ) ;
q = q q_s q ;
-
q = c * q;
n o_o f_i t e r a t i o n s ++ ;
347
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
one resolution element in the z direction are computed. The program enters a
pair of nested for loops to enable it to determine a height value for each pixel in
the xy plane. If we were going to take the simple approach, we 'd just make
another loop, this time through z, starting with the lowest value. At the first
increment where the iterated equation blew up, we 'd stop and record this value
of z in our height matrix. Unfortunately, this takes too long, so we 're going to
make use of a binary searching technique. We first perform the iterations for the
minimum value of z. If this doesn 't blow up, we try again for the maximum
value. If this doesn't blow up either, our search is over and we set the height to
the maximum value. If the maximum value causes blow up, we try again for a
value half way between the two extremes. If this blows up, we work our way
down in an increment half the size of the previous one; if it doesn't blow up, we
move upward by the same increment. In this way, we can move through 256
levels of height with only eight steps. There is one thing we need to be careful
about. After we have performed the eight sets of iterations, the last attempt either
does or does not cause blow up. If it doesn't, then it is the proper value for the
height matrix, but if it does, then the previous value of z is the one that should be
used. Therefore, we always save the previous value, so that it will be available if
we need to load it into the matrix.
The functions julia and dragon perform the quaternion iterations. A flag is
set by the input from the data program to determine which function is used. You
can easily determine that these functions iterate the equations shown above.
After a full line of the matrix has been filled with height values, this line is
written to the output file. When the program ends, it displays a message which
includes the name of the output file. The output file is then closed and the
program terminates.
348
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S
begins by transferring this file name to the variable file_in. Next it displays a title
and then zeroes the height buffer. Then qin is called to read the input data. The
program opens a file having the file name and the extension .zbf as the file from
which to read the height data, and another file having the file name and the
extension .raw as the output file for the color data. The names of these files are
displayed. Next, the values for SinViewPhi and CosViewPhi are computed for
the angle which came from the input data file. These are then used to define the
view vector. The value of the light vector is also determined. The program then
reads the values of Xres and Yres from the height file and displays them on the
screen. It then displays, "Hit any key to continue . . . " and waits for a keystroke.
The purpose of this program is to generate a file of pixel color data which
can be processed to render a 256 color-shaded display. However, for quick
observation of what is going on, the functions setMode and plot have been
included and the program thereby plots a pixel each time that it is saving the
pixel color data to a file. The data is plotted in EGA 1 6 color mode, which
makes i n tere sting, if not real i st i c , displays, and also permits you to see
something if you don't have a VGA display. The next thing that the program
does is to set the display to a graphics mode using setMode. It then continues by
reading the Scaling factor from the height file and writing it and the resolution
parameters to the color output file. Next, the program reads the first row of
height data from the height file. (The height buffer contains room for two rows
of data, which are needed in determining the normal surface vector. Modulus
arithmetic is used to define the height array addresses from here on, so that as
each row i s c ompleted , a new row of height data is read into the buffer,
overwriting the one that is no longer needed.) The program now enters a pair of
nested for loops, which, for each column, scan an entire row, performing the
necessary processing. At the beginning of each pass through the column loop,
the program reads another row of height data.
The next thing that the program does is to compute the first point. It does
this by taking the first height value together with its x and y coordinates and,
making use of the viewing angle, projecting it onto the viewing plane. The
349
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
resulting y v alue i s also set as the horizon. Before proceeding further, the
program sets all of the values of the red, green, and blue column arrays to the
background color. Next, the program loops through the column, from bottom to
top; at each pass through the loop, the appropriate height value is projected onto
the viewing plane. If it is above the horizon, the intensity of the color at that
point is obtained and, if the height is greater than zero, the color is stored in the
color arrays for the projected row value. At the same time, the function Pixel
plots two adjacent columns with the color which is the green color value divided
by three. If you aren 't interested in the instantaneous EGA plot, you can remove
this and the next call to Pixel, and the program will then only generate the color
data file. The program then finds the intensity of the color of the next value in
the column that is to be plotted. Since this is projected onto the viewing plane,
the next value may not be the adjacent pixel of the screen display. If this is the
case, the program interpolates between the colors of the two pixels to fill in the
pixels that were skipped due to projection. Each new pixel value is saved to the
output file and displayed on the instantaneous display. When the end of the row
loop is reached, the column number is written out to the color data file, followed
by the whole column of red data, the column of green data, and the column of
blue data. The program then loops through the next column. After all columns
have been processed, an output message is displayed which includes the name of
the color output data file. Both input and output files are then closed and the
program terminates.
/*
Z - Bu ffe r Rende r i ng P ro g r a m
Rog e r T . S t e v e n s 7 - 24 - 9 0
*/
voi d cl s ( i nt col o r ) ;
voi d pl ot ( i nt x , i nt y , i nt col o r ) ;
v o i d s e tMode ( i n t mod e ) ;
350
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S
c h a r Obj ect Fi l e [ 3 2 J ;
c h a r f i l e_i n [ 3 2 J ;
i n t X r e s , Y r e s , Z r e s =2 5 5 ;
i nt Hei ght [ 2 ] [800 J ;
i n t S c a l i n g , m a x_c o l o r= 6 3 , m a x_i t e r a t i o n s , f l a g ;
V e c t o r v i ew ; I I g l o b a l v i ew v e c t o r
Vector l i ght ; I I g l oba l l i g ht vector
f l o a t V i ew P h i , V i ewT h e t a , S i n V i ew P h i , C o s V i ewP h i , L i g h t P h i ,
Li ghtTheta ,
X m a x , X m i n , Y m a x , Y m i n , Z m a x , Z m i n , d i v e r g e n c e_b o u n d a ry ;
F I LE *fget , *fsave ;
i n t m , i , j , k , p , pO , p l , h o r i z o n ;
V e c t o r P i x , n ew P i x , o l d P i x ;
f l o a t h , t e mp ;
c h a r F i l eNameOut [ 3 2 J ;
i nt Ti l t . Fl i p ;
V e c t o r ambi e n t ; I I p e r c en t a g e o f amb i e n t l i g ht
V e c t o r d i f f u s e ; I I p e r c e n t a g e o f d i f f u s e l i g h t f r om r e f l e c t i o n
gra i nul a r
V e c t o r s p e c u l a r ; I I p e r c e n t a g e o f s p e c u l a r l i g h t f r om r e f l e c t i o n -
Eucl i di an }
Vector bac kg round ;
i nt b = 2 ; I I shi ni ness
i n t Ty p e , t y p e , i n t e g e r :
c h a r red [ 80 0 ] , g r een [ 800 J , b l ue [ 800 J ;
Quatern i on c ;
I*
Ma i n Program
*I
ma i n ( i n t a r g c , c h a r * a rg v [ J )
{
s t r c py ( f i l e_i n , a r g v [ l ] ) ;
p r i n tf ( " Z - Buffer Rende ri ng P rogram\n \ n " ) ;
f o r ( i =O ; i < 2 ; i ++ )
f o r ( j =O ; j <=Y r e s ; j ++ )
Hei ght[ i ] [j ] O;
351
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
qi n ( ) ;
s t r c py ( F i l e N a m e O u t , O b j e c t F i l e ) ;
strcat ( Obj ectFi l e , " . zbf" ) ;
s t r c a t ( F i l e N a meO u t , " . raw " ) ;
cout << "\nSa v i ng " << Fi l eNameOut << " \ n " ;
f s a v e = f o p e n ( F i l e N a me O u t , " w b " ) ;
cout << " \ n load i ng " << Obj ectFi l e << " \ n " ;
fget = fopen ( O bj e c t F i l e , " rb " ) ;
S i n V i ew P h i= s i n ( V i ew P h i ) ;
C o s V i ew P h i = c o s ( V i ew P h i ) ;
v i ew = V e c t o r ( O , - C o s V i e w P h i , S i n V i ew P h i ) ;
l i g ht = Vector ( s i n ( Li g h tTheta ) * cos ( L i g h t P h i ) ,
s i n ( Li ghtTheta ) *
s i n ( L i g h t P h i ) , c o s ( L i g h t T i� e t a ) ) ;
fget = fopen ( Obj ect F i l e , " r b " ) ;
frea d ( &Xres , 2 , 1 , fget ) ;
frea d ( &Y res , 2 , 1 , fget ) ;
c o u t < < " Re s o l u t i o n i s " < < X r e s < < " p i x e l s by " < < Y r e s < < "
r ow s . \ n " ;
c o u t « " H i t a ny k e y t o c o n t i n u e . . . \ n " ;
s etMode ( OxO E ) ;
f r e a d ( &Sc a l i n g , 2 , 1 , fge t ) ;
fw r i t e ( & X r e s , 2 , 1 , f s a v e ) ;
fw r i t e ( & Y r e s , 2 , 1 , f s a v e ) ;
fw r i t e ( & S c a l i n g , 2 , 1 , f s a v e ) ;
fre a d ( &Hei g h t [ O J [ O J , 2 , Y res+l , fget ) ;
f o r ( i =O ; i < ( X r e s - 1 ) ; i ++ )
{
f r e a d ( &H e i g h t [ ( i +l ) % 2 J [ O J , 2 , Y r e s+l , fget ) ;
pO = ( f l o a t ) Z r e s * ( ( H e i g h t [ i % 2 J [ O J I ( f l o a t ) Sc a l i n g ) *
C o s V i ew P h i ) ;
h o r i z o n = pO ;
f o r ( j =O ; j < Y r e s ; j ++ )
I
r e d [ j ] = b a c k g r o u n d . x * m a x_c o l o r ;
g reen [ j ] = b a c k g r o u n d . y * m a x_c o l o r ;
b l u e [ j ] = b a c k g r o u n d . z * m a x_c o l o r ;
f o r ( j = l ; j < Y r e s ; j ++ )
{
p l = ( f l o a t ) Z r e s * ( ( j I ( ( f l o a t ) Z r e s ) ) * S i n V i ew P h i +
( He i g ht [ i % 2 J [j ] I ( fl oat ) Sca l i ng ) *
352
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S
C o s V i ew P h i ) ;
i f ( p l > hori zon )
{
o l d P i x = I n t e n s i ty ( i , j ) ;
Pi xel ( i , pl , ol dPi x . y /3 ) ;
i f ( H e i g h t [ i % 2 ] [ j ] ! =0 )
{
red [ p l J = ol d P i x . x ;
g reen [ p l J = ol d P i x . y ;
bl ue[pl J = ol dPi x . z ;
el se
{
r e d [ p l J = b a c k g r o u n d . x *m a x_c o l o r ;
g r e e n [ p l J = b a c k g r o u n d . y * m a x_c o l o r ;
b l u e [ p l ] = b a c k g r o u n d . z * m a x_c o l o r ;
p pl - l ;
n ew P i x = I n t e n s i ty ( i , j - 1 ) ;
whi l e ( p > hori zon )
{
h = ( f l o a t ) ( p - p O ) I ( f l o a t ) ( p l - pO ) ;
P i x = ( ( o l d P i x * h ) + ( n ew P i x * ( 1 -
h ) ) ) / m a x_c o l o r ;
Pi xel ( i , p , Pi x . y/3 ) ;
i f ( H e i g h t [ i % 2 ] [ j ] ! =0 )
{
red [ p ] = Pi x . x ;
g reen [ p ] = Pi x . y ;
bl ue [ p ] = P i x . z ;
el se
{
r e d [ p J = b a c k g r o u n d . x*ma x_c o l o r ;
g r e e n [ p ] = b a c k g r o u n d . y *ma x_c o l o r ;
b l u e [ p ] = b a c k g r o u n d . z * m a x_c o l o r ;
p- ;
hori zon pl ;
pO pl ;
353
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
fw r i t e ( & i , 2 , 1 , f s a v e ) ;
fw r i t e ( & r e d [ O J , 1 , Y r e s + l , f s a v e ) ;
fw r i t e ( & g r e e n [ O J , l , Y r e s + l , f s a v e ) ;
fw r i t e ( & b l u e [ O J , l , Y r e s + l , f s a v e ) ;
getch ( ) ;
cout « \n \n"
« .. \n"
« .. P r o c e s s i n g C om p l e t e . \n" ;
pri ntf ( " Data i n Fi l e : %12s \ n " , F i l e NameO ut ) ;
cout « " \n"
« .. \n" ;
fc l o s e ( fget ) ;
fcl ose ( fsave ) ;
/ * r.===
====a
pl ot ( ) =Pl ots a poi n t a t ( x , y ) i n col or
f o r E n h a n c e d G r a p h i c s Ad a p t e r . u s i n g T u r b o C p o r t
output funct i on s
*/
voi d pl ot ( i n t x . i n t y , i nt col o r )
{
#d e f i n e d a t a O u t ( r e g , v a l u e ) { outp( Ox3C E . reg ) ; \
outp ( Ox3C F . va l ue ) ; I
#d e f i n e E G A a d d r e s s O x A O O O O O O O L
u n s i g n e d c h a r m a s k , d ummy ;
c h a r f a r * c o l o r_a d d r e s s ;
c o l o r_a d d r e s s = ( c h a r f a r * ) ( E GA a d d r e s s +
( ( l o n g l y * 80 L + ( ( l on g ) x I B L ) ) ) ;
ma s k = Ox80 > > ( x % 8 ) ;
d u mmy = * c o l o r_a d d r e s s ;
dataOut ( O , col o r ) ;
d a t a O ut ( l , OxO F l ;
data0ut ( 3 , 0 ) ;
d a t a 0 u t ( 8 , ma s k ) ;
* c o l o r_a d d r e s s &= O x F F ;
dataOut ( O , O l ;
354
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S
dataOut ( l , 0 ) ;
data0ut ( 3 , 0 ) ;
data0ut ( 8 , 0xFF ) ;
/*
setMode ( ) Sets V i deo Mode
*/
u n i on REGS reg ;
v o i d s etMode ( i n t mode )
{
reg . h . a h = O ;
re g . h . a l = mode ;
i nt86 ( Ox l O , & reg , & reg ) ;
/*
Pi xel ( ) p l o t s two a d j a c ent p i x e l s on s c reen
*/
/*
I n t e n s i ty ( ) F i n d s l i g h t i n t e n s i ty a t a p o i n t
*/
V e c t o r I n t e n s i ty ( i n t i . i n t j )
{
V e c t o r n l . n 2 , d i f f e r e n c e , n o r m a l . r e f l e c t e d . t emp ;
fl oat CosTheta . CosAl pha ;
355
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
356
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S
If this angle is less than zero, we return the ambient light value. This is the light
from the object surface when it is not directly illuminated by the light source. If
the angle is greater than zero, the color of the pixel is made up of the sum of
three components. The first is the ambient color, the second is the diffused
color multiplied by the cosine of the angle theta, and the third is the specular
reflection. To find this, first find the reflected vector, which is the vector which
is the difference between the light vector and the normal vector multiplied by
twice the cosine of theta. Then take the cosine of the angle between the reflected
vector and the viewing vector and raise it to a power that is specified in the input
data fi l e . This i s the Phong shading mode l . You may select the power
(SREFLECT in the input data file) to give the kind of highlights that you desire.
The result of this operation multiplied by the specified reflected color gives you
the third component of pixel color.
/*
quadproc P r o g r a m t o P r o c e s s V GA C o l o r D a t a f o r
Quaterni ons
*/
#i n c l ude <dos . h>
#i n c l ude < s t d i o . h >
voi d g o t o xy ( i n t x , i n t y ) ;
voi d pl ot ( i n t x , i n t y , i nt col or ) :
voi d s etMode ( i n t mode ) ;
voi d s e t V GA p a l e t t e ( u n s i g n e d c h a r * b u f f e r ) :
357
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
typed ef s t r u c t
{
c h a r Red ;
cha r G reen ;
cha r Bl ue ;
RGB ;
e n um { r e d =O , g r n = l , b l u=2 ) ;
u n i on REGS reg ;
st ruct SREGS i n reg ;
i n t i , k , x r e s , y r e s . l a s t_c o l o r . s c a n l i n e , r l , r 2 , g l , g 2 , b l , b 2 ;
u n s i g n e d c h a r r [ M A X X R E S J , g [ MA X X R E S J , b [ MA X X R E S J ;
F I L E * f i l e_l ;
u n s i g n e d c h a r f a r * c o l o r_h i s t ;
l o n g i n t c o l o r_n o ;
u n s i g n ed i n t j ;
u n s i g n e d c h a r f r e q u e n cy [ 8 1 9 2 J ;
u n s i g n ed i n t h u e s [ 8 1 9 2 J ;
v o i d ma i n ( a r g c , a rg v )
i nt a rgc ;
c h a r *a rg v [ J ;
i nt i ndex ;
i nt rgbi ndex ;
i nt xl ;
u n s i g n e d i n t d l , t e m p_d ;
unsi gned cha r d2 ;
358
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S
s etMode ( 3 ) ;
i f ( a rgc ! = 2 )
{
p r i n t f ( " V GA C o l o r P r o c e s s o r f o r Q u a t e r n i o n s by "
" Roge r Steven s \ n " ) ;
p r i n t f ( " U s a g e : % s f i l e n a me . RAW \ n " , a r g v [ O J ) ;
ex i t ( l ) ;
i f ( ( f i l e_ l = f o p e n ( a r g v [ l J , " r b " ) ) == N U L L )
{
p r i n t f ( "Cou l dn ' t open fi l e %s \ n " , a rg v [ l ] ) ;
exi t ( l ) ;
c o l o r_h i s t = f a r m a l l o c ( 3 2 7 6 8 ) ;
f o r ( i =O ; i < 2 5 6 ; i ++ )
{
P a l _A r r a y [ i J [ r e d J O;
P a l _A r r a y [ i J [ g r n J 0;
P a l _A r r a y [ i J [ b l u J 0;
f o r ( j =O ; j < 3 2 7 6 8 ; j ++ )
c o l o r_h i s t [ j ] = 0 ;
xres = y res = O ;
f r e a d ( & x r e s . s i z e o f ( i n t ) , l , f i l e_l ) ;
f r e a d ( &y r e s , s i z e o f ( i n t ) , l , f i l e_l ) ;
p r i n t f ( " V GA c o l o r p o s t - p r o c e s s o r f o r Q u a t e r n i o n s by "
" Rog e r Steven s \ n " ) ;
p r i n t f ( " I m a g e f i l e r e s o l u t i o n i s : % d by % d \ n " , x r e s , y r e s ) ;
f o r ( i =O ; i < 2 5 6 ; i ++ )
{
P a l _A r r a y [ i J [ r e d J O;
P a l _A r r a y [ i J [ g r n J O;
P a l _A r r a y [ i J [ b l u J O;
xl = O ;
pri ntf( "Col l ecti ng col or data [ ]") ;
w h i l e ( ! f e o f ( f i l e_l ) )
{
f r e a d ( & s c a n l i n e , s i z e o f ( i n t ) , l , f i l e_l ) ;
i f ( s c a n l i n e >= x r e s )
{
p r i n t f ( " F a u l ty d a t a f i l e . \ n " ) ;
359
F R A CTA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
exi t ( l l :
g o t oxy ( 2 4 , 3 l ;
pri ntf( "%d" , scanl i ne l :
f r e a d ( & r [ O J , s i z e o f ( c h a r ) , y r e s + l , f i l e_l l :
f r e a d ( & g [ O J , s i z e o f ( c h a r l , y r e s + l , f i l e_l l :
f r e a d ( & b [ O J , s i z e o f ( c h a r ) , y r e s + l , f i l e_l ) ;
f o r ( i n d e x=O ; i n d e x < =y r e s ; i n d e x++ )
{
C o l o r . Re d ( r [ i ndexJ & Ox3e l ;
Col or . Green ( g [ i ndex ] & Ox3e l :
Col o r . B l ue ( b [ i ndex ] & Ox3e ) ;
c o l o r_n o = ( C o l o r . Re d » 1 ) I ( C o l o r . G r e e n «
4) I
( C ol or . B l ue << 9 ) ;
i f ( c o l o r_h i s t [ c o l o r_n o J < 2 5 5 )
c o l o r_h i s t [ c o l o r_n o ] ++ ;
x l += 1 ;
l a st col or = - 1 ;
f o r ( j =O : j < 3 2 7 6 8 ; j ++ l
{
i f ( c o l o r_h i s t [ j ] > 0 )
{
l a s t_c o l o r++ ;
h u e s [ l a s t_c o l o r J j:
f r e q u e n cy [ l a s t_c o l o r J c o l o r_h i s t [ j J ;
360
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S
f o r ( j =O ; j < 2 5 6 ; j ++ )
{
C o l o r . Re d = ( h u e s [ i ] < < l l & O x 3 E ;
Col o r . G reen = ( h ues [ i ] >> 4 ) & Ox3 E ;
C o l o r . B l ue = ( h ue s [ i ] > > 9 ) & Ox3 E ;
C o l o r 2 . Red = ( h u e s [ j ] < < l l & O x 3 E ;
Col o r 2 . Green = ( h ues [ j ] >> 4 ) & Ox3E ;
Col o r2 . B l ue = ( h ues [ j ] >> 9 ) & Ox3 E ;
t e m p_d = ( C o l o r . Red - C o l o r 2 . Re d ) * ( C o l o r . Red -
C o l o r 2 . Red ) + ( C o l o r . Green -
Col o r 2 . G reen l * ( C ol o r . Green - Col or2 . G reen l +
( Col o r . B l ue - Col o r2 . B l ue ) * ( Col or . B l ue -
Col o r2 . B l ue l ;
i f ( t em p_d < d l l
{
dl t e m p_d ;
d2 j;
f r e q u e n cy [ i ] d2 ;
f o r ( j =O ; j < 2 5 6 ; j ++ )
{
C o l o r . Re d = ( h u e s [ j J < < l l & O x 3 E ;
Col o r G reen = ( h ues [ j ] >> 4 ) & Ox3 E ;
Col o r . B l ue = ( h ues [ j ] >> 9 ) & Ox3 E ;
P a l _A r r a y [ j J [ O J C o l o r . Re d ;
P a l _A r r a y [ j J [ l J Col o r . Green ;
P a l _A r r a y [ j J [ 2 J Col o r . Bl ue ;
s e tMode ( Ox l 3 ) ;
s e t V GA p a l e t t e ( & P a l _A r r a y [ O J [ O J ) ;
f o r ( j =O ; j < 3 2 7 6 8 ; j ++ )
c o l o r_h i s t [ j ] = O ;
f o r ( j =O ; j <= l a s t_c o l o r ; j ++ )
c o l o r_h i s t [ h u e s [ j ] J f r e q u e n cy [ j J ;
r e w i n d ( f i l e_l ) ;
xl = O ;
f r e a d ( & x r e s , s i z e o f ( i n t l , l , f i l e_l l ;
f r e a d ( &y r e s , s i z e o f ( i n t ) , l , f i l e_l ) ;
w h i l e ( ! f e o f ( f i l e_l l l
{
361
F R A C TA L P R O G R A M M I N G A N D R A Y T R A C I N G W I T H C + +
f r e a d ( & s c a n l i n e , s i z e o f ( i n t ) , l , f i l e_l ) ;
i f ( s c a n l i n e >= x r e s )
l
p r i n t f ( " Fa u l ty d a t a f i l e . \ n " ) ;
ex i t ( l ) ;
f r e a d ( & r [ O J , s i z e o f ( c h a r ) , y r e s + l , f i l e_l ) ;
f r e a d ( & g [ O J , s i z e o f ( c h a r ) , y r e s + l , f i l e_l ) ;
f r e a d ( & b [ O J , s i z e o f ( c h a r ) , y r e s + l , f i l e_l ) ;
f o r ( i n d e x=O ; i n d e x <=y r e s ; i n d e x++ )
l
C o l o r . Red ( r[ i ndex] & Ox3e ) ;
Col o r . Green ( g [ i ndexJ & Ox3e ) ;
Col or . Bl ue ( b [ i ndex ] & Ox3e ) ;
c o l o r_n o = ( C o l o r . Re d » 1 ) I ( Col or . Green «
4) I
( Col or . Bl ue « 9 ) ;
p l o t ( x l , y r e s - i n d e x , c o l o r_h i s t [ c o l o r_n o ] ) ;
x l += 1 ;
getch ( ) ;
setMode ( 3 ) ;
f c l o s e ( f i l e_l ) ;
/*
setMode ( ) Sets V i deo Mode
*/
v o i d setMode ( i n t mode )
l
reg . h . a h = O ;
reg . h . a l = mode ;
i n t86 ( Ox l O , ® , ® ) ;
/*
pl ot ( ) F u n c t i on to p l ot poi n t to VGA 2 5 6 Col o r Sc reen
*/
362
J U L I A S E T S A N D D R A G O N S I N Q U AT E R N I O N S
voi d pl ot ( i nt x , i nt y , i nt col o r )
l
un s i gned i n t offset :
c h a r fa r * a d d r e s s :
offset = 320 * y + x :
a d d r e s s = ( c h a r fa r * ) ( OxAOOOOOO O L + o ffset ) :
*address = col or :
*/
v o i d s e t V GA p a l e t t e ( u n s i g n e d c h a r * b u f f e r )
l
reg . x . a x = Oxl 0 1 2 :
segread ( &i n reg ) ;
i n reg . es i n reg . d s :
reg . x . bx 0:
reg . x . cx 256 :
reg . x . dx ( i n t ) &b u f fe r [ O J :
i n t86x ( Ox l 0 , & reg , & reg , &i n reg ) ;
sort ( ) O u i c k s o r t t o s o r t c o l o r s by f r e q u e n cy
*/
v o i d s o r t ( un s i g n e d i n t s t a r t . u n s i g n ed i n t end )
l
un s i g n ed i n t pi vot . temp2 ;
u n s i g n ed c h a r temp :
i f ( s t a r t < ( end - 1 ) )
l
i = sta rt :
j = end :
p i v o t = ( f r e q u e n cy [ i ] + f r e q u e n cy [ j ] +
f r e q u e n cy [ ( i +j ) / 2 ] ) / 3 :
363
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
do
{
w h i l e ( f r e q u e n cy [ i ] > p i v o t )
i ++ ;
w h i l e ( f r e q u e n cy [ j J < p i v o t )
j-;
if (i < j)
{
t e m p = f r e q u e n cy [ i ] ;
f r e q u e n cy [ i ] = f r e q u e n cy [ j ] ;
f r e q u e n cy [ j ] = t em p ;
temp2 = hues [ i ] ;
h u e s [ i ++ J = hues [j ] ;
h u e s [ j -J = temp2 ;
whi l e ( i < j ) ;
i f ( j < end )
{
sort ( sta rt , j ) ;
s o r t ( j+l , end ) ;
i f ( f r e q u e n cy [ e n d J > f r e q u e n cy [ s t a r t ] )
{
t em p = f r e q u e n cy [ s t a r t ] ;
f r e q u e n cy [ s t a r t ] = f r e q u e n cy [ e n d ] ;
f r e q u e n cy [ e n d ] = temp ;
temp2 = hues [start J ;
hues [ s t a r t ] = hues [ end ] ;
hues [ end J = t em p 2 ;
v o i d g o t o xy ( i n t x , i n t y )
{
reg . h . a h 2·
reg . h . bh O;
reg . h . d h y-1 ;
reg . h . d l x-1 ;
i nt86 ( 0x l 0 , ® , ® ) ;
364
Appendix A:
Data Files for Ray
Tracing
Plates 4 through 1 2 were generated with the ray-tracing program. The data
fi les for these pl ates have the extension .ray. Plate s 1 3 through 1 6 were
generated with the quaternion program. The data files for these plates have the
extension .qat. The data files are listed below so that you can duplicate the color
plates. After that, you're on your own. It sometimes takes a number of tries to
determine exactly where to position each element of a picture and how large to
make it.
P l a t e 04 . r a y
P i c t u r e o f s p h e re s a n d a b r i c k wa l l
By R o g e r T . S t e v e n s 1 2 / 3 1 /89
F I L E_N A M E = W S p h e r e . RAW
PATT E R N S U S E D I
PATT E R N ( x si ze 60 , ! C H E C K E R E D G RO U N D I
y_s i z e 60 ,
n a me CHECK ,
365
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
RECTA N G L E
s t a r t_x 0.
s t a r t_y 0.
e n d_x 40 ,
e n d_y 40 ,
d i ff ( .1 ,1.0, .4) ,
di ther 0,
RECTA N G L E
s t a r t_x = 40 ,
s t a r t_y = 40 ,
e n d_x = 80 ,
e n d_y = 80 ,
d i ff ( .1,1.0, .1) ,
di ther = 0,
PATT E R N x s i z e = 80 , { PATT E R N F O R B R I C K S l
y_s i z e = 5 0 ,
n a me = BRICK,
RECTANG L E (
s t a r t_x = 0 , s t a r t_y = 2 ,
e n d_x 1 8 , e n d_y 23 ,
d i ff ( 1 . 00 , . 20 , . 20 ) ;
di ther 0,
RECTANGLE
sta rt x 6 2 , s t a r t_y = 2 ,
e n d_x 8 0 , e n d_y = 23 ,
d i ff ( 1 . 00 , . 24 , . 20 ) ;
di ther 2.
RECTA N G L E
sta rt x 2 2 , s t a r t_y = 2 ,
e n d_x 5 8 , e n d_y = 23 ,
d i ff ( . 80 , . 2 0 , . 2 0 ) ;
di ther 0,
R E C TA N G L E
sta rt x 2 , s t a r t_y = 2 7 .
e n d_x 3 8 , e n d_y = 48 ,
d i ff ( . 85 , . 35 , . 10 ) ;
366
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G
di ther 0,
RECTANGLE ( { bri ck 4 }
s t a r t_x = 4 2 , s t a r t_y = 2 7 ,
e n d_x 7 8 , e n d_y = 48 ,
d i ff ( . 70 , . 25 , . 20 ) ;
di ther 0'
P A RA L L E L O G RA M l ac - 1 0000 , 0 , - 1 0000 ) ,
vl ( 20000 , 0 , 0) ,
v2 0 , 0 , 20000 ) ,
d i ff .8, .8, 0) ,
di ther 0,
pattern = CHECK
xm u l t 2
ymul t = 2
B E G I N_B B O X
B E G I N_B B O X
SPHERE l ac = ( 2 1 0 , 55 , - 80 ) ,
ra d i u s = 40 ,
d i ff = ( . 5 , . 3 , . 5 ) ,
xm u l t = 1.5,
ymul t = 1.5
mi rror ( .9, .9, .9)
367
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
E N D_B B O X
B E G I N_B B O X
SPHERE l oc ( 2 00 , 90 , 7 0 ) ,
radi us 35 ,
d i ff ( .3 •5 . 9) .
• .
amb ( . 32 , . 32 , . 32 ) ,
refl ect . 60
s refl ect = 20
xm u l t 1.0,
ymu l t = 1.0
Q U A D RAT I C ( l o c = ( 2 0 0 , o . 7 0 ) ,
a = 1.
b = o.
c 1.
d 1 50 ,
xmi n - 13 .
xma x 13 .
ymi n 0.
ymax 90 ,
zmi n - 13 .
zma x = 1 3 ,
d i ff = ( . 1 . . 1 , . 1 ) .
mi rror = ( . 8 , . 8 , . 8 )
E N D_B B O X
END BBOX
B E G I N_B B O X
P A RA L L E L O G RA M l oc ( 1 50 , 00 , - 1 5 ) ,
vl ( 0 , 0 , 30 ) ,
v2 ( 0 , 60 , 0 )
d i ff = ( 1 , 1 . 1 ) .
pattern = B R I C K
xm u l t .5.
ymu l t = . 5
P A RA L L E L O G RA M l oc ( 1 50 , 00 , 1 5 ) - ,
vl ( 1 50 , 0 , 0 ) ,
v2 ( 0 , 60 , 0 )
d i ff = ( 1 , 1 , 1 ) ,
pattern = BRICK
368
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G
xm u l t .5,
ym u l t .5
P A RA L L E L O G RA M l oc ( 1 50 , 00 , 1 5 ) ,
vl ( 1 50 , 0 , 0 ) ,
v2 ( 0 , 60 , 0 )
d i ff (1, 1, 1),
=
pattern BRICK=
xm u l t .5, =
ymu l t .5 =
)
P A RA L L E L O G RA M ( l o c ( 1 50 , 60 , - 1 5 ) ,
=
v1 ( 0 . 0 . 30 ) .
=
v2 ( 1 50 , 0 , 0 )
=
d i ff (1, 1, 1),
=
pattern BRICK =
xm u l t .5,
ymu l t .5 =
E N D_B B O X
B E G I N_B B O X
P A RA L L E L O G RA M l oc ( 2 00 , 60 , - 1 5 ) ,
vl ( 0 , 0 , 30 ) ,
v2 ( 0 , 60 , 0 )
d i ff (1, 1. 1),
=
pattern BRICK=
xm u l t .5, =
ymu l t .5 =
P A RA L L E L O G RA M l oc ( 200 , 60 , - 1 5 ) ,
vl ( 50 , 0 , 0 ) ,
v2 ( 0 , 60 , 0 )
d i ff (1, 1. 1),
=
p a t t e rn BRICK
=
xm u l t . 5 ,
ymu l t .5=
P A RA L L E L O G RA M l oc ( 200 , 60 , 1 5 ) ,
vl ( 50 . 0 . 0 ) .
v2 ( 0 . 60 . 0 )
369
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
di ff = ( 1 , l , 1 ) ,
pattern = BRICK
xmul t .5,
ymul t = . 5
E N D_B B O X
O B S E RV E R l oc ( - 20 ' 70 , - 40 ) ,
l ookat ( 200 ' 50 ' 0 )
L A M P ( l o c = ( 1 2 0 ., 1 2 0 , - 5 0 ) '
rad i us = 5 ,
d i s t = 80
LAMP l oc = ( 1 20 ' 1 5 0 , 80 ) ,
radi us = 5 ,
di st = 70
X RES 320
Y RES 200
FOC L ENGTH 80
Pl ate 05 . ray
B y Rog e r T . S t e v e n s - 1 2 / 3 1 /89
F I L E_ N A M E C O N E 5 . RAW
=
{ PATT E R N S U S E D )
PATT E R N ( x s i z e 80 , { C H E C K E R E D G RO U N D )
y_s i z e 80 ,
370
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G
n a me = CHEC K ,
RECTANG L E (
s t a r t_x = 0,
s t a r t_y = 0,
e n d_x = 40 ,
e n d_y = 40 ,
d i ff = ( . 75 , . 25 , . 75 ) ,
di ther = O,
RECTANG L E
s t a r t_x = 40 ,
s t a r t_y = 40 ,
e n d_x = 80 ,
e n d_y = 80 ,
d i ff ( . 75 ' . 25 , . 75 ) ,
di ther = 0,
P A RA L L E L O G RA M l oc - 1 0000 , 0 , - 1 0000 ) ,
vl ( 20000 , 0 , 0) ,
v2 0 , 0 , 20000 ) ,
d i ff ( l , l , . 75 ) ,
=
di ther 0, =
pattern CHECK =
xmul t 2
ymul t 2 =
B E G I N_B B O X
SPHERE ( l oc ( 2 30 , 90 , - 7 0 ) ,
=
rad i us 30 , =
xm u l t 1 =
ymul t 1 =
CONE ( l oc ( 230 , 60 , - 7 0 ) ,
radi us 35 =
hei ght 60 =
d i ff (1, 0, 0) ,
=
)
E N D_B B O X
371
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
B E G I N_B B O X
SPHERE l oc = ( 2 20 , 90 , 50 ) ,
radi us = 30 ,
di ff ( .7' .7' .7) '
mi r ro r ( .9' .9' .9)
xm u l t 1.0'
ymu l t 1.0
CONE ( l oc = ( 2 20 , 60 , 50 ) ,
rad i us = 30
hei ght = 60
d i ff = ( 0 , 1 , 0 . 6 ) ,
)
E N D_B B O X
B E G I N_B B O X
SPHERE l oc = ( 350 , 90 , 0 ) ,
r a d i u s = 30 ,
d i ff = ( . 7 , . 7 , . 7 ) ,
xm u l t = 1
ymul t = 1
mi rror = ( . 9 , . 9 , . 9 )
CONE ( l oc = ( 3 50 , 60 , 0 ) '
rad i us = 35
hei ght = 60
d i ff = (0, 0' 1) '
)
E N D_B B O X
O B S E RV E R l oc ( - 20 ' 70 , - 40 ) ,
l oo k a t ( 2 00 , 50 , - 1 5 )
372
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G
di ther 1
X RES =320
Y RES =200
FOC L ENGTH 65
{
Pl ate 06 . ray
N e w Y o r k W o r l d ' s F a i r 1 9 3 9 - T ry l o n a n d P e r i s p h e r e
By R o g e r T . S t e v e n s - 2 / 1 8 - 9 0
F I L E N A M E = N Y W F 3 9 . RAW
PATT E R N S U S E D )
PATT E R N ( x s i z e 60 , { C H EC K E RE D GROUND )
y_s i z e 60 ,
n a me CHECK ,
RECTANGLE (
s t a r t_x 0'
s t a r t_y 0'
e n d_x 30 ,
e n d_y 30 ,
d i ff ( . 1 ,1 .0, .4) ,
di ther 0,
RECTANG L E
s t a r t_x 30 ,
s t a r t_y 30 ,
e n d_x 60 ,
e n d_y 60 ,
d i ff ( . 1,1.0, .1),
di ther 0'
373
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
B EG I N BBOX
TRI ANGLE
l oc = ( 380 , 0 , 20 ) ,
v l = ( 60 , 0 , 0 ) ,
v2 = ( 30 , 1 50 , 1 7 ) ,
d i ff = ( 1 . 0 , 1 . 0 , 1 . 0 ) ,
xm u l t 1.5,
ymul t = 1 . 5 ,
)
TRI ANGLE (
l oc = ( 380 , 0 , 20 ) ,
v l = ( 30 , 0 , 52 ) ,
v2 = ( 30 , 1 50 , 1 7 ) ,
di ff = ( 1 . 0 , 1 . 0 , 1 . 0 ) ,
xm u l t 1.5,
ym u l t = 1 . 5 ,
)
E N D_B B O X
OBSERVER l oc ( - 80 , 7 0 , - 40 ) ,
l ookat ( 2 00 , 7 0 , 0 )
! ** A l amp ** )
LAMP ( l oc = ( 0 , 1 50 , 1 20 ) ,
radi us = 5 ,
d i s t = 200
374
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G
X RES = 320
Y RES = 200
F O C L E N GT H 120
I
Pl a te 07 . ray
P i c t u r e o f Py r a m i d s i n t h e D e s e r t
By Rog e r T . Steven s - 4 / 2 2 - 90
F I L E_N A M E = Py r a m i d . RAW
B E G I N_ I N S T A N C E S
name = P Y RAM I D
BEGI N BBOX
T R I ANGLE ( l oc 0 , 0 , 0 )
vl ( 52 , 0 , 30 )
=
v2 ( 34 . 3 , 30 , 0 )
=
di ff ( . 72 , . 41 . . 14 )
=
TRIANGLE ( l QC 0 , 0 . 0 )
vl = ( 52 . 0 . - 30 )
v2 = ( 34 . 3 . 3 0 , 0 )
diff = ( . 72 . . 4 1 . . 14 )
)
T R I ANGLE ( l oc 52 , 0 . - 30 )
vl = ( 0 , 0 , 60 )
v2 = ( - 1 7 . 7 . 30 , 30 )
d i ff = ( . 72 . . 41 . . 14 )
E N D_B B O X
E N D_ I N S T A N C E S
375
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
I N S T A N C E_O F n a m e = P Y RAM I D
l ac = ( 200 , 0 , - 40 )
sca l e = ( 1 . 3 , 1 . 3 , 1 . 3 )
)
I N S T A N C E O F n a m e = P Y RAM I D
l ac = ( 1 7 0 , 0 , 80 )
sca l e = ( 1 . 2 , 1 . 2 , 1 . 2 )
)
I N ST A N C E O F n a m e = P Y RAM I D
l ac = ( 225 , 0 . 20 )
)
I N S T A N C E O F n a m e = P Y RAM I D
l ac = ( 350 , 0 . - 70 )
)
I N S T A N C E O F n a m e = P Y RAM I D
1 a c = ( 400 , 0 . 1 20 )
sca l e ( 1 . 25 , 1 . 25 . 1 . 25 )
)
I N S T A N C E O F n a m e = P Y RAM I D
l ac = ( 500 , 0 . - 60 )
)
I N S TA N C E O F n a m e = P Y RAM I D
l ac = ( 7 00 . 0 . - 1 00 )
scal e ( 1 . 25 , 1 . 25 . 1 . 25 )
I N S T A N C E O F n a m e = P Y RAM I D
l ac = ( 7 50 , 0 . 140 )
)
I N S T A N C E O F n a m e = P Y RAM I D
1 a c = ( 900 , 0 . - 80 )
scal e ( 1 . 25 , 1 . 25 . 1 . 25 )
)
I N S T A N C E O F n a m e = P Y RAM I D
-
l ac = ( 950 , 0 . 300 )
376
A P P E N D I X A : D AT A F I L E S F O R R AY T R A C I N G
I N S T A N C E_O F n a m e = P Y RAM I D
l oc = ( 1050 , 0 , 0 )
OBSERVER l oc ( - 20 , 70 , - 40 ) ,
l ookat ( 200 , 50 , 0 )
LAM P ( l oc = ( 1 2 0 , 1 8 0 , 80 ) ,
rad i us = 5 ,
di st = 70
S KY hori z = ( 0 , . 4 , . 7 ) ,
zeni th = ( 0 , . 4 , . 7 ) ,
di ther 1
X RES = 320
Y RES = 200
F O C L E N GT H 75
P l a t e 08 . ray
I n d i a n S t o ry T e l l e r
By R o g e r T . S t e v e n s - 4 / 2 2 - 9 0
F I L E N A M E = M S P H E R E 4 . RAW
OBSERVER
( l oc ( 2 . 1 00000 , 1 . 000000 , 1 . 700000 ) ,
=
377
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
XRES = 320
Y RES = 200
S KY
( ha r i z = ( 0 . 078000 , 0 . 3 6 1 000 , 0 . 7 53000 )
z en i t h = ( 0 . 078000 , 0 . 361 000 , 0 . 7 53000 )
di ther = 0
)
LAM P
( l ac = ( 4 . 000000 , 3 . 000000 , 2 . 000000 )
radi us = 5
di st = 5
)
LAM P
( l ac = ( 1 . 000000 , - 4 . 000000 , 4 . 000000 )
radi us = 5
di st = 5
)
LAM P
( l ac = ( - 3 . 000000 , 1 . 000000 , 5 . 000000 )
radi us = 5
di st = 0
)
P A RA L L E L O G RAM
( l ac ( - 1 000 , 0 , - 1 000 )
v l = ( 0 , 0 , 20000 )
v 2 = ( 20000 , 0 , 0 )
d i ff = ( 1 . 000000 , 0 . 7 50000 , 0 . 330000 ) ,
refl ect = 0 . 000000 ,
s refl ect = 0 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
B E G I N_B B O X
SPHERE
( l ac = ( 0 . 000000 , 0 . 500000 , 0 . 000000 ) ,
radi us = 0 . 500000 ,
d i ff = ( 0 . 00000 , 0 . 0000 , 0 . 850000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
378
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G
SPHERE
( l o c = ( 0 . 2 7 2 1 6 6 , 0 . 7 7 2 1 6 6 , 0 . 544 3 3 1 ) ,
rad i us = 0 . 1 66667 ,
d i ff = ( 1 . 00000 , 0 . 0000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( 0 . 4 2 0 3 1 4 , 0 . 9 2 0 3 1 4 , 0 . 6 1 84 0 5 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t ra n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( 0 . 4 6 1 844 , 0 . 8 0 4 7 0 9 , 0 . 4 3 3 2 2 0 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( 0 . 3 0 4 7 0 9 , 0 . 9 6 1 844 , 0 . 4 3 3 2 2 0 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( 0 . 2 3 0 6 3 5 , 0 . 88 7 7 7 0 , 0 . 7 2 9 5 1 6 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
379
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
SPHERE
( l ac = ( 0 . 387 7 7 0 , 0 . 7 3 0 6 3 5 , 0 . 7 2 9 5 1 6 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( 0 . 239622 . 0 . 582487 , 0 . 6 5 5442 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t ra n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac ( 0 . 4 29300 , 0 . 6 1 503 1 , 0 . 54433 1 ) ,
380
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPH E RE
( l oc = ( 0 . 6439 5 1 , 0 . 67 2546 , 0 . 000000 ) ,
radi us = 0 . 1 66667 ,
d i ff = ( 0 . 50000 , 0 . 0000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( 0 . 8 0 2 6 0 8 , 0 . 88 1 4 7 1 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPH E RE
( l oc = ( Q . 6439 5 1 . 0 . 6 7 2 546 , - 0 . 2 2 2 2 2 2 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 59 4 1 4 1 , 0 . 858439 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
381
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
SPHERE
( l ac = ( 0 . 802608 , 0 . 7 8 1 4 7 1 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 350000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( 0 . 59414 1 , 0 . 858439 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 350000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( 0 . 6439 5 1 , 0 . 6 7 2 546 , 0 . 2 2 2 2 2 2 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 350000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t ra n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( 0 . 8524 1 8 , 0 . 595579 , 0 . 000000 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 350000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t ra n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( 0 . 693760 , 0 . 486654 , 0 . 1 1 1 1 1 1 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 350000 ) ,
refl ect = 0 . 500000 ,
382
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G
383
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l a c = ( 0 . 09 5 5 7 9 , 1 . 3 5 24 1 8 , - 0 . 000000 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( - 0 . 01 3346 , 1 . 1 93760 , - 0 . 1 1 1 1 1 1 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( - 0 . 01 3346 , 1 . 1 93760 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( 0 . 28147 1 , 1 . 302608 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 509000 ,
s r e f l e c t = 3 . 0 00 0 0 0 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
384
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G
SPHERE
( l ac = ( 0 . 1 72546 , 1 . 14395 1 , 0 . 222222 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t rans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( 0 . 3 58439 , 1 . 19414 1 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t ra n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l a c = ( - 0 . 3 7 1 7 8 5 , 0 . 5 9 9 6 1 9 , 0 . 544 3 3 1 ) ,
radi us = 0 . 166667 ,
d i ff = ( 0 . 800000 , 0 . 0000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( - 0 . 39362 1 , 0 . 7 20501 , 0 . 729516 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( - 0 . 1 9 1 24 7 , 0 . 6 6 6 2 7 5 , 0 . 6 5 544 2 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
385
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
386
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( - 0 . 4 2 9 3 0 0 , 0 . 3 8 4 9 6 9 , 0 . 5 44 3 3 1 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( - 0 . 2 4 8 7 6 2 , 0 . 4 5 1 6 2 5 , 0 . 6 5 5 44 2 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 4 7 1 4 0 5 , 0 . 9 7 1 4 0 5 , 0 . 000000 ) ,
radi u s = 0 . 1 66667 ,
d i ff = ( 0 . 800000 , 0 . 0000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 508983 , 1 . 1 90426 , - 0 . 000000 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
387
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
SPHERE
( l oc = ( - 0 . 335322 , 1 . 1 07487 , 0 . 1 1 1 1 1 1 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 335322 , 1 . 1 07487 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 645066 , 1 . 0 54344 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 47 1405 , 0 . 9 7 1 405 , - 0 . 222222 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 6 0 7 4 8 7 , 0 . 83 5 3 2 2 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
388
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G
389
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i nd ex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 6439 5 1 , 0 . 327454 , 0 . 2 2 2 2 2 2 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 693760 , 0 . 5 1 3346 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 83 5 8 1 5 , 0 . 3424 5 7 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 693760 , 0 . 5 1 3346 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i f f = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
390
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G
SPHERE
( l o c = ( - 0 . 6 4 3 9 5 1 , 0 . 3 2 7 4 54 , - 0 . 2 2 2 2 2 2 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 78600 5 , 0 . 1 56 5 6 5 , - 0 . 000000 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) .
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 594141 , 0 . 141561 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) .
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 59 4 1 4 1 , 0 . 1 5 1 5 6 1 . 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 . 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( 0 . 0 9 9 6 1 9 , 0 . 1 2 8 2 1 5 , 0 . 5 44 3 3 1 ) ,
radi us = 0 . 1 66667 ,
d i ff = ( 0 . 800000 , 0 . 0000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
391
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
392
A P P E N D I X A : D AT A F I L E S F O R R AY T R A C I N G
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 00000 0 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 1 1 503 1 , 0 . 0 7 0 7 0 0 , 0 . 54433 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 1 5 3845 , - 0 . 0 7 4 1 5 9 , 0 . 6 1 8405 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 032964 , - 0 . 052323 , 0 . 433220 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 24 7 6 1 4 , 0 . 00 5 1 9 2 , 0 . 43 3 2 20 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
393
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
)
SPHERE
( l oc = ( - 0 . 1 7 2546 , - 0 . 14395 1 . 0 . 000000 ) ,
rad i us = 0 . 1 66667 ,
d i ff = ( 0 . 800000 , 0 . 0000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t rans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 1 5 7 543 , - 0 . 33581 5 . 0 . 1 1 1 1 1 1 ) .
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) .
refl ect = 0 . 500000 .
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i n d ex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 0 1 3346 , - 0 . 1 93760 , 0 . 1 1 1 1 1 1 ) .
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 1 7 2546 , - 0 . 14395 1 , 0 . 222222 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 . 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 34343 5 , - 0 . 286005 , - 0 . 000000 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
394
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G
395
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 47 1 405 , 0 . 0285 1 5 , 0 . 000000 ) ,
rad i us = 0 . 166667 ,
d i ff = ( 0 . 800000 , 0 . 0000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 69042 6 , - 0 . 008983 , 0 . 000000 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 . 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 607487 , 0 . 1 64678 , - 0 . 1 1 1 1 1 1 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 607487 , 0 . 1 64678 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
396
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G
SPHERE
( l oc = ( 0 . 5 54344 , - 0 . 145066 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 47 1405 , 0 . 028595 , 0 . 222222 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t ra n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
S P H E RE
( l oc = ( 0 . 335322 , - 0 . 1 07487 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 5 54344 , - 0 . 1 45066 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 33 5 3 2 2 , - 0 . 1 0 7 487 , - 0 . 1 1 1 1 1 1 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
397
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
SKY
( ho r i z = ( 0 . 078000 , 0 . 361 000 , 0 . 753000 )
zen i th = ( 0 . 078000 , 0 . 3 6 1 000 , 0 . 7 53000 )
di ther = 0
)
LAM P
( l oc = ( 4 . 000000 , 3 . 000000 , 2 . 000000 )
radi us = 5
di st = 5
)
LAM P
( l oc = ( 1 . 000000 , - 4 . 000000 , 4 . 000000 )
radi us = 5
di st = 5
)
LAM P
( l oc = ( - 3 . 000000 , 1 . 000000 , 5 . 000000 )
radi us = 5
di st = O
)
398
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G
P A RA L L E L O G RA M
( l oc = ( - 1 000 , 0 , - 1 000 )
v l = ( 0 , 0 , 20000 )
v 2 = ( 20000 , 0 , 0 )
d i ff = ( 1 . 000000 , 0 . 7 5 0000 , 0 . 330000 ) ,
refl ect = 0 . 000000 ,
s refl ect = 0 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
B E G I N_B B O X
SPHERE
( l oc = ( 0 . 000000 , 0 . 500000 , 0 . 000000 ) ,
rad i us = 0 . 500000 ,
d i ff = ( 0 . 00000 , 0 . 0000 , 0 . 850000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( 0 . 2 7 2 1 6 6 , 0 . 7 7 2 1 66 , 0 . 54433 1 ) ,
radi us = 0 . 1 66667 ,
d i ff = ( 1 . 00000 , 0 . 0000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 42 0 3 1 4 , 0 . 9203 1 4 , 0 . 6 1 8405 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( 0 . 4 6 1 84 4 , 0 . 8 04 7 0 9 , 0 . 4 3 3 2 2 0 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
399
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
400
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G
( l oc = ( 0 . 38 7 7 7 0 , 0 . 7 3 0 63 5 , 0 . 7 2 9 5 1 6 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) .
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( 0 . 2 3 9 6 2 2 , 0 . 582487 , 0 . 6 5 5442 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( 0 . 4 2 9 3 0 0 , 0 . 6 1 5 0 3 1 , 0 . 544 3 3 1 ) .
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 64395 1 , 0 . 672546 , 0 . 000000 ) ,
radi us = 0 . 1 66667 ,
d i ff = ( 0 . 50000 . 0 . 0000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 . 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( 0 . 8 0 2 6 0 8 , 0 . 88 1 4 7 1 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
401
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 6439 5 1 , 0 . 6 7 2 546 , - 0 . 2 2 2 2 2 2 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 . 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 594141 , 0 . 858439 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 0000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 802608 . 0 . 78147 1 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 350000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 5 94 1 4 1 , 0 . 8 58439 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 350000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 6439 5 1 , 0 . 6 7 2 546 , 0 . 2 2 2 2 2 2 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 350000 ) ,
402
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G
403
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
( l ac = ( 0 . 2814 7 1 , 1 . 302608 , - 0 . 1 1 1 1 1 1 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t ra n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l a c = ( 0 . 3 5 84 3 9 , 1 . 0 9 4 1 4 1 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( 0 . 1 7 2546 , 1 . 14395 1 , - 0 . 222222 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( 0 . 09 5 5 7 9 , 1 . 352418 , - 0 . 000000 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l ac = ( - 0 . 0 1 3346 , 1 . 1 93760 , - 0 . 1 � 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
404
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 0 1 3346 , 1 . 1 93760 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) .
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 28147 1 , 1 . 302608 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 . 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect - 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
S P H E RE
( l oc = ( 0 . 1 7 2 546 , 1 . 1 4395 1 , 0 . 222222 ) .
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t ra n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 3 58439 , 1 . 1 94 1 4 1 . 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 3 7 1 7 85 , 0 . 5996 1 9 , 0 . 54433 1 ) ,
rad i us = 0 . 166667 ,
d i ff = ( 0 . 800000 , 0 . 0000 , 0 . 00000 ) ,
405
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
406
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G
407
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = C - 0 . 47 1 405 , 0 . 97 1405 , 0 . 000000 ) ,
rad i us = 0 . 1 66667 ,
d i ff = C 0 . 800000 , 0 . 0000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = C - 0 . 508983 , 1 . 1 90426 , - 0 . 000000 ) ,
radi us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = C - 0 . 335322 , 1 . 1 07487 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = C - 0 . 335322 , 1 . 1 07487 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
S P H E RE
C l oe = C - 0 . 64 5 0 6 6 , 1 . 054344 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
408
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G
409
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
41 0
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G
i ndex 0 . 000000 ,
)
SPHERE
( l o c = ( - 0 . 8 3 5 8 1 5 , 0 . 34 2 4 5 7 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
S P H E RE
( l oc = ( - 0 . 693760 , 0 . 5 1 3346 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 6439 5 1 , 0 . 327454 , - 0 . 222222 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( - 0 . 78600 5 , 0 . 1 56565 , - 0 . 000000 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t rans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc= ( - 0 . 594141 , 0 . 141561 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
41 1
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
41 2
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G
( l oc = ( 0 . 1 6 6 2 7 5 , 0 . 3087 5 3 , 0 . 6 5 5442 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( 0 . 0 0 5 8 5 1 , 0 . 04 8 8 6 1 , 0 . 7 2 9 5 1 6 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l o c = ( - 0 . 04837 5 , 0 . 2 5 1 238 , 0 . 6 5 5442 ) ,
rad i us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
S P H E RE
( l o c = ( - 0 . 1 1 5 0 3 1 , 0 . 0 7 0 7 0 0 , 0 . 5 44 3 3 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPH E RE
( l oc = ( 0 . 1 53845 , - 0 . 07 4 1 5 9 , 0 . 6 1 8405 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
41 3
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
i ndex = 0 . 000000 ,
)
S P H E RE
C l oe = ( 0 . 032964 , - 0 . 052323 . 0 . 433220 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = ( 0 . 24 7 6 1 4 , 0 . 00 5 1 9 2 . 0 . 433220 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = ( - 0 . 1 7 2546 , - 0 . 14395 1 , 0 . 000000 ) ,
radi us = 0 . 1 66667 ,
d i ff = ( 0 . 800000 , 0 . 0000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i n dex = 0 . 000000 ,
)
SPHERE
C l oe = ( - 0 . 1 5 7 543 , - 0 . 33581 5 . 0 . 1 1 1 1 1 1 ) ,
radi u s = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 . 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = ( 0 . 0 1 3346 , - 0 . 1 93760 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
414
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G
41 5
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
C l oe = C - 0 . 1 5 7 543 , - 0 . 33581 5 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = C - 0 . 1 7 2 546 , - 0 . 1439 5 1 . - 0 . 22222 2 ) ,
radi us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = C 0 . 0 1 3346 , - 0 . 1 93760 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = C 0 . 47 1405 , 0 . 0285 1 5 , 0 . 000000 ) ,
radi us = 0 . 1 66667 ,
d i ff = C 0 . 800000 , 0 . 0000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
C l oe = C 0 . 690426 , - 0 . 008983 , 0 . 000000 ) ,
radi us = 0 . 055556 ,
d i ff = C 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
t r a n s = C 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
41 6
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G
i ndex 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 607487 , 0 . 1 64678 , - 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s re f l ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
S P H E RE
( l oc = ( 0 . 607487 , 0 . 1 64678 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s re f l ect = 3 . 000000 ,
t r a n s = ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 554344 , - 0 . 145066 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s refl ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 47 1405 , 0 . 028595 , 0 . 222222 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
refl ect = 0 . 500000 ,
s re f l ect = 3 . 000000 ,
trans ( 0 . 000000 , 0 . 000000 , 0 . 000000 ) ,
i ndex = 0 . 000000 ,
)
SPHERE
( l oc = ( 0 . 335322 , - 0 . 1 07487 , 0 . 1 1 1 1 1 1 ) ,
radi us = 0 . 055556 ,
d i ff = ( 0 . 00000 , 0 . 450000 , 0 . 00000 ) ,
41 7
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
Pl ate 09 . ray
P i c t u r e s of q u a d r i c s h a pes
By Roge r T . Stevens - 6 / 1 7 1 90
41 8
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G
F I L E_ N A M E = S H A P E S 2 . RAW
PATT E R N S U S E D }
P A T T E R N ( x_s i z e = 8 0 , { C H E C K E R E D G RO U N D }
y_s i z e = 8 0 .
n a me = CHECK .
R E CTAN G L E (
s t a r t_x = 0 ,
s t a r t_y = O .
e n d_x = 40 ,
e n d_y = 40 .
d i ff ( . 75 , . 25 , . 75 ) ,
di ther O.
)
RECTANG L E (
s t a r t_x = 4 0 .
s t a r t_y = 4 0 ,
e n d_x = 80 ,
e n d_y = 80 .
d i ff ( . 75 . 25 . . 75) .
•
di ther = o .
P A RA L L E L O G RA M l oc ( - 1 0000 , 0 , - 10000 ) .
vl ( 20000 . O . 0) .
v2 ( 0 , 0 , 20000 ) ,
d i ff = ( 1 . 1 . . 7 5 ) .
di ther = 0 .
pattern = CHECK
xmu l t 2
ymu l t = 2
)
B E G I N_B B O X
Q U A D RAT I C ( l oc= ( 230 , 60 . - 1 00 ) { el l i pt i c cone -
cy a n }
a = 2500 . b = - 625 , c = 2500 ,
d = 0.
xmi n - 2 5 , xma x = 2 5 ,
ymi n - 50 . yma x = 5 0 ,
zmi n - 2 5 . zma x = 2 5 ,
d i ff (0. 1 .0, 1.0) .
41 9
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
E N D_ B B O X
B E G I N_B B O X
Q U A D RAT I C ( l ac= ( 300 , 0 , - 5 5 ) { cy l i n d e r - g r e e n )
a 1, b = o. c 1, =
d = 300 ,
xmi n = - 1 8 , xma x 18 ,
ymi n = 0, yma x 60 ,
zmi n - 18 . zmax 18 ,
d i ff = (0, 1.0, 0) .
)
E N D_B B O X
B E G I N_B B O X
Q U A D RAT I C ( l ac= ( 220 , 60 , 2 5 ) { el l i pt i c
pa rabol oi d -
purpl e )
a 60 , e =- 60 , c 60 ,
d 0.
xmi n - 2 0 , xma x = 20 ,
ymi n - 40 , yma x =60 ,
zmi n - 20 , zmax = 20 ,
d i ff (1.0, 0, 1.0) ,
)
E N D_B B O X
B E G I N_B B O X
Q U A D RAT I C ( l ac= ( 1 60 , 30 , - 3 5 ) { hype rbol i c
pa r a b o l o i d -
bl ue )
a 2. e = - 1 00 . c -2.
d 0
xmi n - 1 5 , xma x = 15 ,
ymi n - 25 , ymax 40 ,
=
zmi n - 1 5 , zma x = 15 ,
d i ff (0, 0, 1.0) ,
)
E N D_B B O X
B E G I N_B B O X
Q U A D RAT I C ( l ac= ( 2 30 , 60 , 90 ) { hy p e r b o l o i d of
420
A P P E N D I X A : D ATA F I L E S F O R R AY T R A C I N G
o n e s h eet
- orange }
a 1. b = -1, c = 1.
d 300 ,
xmi n - 2 5 , xma x = 2 5 ,
ymi n - 60 , ymax = 60 ,
zmi n - 2 5 , zma x =25 ,
d i ff (1.0, 0.5, 0) ,
)
E N D_B B O X
B E G I N _B B O X
Q U A D RAT I C ( l oc= ( 500 . 60 , 30 ) l { h y p e r b o l o i d o f two
s heets - red }
a -5. b = -7, c = 3,
d 700 ,
xmi n - 2 2 , xma x = 2 2 ,
ymi n - 60 , yma x = 60 ,
zmi n - 2 2 , zma x = 2 2 ,
di ff (1, 0, 0) ,
)
E N D_B B O X
B E G I N_B B O X
Q U A D RAT I C ( l ac= ( 1 30 , 30 , 3 5 ) { e l l i ps o i d - wh i te }
a = 8, b = 4, c = l,
d 500 ,
xmi n - 2 5 , xma x = 2 5 ,
ymi n - 40 , ymax = 60 ,
zmi n - 2 5 , zma x = 2 5 ,
d i ff (1.0, 1.0, 1.0) ,
)
E N D_B B O X
O B S E RV E R l oc ( - 2 0 . 7 0 , - 80 )
l oo k a t ( 200 , 50 , - 1 5 )
LAM P ( l OC = ( 1 20 , 400 , - 50 ) ,
rad i us = 5 ,
di st = 250
421
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
radi us = 5 ,
di st 220
)
LAMP ( l oc ( - 200 , 200 , 140 )
rad i us = 5 ,
di st = 220
X RES = 320
Y RES = 200
FOC L ENGTH 65
Pl ate 1 0 . ray
Pi c t u r e s of T roj a n H o r s e
B y Ro g e r T . S t e v e n s - 6 1 24 1 9 0
F I L E_N A M E = H o r s e . RAW
B E G I N_B B O X
Q U A D RAT I C ( l oc= ( 1 30 , 60 , - 20 ) { e l l i ps o i d !
a 8, b = 4, c = 1,
d 4000 ,
xmi n - 1 0 0 , xma x 100 ,
ymi n - 80 , yma x = 80 ,
422
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G
Q U A D RAT I C ( l oc= ( 1 40 , 0 , 1 0 ) ! cy l i n d e r !
a 1, b = o. c 1,
d 50 ,
xmi n - 1 8 , xma x 18,
ymi n 0, ymax 30 ,
zmi n - 1 8 , zma x 18 ,
di ff (1.0, .6, .4) .
)
Q U A D RAT I C ( l oc= ( 1 20 , 0 , 1 0 ) ! cy l i n d e r !
a l, b = O, c 1.
d 50 ,
xmi n - 1 8 , xma x 18 ,
ymi n 0, ymax 30 ,
zmi n - 1 8 , zma x 18,
d i ff (1.0, .6, .4) ,
423
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
E N D_B B O X
O B S E RV E R l ac ( - 20 , 7 0 , - 80 )
l ookat ( 200 , 50 , - 1 5 )
LAM P l ac = ( 1 20 , 180 , 80 ) ,
radi us = 5 ,
di st = 70
FOC L ENGTH 50
Pl a te 1 1 . ray
T h e Re f l e c t i n g B l i m p
By R o g e r T . S t e v e n s - 6 / 2 4 / 9 0
F I L E_NAM E = B L I M P . RAW
B E G I N_ I N S TA N C E S
n a me = P Y RAM I D
B E G I N_B B O X
T R I AN G L E ( l ac o . o . 0 )
424
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G
vl =( 52 , 0, 30 )
v2 =( 34 . 3 , 30 , 0 )
di ff (1, 0, 0)
=
T R I AN G L E ( l ac 0 , 0 , 0 )
vl = ( 52 , 0 , - 30 )
v2 = ( 34 . 3 , 30 , 0 )
di ff (1, 0, 0)
=
T R I AN G L E ( l ac 52 , 0 , - 30 )
vl = ( 0 , 0 , 60 )
v2 = ( - 1 7 . 7 , 30 , 30 )
d i ff (1, 0, 0)
=
E N D_B B O X
E N D_ I N S T A N C E S
PATT E RN S U S E D }
P A T T E R N ( x_s i z e = 80 , { C H E C K E R E D G RO U N D }
y_s i z e = 80 ,
n a me = C H EC K ,
R E C TA N G L E (
s t a r t_x = 0,
s t a r t_y = 0,
e n d_x = 40 ,
e n d_y = 40 ,
d i ff = ( . 25 • . 85 , . 2 5 ) ,
di ther = 0,
R E C TA N G L E
sta rt x = 40 ,
s t a r t_y = 40 ,
e n d_x = 80 ,
e n d_y = 80 ,
d i ff ( . 25 . . 85 , . 2 5 ) .
di ther = 0,
P A RA L L E L O G RA M l OC ( - 1 0000 , 0 , - 1 0000 ) .
vl ( 20000 , 0 , 0) .
425
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
v2 0 , 0 , 20000 ) ,
d i ff = 1 . 1 . . 75) ,
di ther = 0,
pattern = CHECK
xm u l t 2
ymu l t = 2
I N S TA N C E_O F n a m e = P Y RAM I D
l ac = ( 1 50 , 0 , - 60 )
sca l e = ( 2 , 2 , 2 )
)
Q U A D RAT I C ( l o c= ( 2 5 0 , 7 0 , 2 0 ) { e l l i p s o i d }
a 12 , b = 4 , c = 1 ,
d = 4000 ,
xmi n - 1 0 0 , xma x = 1 0 0 .
ymi n - 80 . ymax = 80 ,
zmi n - 1 00 . zmax = 1 00 ,
d i ff ( .5 .3. .5)
• •
mi r ro r = ( 9 . . 9
. 9) ;, .
T R I ANGLE l ac = ( 2 50 , 7 0 , 80 )
v l = ( 0 , 30 , 25 )
v2 = ( 0 , - 30 , 25 )
d i ff = ( . 5 3
• .5) • .
mi r ro r = ( . 9 . . 9 . . 9 )
O B S E RV E R l ac = ( - 20 7 0 , - 80 )
•
l ookat ( 200 , 50 , - 1 5 )
X RES 320
Y RES 200
426
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G
FOC L E NGTH 65
I
Pl a te 1 2 . ray
By R o g e r T . S t e v e n s - 6 1 2 1 9 0
C O LO R
di ff ( . 75 • . 43 , . 14 )
d i ff ( . 85 . . 43 , . 14 )
di ff ( . 95 . . 65 , . 65 )
amb ( .2. .3. .3) :
BEG I N BBOX
SPHERE l ac = 230 , 50 , - 50
rad i us 8
d i ff 1 . . 35 , . 35
R I NG l oc 230 . 50 . - 50
vl = 1 . 0 , 0
v2 = 0 . 0 . 1
r a d_2 = 2 0
r a d_l = 8
d i ff = . 2 , . 8 , . 8
SPHERE l o c = 1 8 0 . 50 . 0
radi us 8
d i ff 1 , . 35 , . 35
RI NG l o c = 1 80 . 5 0 . 0
vl = l , 0 , 0
v2 = 0 , 0 ,
r a d_2 = 2 0
r a d_l = 8
di ff = . 2 8, .8
• .
SPHERE l ac 230 , 50 , 50
radi us 8
d i ff 1 , . 35 , . 35
427
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
vl = 1. 0, 0
v2 = 0 , 0 , 1
r a d_2 20
=
r a d_l 8
=
E N D_B B O X
F RA C T A L ( l o c = ( 3 0 0 , 0 , 1 0 0 )
scal a r = 0 . 01
d i men s i on = 0 . 8
vl ( 502 , 0 , - 650 )
v2 = ( 502 , 0 , 750 )
O B S E RV E R l oc ( - 20 . 70 . - 40 ) .
=
l ookat = ( 200 , 50 , 0 )
S KY hori z = ( 0 . . 4 . . 7 ) .
zen i th (0. .4. .7 ) .
di ther 1
XRES 320
YRES 200
F O C_ L E N G T � - 75
428
APPENDIX A: D ATA FILES F O R R AY T R A C I N G
Pl ate 13 . qat
Quatern i on J u l i a Set
By R o g e r T . S t e v e n s - 7 / 1 /90
B A C K G RO U N D
(1. 0. 1)
AMB
(0. .4. .4)
DI FF
(0 • .8, .8)
SREFLECT
4
R E F L ECT ( 0 , . 8 , . 8 )
F I L E_NA M E
j ul i a
FLI P
L I G H T_PH I :
- 20
L I G H T_T H E T A :
50
V I E W_PH I :
45
XRES
319
Y RES
199
XMAX
1.8
XMI N
-1.8
429
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
Y MA X
1.0
YM I N
-1. 0
Z MA X
1.0
ZM I N
0.0
MA X_S I Z E
256
M A X_ I T E RAT I O N S
100
Q U AT E R N I O N
( - 1 , 0. 0. 0)
JULIA
Pl ate 14 . qat
Q u a t e rn i on J u l i a Set
By R o g e r T . S t e v e n s 7 / 1 /90
B A C K G RO U N D
( 1 , 1 . 0)
AMB
(0.3, 0.3, 0.6)
DIFF
(0.5, 0.5 1 .0)
SREF LECT
3
REF LECT ( 0 . 3 , 0 . 3 , . 9 )
F I L E_ N A M E
pl a tel4
FL!p
1
L I GHT PH I :
430
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G
-40
L I GHT TH ETA :
45
V I E W_ P H I :
75
XRES
319
YRES
199
XMAX
2.0
XM I N
-2.0
YMAX
1.3
YMI N
-1.3
ZMAX
0.6
ZM I N
0.0
M A X _S I Z E
1 28
M A X _ I T E RAT I O N S
64
Q U AT E R N I O N
( - 0 . 743036 , 0 . 1 1 3467 , 0 , 0 )
JULIA
!
Pl ate 15 . qat
Q u a t e rn i on J u l i a Set
By R o g e r T . S t e v e n s - 7 / 1 / 9 0
BAC KGRO U N D
(1, l, 0)
431
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
AMB
(0. 0. .4)
DI FF
(0. o. .8)
SREFLECT
4
REF LECT C O . o . . 8 )
F I L E_ N A M E
pl atel5
FL!p
1
L I GHT PH I :
- 32
L I G H T_ T H E T A :
70
V I E W_ P H I :
60
XRES
319
Y RES
199
XMAX
1.3
XM I N
-1.3
YMAX
1.3
YM I N
-1.3
ZMAX
2.0
ZM I N
0.0
M A X_S I Z E
1 28
M A X_ I T E RAT I O N S
64
Q U AT E R N I O N
( 0 . 2809 , 0 . 53 , 0 , 0 )
DRAGON
432
APPENDIX A: D ATA F I L E S F O R R AY T R A C I N G
Pl a te 1 6 . qa t
By Rog e r T . Stevens - 7 / 1 / 90
B A C K G RO U N D
( 0 . 0. 0 )
AMB
( .9. 0. 0)
DI FF
( .9. .7. .4)
SREF LECT
2
REF LECT ( . 9 , . 7 . 4 )
F I L E_N A M E
g ood r a g
FL! p
0
L I GHT PH I :
- 32
L I G H T_T H E T A :
40
V I E W_ P H I :
100
X RES
319
YRES /
/
199
XMAX
1.2
XM I N
-0.2
Y MA X
0.8
YMI N
433
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
0.8
ZMAX
0.8
ZM I N
0.0
M A X _S I Z E
1 28
M A X _ I T E RA T I O N S
32
Q U AT E R N I O N
( 1 . 646009 , 0 . 9 6 7 049 , o . 0 )
D RA G O N
434
Appendix B :
Format for .PCX Files
The ZSoft .PCX file format begins with a 1 28 byte header, the contents of
which are shown below:
435
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
64 1 Reserved
436
APPENDIX B : F O R M AT F O R . P C X F I L E S
Except for the color map, most of the header contents are self-evident. The
part of the header that is not currently being used by ZSoft may be used to
include some of your own variables to identify particular programs, but do so at
your own risk, as ZSoft may make use of these spaces in a future version.
The contents of a palette register for the EGA color system is described as
follows. Six bits are used, with two each for the primary colors red, green, and
blue. The capital letters represent colors of 75% amplitude; the small letters
colors of 2 5 % amplitude. So for each of the primary colors, four levels are
available : 0 (none of that color), 25% amplitude, 75% amplitude, and 1 00%
amplitude (both capital and small letter bits are one). The color map in the file
header contains 1 6 sets of triples, one for each EGA palette. For the first byte of
a triple, the values of the capital and small letter position for red are extracted
and combined to produce a number from one to three. This number is multiplied
by 85 and stored in the header. The same procedure takes place for the second
byte of the triple for green and the third byte for blue. The process is repeated
sixteen times, once for each palette. Note that when you set the palette registers
on the EGA you are setting a write-only register, this means that you will not be
able to recover the contents at a later date if you need to know what the setting
was. Consequently, our setEGApalette function saves the palette register
information in a global arrayPALEITE [ 1 6] . Use this data to write the color map
437
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
The VGA is quite different in the way that it handles colors. With the VGA,
each palette register contains the number of a color register. The color register
contains six bits, permitting 64 shades of each color. With the VGA you can
read the six bit value for each of the colors red, green, and blue, as well as
information in the palette registers and in the color registers. To create the color
map, read each palette register and then go and read the color register pointed to
by that palette register. Then multiply the red, green, and blue values by four
and store the results in the triple associated with that palette. Note that when you
restore a screen, you may not assign a color value to the same color register that
it was obtained from originally, and that the palette registers may not select the
same color registers. The net result is the same, however, because each palette
register points to a color register that contains the same color information that
was contained in the original screen. The VGA also has a color mode in which
256 different colors may be displayed simultaneously. This is the mode that we
use for reproducing the ray traced pictures. The format is the same as that used to
display the 1 6 color palette, but due to the 256 colors, the palette information is
much longer. It i s appended at the end of the . PCX file. To access this
information, you must first ascertain that the version number data in the header
(byte 1 ) is 5 (version 3 .0). Then read to the end of the file and count back 769
bytes. If the value in this byte position is ' OCH ' ( 1 2 decimal), the succeeding
information is 256 color palette data.
Data is read from the screen, horizontally from left to right, starting at the
pixel position for the upper left comer. For EGA and VGA, which have multiple
memory plane s , a line is read of the color red (to the end of the window
boundary), then the green information for the same line is read, and finally the
blue.
Data is run length encoded in the following manner. If the byte is unlike the
ones on either side of it, and if its two most significant bits are not 11 , it is
written to the file. Otherwise a count is made of the number of like bytes (up to
438
APPENDIX B : F O R M AT F O R . P C X F I L E S
63) and this count is ANDed with COH and the result written to the file, followed
by the value of the byte. If there are more that 63 successive like bytes, the
count for 63 and the byte are written, and then the count begins all over again.
(Note that the case for a singular byte having the two most significant bits 1 is
handled by writing a count of one followed by the byte value.)
28 4 Red
29 4 Green
30 4 Blue
439
Byte Palette Color
31 5 Red
32 5 Green
33 5 Blue
34 6 Red
35 6 G reen
36 6 Blue
37 7 Red
38 7 Green
39 7 Blue
40 8 Red
41 8 Green
42 8 Blue
43 9 Red
44 9 G reen
45 9 Blue
46 10 Red
47 10 Green
48 10 Blue
49 11 Red
50 11 G reen
51 11 Blue
52 12 Red
53 12 Green
54 12 Blue
55 13 Red
56 13 Green
57 13 Blue
58 14 Red
59 14 G reen
60 14 Blue
61 15 Red
62 15 Green
63 15 Blue
440
Appendix C :
Hardware Requirements
With the wide variety of PC clones that are now available, including some
that use 80286 and 80386 microprocessors at speeds far higher than anything
envisioned by IBM, there is no telling when some strange glitch is going to
wreak havoc with your program . To attempt to minimize that kind of problem, I
have attempted to run most of the programs described in this book on several
different systems. The primary system consists of the following:
Disk Control ler: Perstor PS l 80- 1 6FN from Hard Drives International, 1 9 1 2
West Fourth Street, Tempe, Arizona 8528 1 . This controller not only controls
two floppy disk drives of any type (5 1 /4 inch or 3 1 /2 inch), but also just about
doubles the capacity of your hard drive. I have found it to be completely reliable
with no signs of drop-outs or deterioration.
441
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
442
A P P E N D I X C : H A R D WA R E R E Q U I R E M E N TS
443
F R A C TA L P R O G R A M M I N G A N D R AY T R A C I N G W I T H C + +
problems, try to identify how your system differs from the two described above.
In troubleshooting your system, try to pinpoint which card or peripheral may be
the cause of the problem and then proceed from there. Once again, the most
important thing is to make sure that your system is fully IBM compatible.
Display Considerations
In order to run the ray tracing programs described in this book, you must
have a VGA display. The Newton 's method and quaternion programs can also
be run on an EGA display. If you have a Video Seven 1 024i display, you will be
able to create scenes that have much higher resolution than the ones in this
book. If you have another enhanced VGA card, the techniques are similar, but
you ' 1 1 have to discover the right ones for your particular card.
Processor Speed
Some of the ray tracing displays can take hours or days to generate, even
using a 386 machine with a math coprocessor. As you downgrade from this,
things get slower and slower, but if you have enough patience, you can usually
complete the program. One good thing; once you have the data file generated, it
only takes a few seconds to recreate the picture on your screen, and if you have
converted it to a .PCX file, you can reproduce it even faster.
444
Index
YMAX 1 7 3 , 342
YMIN 1 73 , 343
-W- YMULT 1 67 , 1 69, 1 7 1 , 1 74, 1 76
World 75, 1 43 , 229, 243 YRES 79
World, loading l 0 l YSIZE 79
WORLD.first_scan 228 YRES 1 80, 268, 342, 350
WORLD.flength 1 44 y_mult 246
WORLD.lamps 1 45 Y_SIZE 1 59
WORLD.last_scan 228 YMULT 1 65
WORLD.objcount 1 48 YRES 1 45
WORLD.outfile 1 44
WORLD.patlist 1 53
WORLD.sky_dither 1 43 , 243 -Z-
WORLD.stack 72 z buffer 1 2
WORLD_stack 73 ZENITH 1 43 , 1 77
WORLD.threshold 242 ZMAX 1 74, 343
World_Stats function 8 3 , 87, 8 8 ZMIN 1 73 , 343
wsphere.ray data file 25 1 Zortech C++ 1 3, 1 6, 28, 36, 80, 249,
25 1 , 252
zs256.c program, listing of 288
-
X -
ZSoft 278 , 436
Xerox Palo Alto Research Center 1 5 " operator 50
" operator, Vector, overloading 53
- operator 36
- operator, Vector, overloading 54