home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C!T ROM 2
/
ctrom_ii_b.zip
/
ctrom_ii_b
/
DOS
/
GRAFISCH
/
RAYTRACE
/
VIVID
/
VIVID.DOC
< prev
next >
Wrap
Text File
|
1992-03-15
|
113KB
|
3,232 lines
Vivid 2.0 March 14, 1992
Copyright 1989-1992 by Stephen B. Coy
Table of Contents
Introduction . . . . . . . . . . . . . . . . . . 2
Changes for Version 2.0. . . . . . . . . . . . . 3
Running Vivid. . . . . . . . . . . . . . . . . . 5
Statistics Display . . . . . . . . . . . . . . . 7
Legal Stuff. . . . . . . . . . . . . . . . . . . 9
Acknowledgements . . . . . . . . . . . . . . . . 11
Input File Format. . . . . . . . . . . . . . . . 13
Preprocessor . . . . . . . . . . . . . . . . 15
Studio . . . . . . . . . . . . . . . . . . . 17
Lights . . . . . . . . . . . . . . . . . . . 24
Surfaces . . . . . . . . . . . . . . . . . . 28
bump mapping . . . . . . . . . . . . . . 31
solid texture. . . . . . . . . . . . . . 33
Mandelbrot . . . . . . . . . . . . . . . 36
Geometric Primatives . . . . . . . . . . . . 37
sphere . . . . . . . . . . . . . . . . . 37
ring . . . . . . . . . . . . . . . . . . 38
polygon. . . . . . . . . . . . . . . . . 39
triangular patch . . . . . . . . . . . . 40
cone . . . . . . . . . . . . . . . . . . 41
Transformations. . . . . . . . . . . . . . . 42
Clipping . . . . . . . . . . . . . . . . . . 44
Support Programs . . . . . . . . . . . . . . . . 46
img2gif.exe. . . . . . . . . . . . . . . . . 46
paste.exe. . . . . . . . . . . . . . . . . . 50
up.exe . . . . . . . . . . . . . . . . . . . 51
down.exe . . . . . . . . . . . . . . . . . . 52
File Formats . . . . . . . . . . . . . . . . . . 53
Bibliography . . . . . . . . . . . . . . . . . . 54
Index. . . . . . . . . . . . . . . . . . . . . . 55
1
Introduction to Vivid 2.0
Surprise! Yes, 2.0 is finally here. I'd like to appologize
to those of you who have been waiting for many months for this to
come out. I've been busy doing my Master's thesis and, of
course, adding "just this one more feature." A few bugs were
squashed in the process although I'm sure that new ones have been
breeding in the walls just waiting until this release. Even with
the bugs I still consider Vivid to be one of the finest ray
tracers (I've) ever written.
In the archive you received should be this document, the
Vivid executable, some sample input files, and tools for
processing the image after it has been generated. Vivid.exe has
been compiled to run on any MS-DOS based system with a 286 or
better and a math coprocessor. Ray tracing can be extremely slow
and anything less is really not worth it. If, however, you don't
believe me feel free to write and I'll send you a copy compiled
for an bare 8086. I hope you don't plan on using your PC in the
next month. Back to the 286/287 version. This version also
contains a DOS extender allowing Vivid to take advantage of any
extended memory you may have. For those of you that still want
something better I also have 386 versions available. See the
Legal Stuff section for more info.
The rest of this document explains the details of how to run
Vivid and the tools and how to construct an input file. I
recommend that you print out this file and a couple of the sample
input files when first learning Vivid. An example is worth a
thousand words, or at least the paper it's printed on.
2
(Most of the) Changes for Version 2.0
I learned to spell Mark VandeWettering's name correctly.
Sorry about version 1.0 Mark.
Inside/outside problems have been resolved eliminating the
need to have spheres with negative radii or worry about clockwise
vs counter-clockwise polygons.
Polygon patches are a lot healthier.
I plugged my brain back in. The description of fuzzy
spheres given in the 1.0 docs is wrong. But it's better now.
When using the depth of field option a new "samples"
parameter has been added to allow you to control the number of
rays per pixel used.
Spherical light sources also allow the "samples" parameter
to determine the number of shadow rays shot toward them.
There is no longer a limit on the number of lights except
for memory and your patience. The limit was 20 but this info
never made it into the docs for version 1.0. The limit on number
of objects has also been removed although due to the operating
system an effective limit of about 2000 objects still remains.
The DOS extender version is limited only by memory.
The number of objects contained within a bounding box may
now be specified. The default, 4, is equal to the prior, fixed
value. This can be specified by adding
bunching 6
to the studio structure. Changing this value will affect the
performance of the automatic bounding box construction. Results
are image dependent but I think that 4 is a good default value.
A bug in the camera model caused the image to become
distorted when the up vector given in the studio structure wasn't
perpendicular to the direction of view. It has been fixed.
The traditional flat projection model has been joined by not
one, not just two, but by three other projection models,
spherical, othographic and parallax. See the section on the
studio structure for details.
The input file format has been changed to eliminate the need
for semicolons and equals signs. In order to be compatable with
the old file format, they are still accepted but are now treated
just as a space would be treated.
A quick-render mode has been added to help speed up
3
previews.
Simple math operations are now supported by the parser.
These operations are supported on numbers and on vectors (rgb
triples and xyz coordinates). The following is a list of the
operations supported. Vectors operations supported include cross
product, addition, subtraction, scaling, and dot product.
Numerical operations include multiplication, division, addition,
subtraction and exponentiation. Sine, cosine, tangent, arcsine,
arccosine, arctangent and square root functions are also
supported.
Cylinders can now be specified by giving a cone a single
radius parameter.
Preprocessor is here. include files, defines, undefs and
lack of fixed colors which are now replaced with color.vc.
Global transformations are now supported. Together with
include files this should make scene modeling much easier.
Primitives can now be clipped by planes, spheres or cone
allowing easier generation of more complex models.
The background can have a palette mapped to it rather than
just having a single color.
A new bunch of command line switches are now supported.
Typing vivid on the command line without any arguements will give
you a listing of them.
The keyword "noise" is now "turbulence" to better follow the
literature.
4
Running Vivid
Vivid input files use the extension .v and the output files
use .img. With the preproccessor in Vivid, include files are
also supported. These may have any extension. The syntax for
including a file into your input file is:
#include filename
Include files may have any extension you choose. The
following is a list of the file extensions that I regularly use.
If we all use the same convention it should make things easier
for trading input files. Feel free come up with your own
conventions if that suits you better.
.v Main input file for an image. Required.
.img 24-bit output file.
.map palette file for img2gif or background mapping.
.vc include file with color definitions. See color.vc.
.vo include file with object definition.
.vs include file with surface definitions.
The .img files produced by Vivid are full 24-bit color. The
details of their format are explained later in this document.
Since most systems can't display 24-bit graphics I've included a
tool to convert the .img files into .gif files which can be
displayed using vpic or cshow. This tool is called img2gif. Its
workings are also detailed later. In general the procedure for
generating an image will look like this:
1) Create an input file, test.v, with your favorite text editor.
2) Run Vivid.
C>vivid test
3) Wait until done. This can take from a few minutes to a
couple of days depending on the complexity of the image
and the speed of your machine. This is a good time to
raid the fridge.
4) Convert the result, test.img, into a .gif file.
C>img2gif -m -d test
The -m flag tells img2gif to use median cut to determine
the palette. The -d flags turns on Floyd-Steinberg
dithering.
5) View the image.
C>vpic test.gif
Because of the way I implemented the preprocessor Vivid
creates a temporary file on the disk called xyzzy.v. At this
time, Vivid does not delete the file after it is done using it.
5
The reason I leave this is that it is sometimes useful to look at
when trying to figure out what the preprocessor is doing with
your input definition. Feel free to delete it at any time.
Vivid supports a number of command line flags. These flags
allow you to change the operation of the program without changing
the input file. The following command line flags are now
supported:
-s Run in silent mode, ie no statistics display.
-r Resume.
-i x y Set image size to x by y pixels.
-n No_shadows, same as studio flag.
-d # Set maximum recursion depth value
-a mode Set antialias mode. Valid modes are: none,
quick, corners and adaptive. Since I can't type
I've made it so that you only have to give the
first letter of the mode for it to work.
-p Don't use the preprocessor.
Vivid has the ability to resume the generation of an
interrupted image. If during image generation you need to stop,
hitting ctrl-C or ctrl-BREAK will cause Vivid to stop at the end
of the next scan line. This may be up to a few minutes for a
slow image. This only works if statistics are enabled (the
default). Later, the image generation may be resumed by using
the -r flag on the command line.
6
Statistics
Surprisingly enough some people are curious about the
statistics that Vivid displays while processing. Somehow they
actually got the idea that the numbers may contain useful
information if only they were documented somewhere. The secret
is out. They don't mean a thing. I just put them in there
because I like watching them change while I'm waiting for the
image to generate. Sorry to break your bubble. OK, fine, I'm
joking, happy now?
When you run Vivid it displays the current version number
and the copyright notice. It then displays the filename of the
input files as the preprocessor digests them. Next a running
total of lights and primitives is displayed as the parser reads
the preprocessed input file. Once the file is completely read in
the automagic bounding box code is called. As it generates
bounding boxes you see the number of primitives climb. Upon
completion of the bounding box generation the scene extent is
displayed. This is the minimum and maximum values in each axis
for all the primitives. At this time the first scan line is
starting to be rendered. When it is done the screen will clear
and a full display of current statistics will be displayed. The
meanings for each of the numbers will now be described in
glorious detail bereft of all attempts at obfuscation. I hope
this makes sense.
The resolution is the size of the final image in pixels.
The line display next to it shows the progress of the ray tracer.
For example, if you where generating an image 320 pixels wide and
200 pixels tall the resolution would display 320x200
(unbelievable!) and the line value would go from 0 to 200. In
quick mode this number will increment by 6 instead of 1.
The next four lines contain information about the number of
rays cast. Eye rays are the rays cast from the viewpoint out
into the scene. Reflected rays are those generated by a specular
surface and refracted rays are those generated by transparent
surfaces. The total is just the sum of these rays. If your
input file doesn't have any reflective or transparent surfaces
these numbers will stay 0.
The next section contains information about shadow rays.
Shadow rays are the rays shot from the point of intersection
toward each light in order to determine if there are any other
primitives in the scene blocking the light (casting a shadow).
Vivid uses a shadow cache to try and speed up this process.
Cache hits signify an instance when the cached object was found
to cast a shadow and no ray was cast. The cache percentage is
just the number of hits divided by the number of shadow rays.
7
The next number is the average number of rays cast per
pixel. This number can give you a fair idea of just how hard the
ray tracer is working to generate the image. With no
antialiasing, reflection, or refraction this number should be
1.0. Adaptive antialiasing can push this as high as 16 depending
on the amount of extra work it does. Reflected and refracted
rays will make this even higher. Using the quick mode this
number may go to as low as .066 or so. When this number is less
than 1 that means that the ray tracer is guessing at some of the
pixels instead of actually casting a ray for them.
The average queues per ray value has to do with the bounding
scheme. The automatic bounding box generator creates a tree-like
heirarchy of bounding boxes for the system to test each ray
against. If a box is intersected by a ray then the objects in
the bounding box (either other bounding boxes or primitives) are
entered into the priority queue for further intersection testing.
The "bounds checked" number shows how many bounding box
intersection tests were performed. The "queue inserts" number
shows how many object passed the bounds check and were put into
the priority queue. The "queue resets" number displays the total
number of times the priority queue was reset. This should be
equal to the total number of rays plus the number of shadow rays
plus the number of cache hits. Don't ask why, it just will be.
The "max queue size" number shows the maximum number of objects
in the queue during the rendering.
The final number, the max recursion depth, shows the maximum
number of levels deep the ray tracer had to go while rendering
the image. The number after the slash is the max depth it is
allowed to go.
8
Legal Stuff
Vivid is Copyright 1989-1992 by
Stephen B. Coy
All Rights Reserved.
You are free to redistribute this package in its entirety.
In doing so you may charge no more than a nominal fee for
duplication. No part of this package may be included as part of
a commercial package without explicit written permission. If you
have any questions about commercial distribution of Vivid or its
tools I can be contacted at:
Stephen Coy
Vivid Software
15205 NE 13th Pl. #2904
Bellevue, WA 98007
(206) 641-8615
INTERNET: coy@ssc-vax.boeing.com or
uw-beaver!ssc-vax!coy
CompuServe: 70413,136
Originally I thought of distributing Vivid via shareware but
I seriously dislike the guilt games most shareware authors
include. So, I've decided to try beggarware. Here's the
product. Use it. If you like it I'd be very happy if you'd sent
a check for $30. If you think $30 is out of line, send less (or
more) or beer. If you don't think Vivid is worth diddly at least
send a postcard explaining why you don't like it. If you want
the 386 versions you'll have to register at the $50 level. Sorry
about that but times are tough and compilers aren't cheap.
Anyway that's about the price of an average game lately so I
don't think it's too far out of line. As is usual I will also
accept severe sob stories, beer, software (nothing pirated, thank
you), barter goods, and young women instead of money. The 386
diskette contains versions of Vivid compiled with both the
Zortech and the Intel compilers giving you a choice of DOS
extenders to work with. The Intel version is DPMI compliant and
has the advantage of supporting virtual memory allowing you to
allocate up to 128Mb of disk space as memory for those seriously
huge models. The Zortech version is DPMI, VCPI and XMS
compatible and takes up less space. It also seems to be able to
find about 500K more memory than the Intel version but doesn't
directly offer virtual memory support. If another DPMI host
which supports virtual memory is active, Windows 3.0 running in
386 enhanced mode for instance, then the Zortech version can take
advantage of it.
Whether you send anything or not I would like to hear about
any suggestions or bugs. Of course requests accompanied by money
9
will tend to get higher priority. I will answer all mail and
email even though I may be a bit slow at times. Email tends to
get the fastest response. If you have tried to contact me and
not gotten a response please try again. If you still don't get a
response you might have to resort to US Mail.
For those of you into BBSing I can be contacted via any of
the ADEnet nodes. ADEnet is a network of BBSs primarily
dedicated to providing professional quality support for AutoCAD
and other CAD programs. In addition there is also an animation
and rendering conference where questions about Vivid, or graphics
in general, will be answered. I usually log in on a daily basis
so turn around is quite quick. Another BBS I log into a lot is
TurboTech. Ray Johnson, TurboTech's sysop and the author of
TurboCit, has provided a room for ray trace discussions and has
plenty of disk space for images. Check out the conversations,
too. The BBS attracts some interesting people. I also frequent
CompuServe's COMART forum for those of you with deeper pockets.
Ray Johnson's Turbo Tech BBS can be reached at
(206)362-6828.
Alacrity Design & Engineering Network (ADEnet)
ADEnet serves the design and engineering communities by
making information useful to them widely available. This is done
in three ways: the ADEnet message conferences, the sharing of
programs and data files across ADEnet and the dissemination of
industry news and press releases.
ADEnet Member Listing
The following is a listing of the current ADEnet Member
BBSs. Each ADEnet Member is an independant BBS operated by a
local sysop.
Alacrity Software BBS 206-643-5477 Bellevue, WA DUAL (14.4)
The Graphics Alternative 510-524-2780 El Cerruto, CA DUAL (14.4)
Off Broadway 510-547-5264 San Francisco, CA V32
PC-AUG BBS 602-952-0638 Phoenix, AZ DUAL (9600)
Mind Image BBS 612-781-1720 Minneapolis, MN v22, MNP5
LABB 717-394-1357 Lancaster, PA v22, MNP5 [%]
AEC-ONLINE 818-360-7022 Los Angeles, CA v22
The University BBS 908-544-8193 Shrewsbury Twp, NJ DUAL (14.4)
AZCAD BBS +61-3-481-6873 Australia v32bis
Each of the listings has the BBS name and it's (primary)
phone number followed by the location. At the end of listing is
the highest allowable bits per second (bps) and protocol.
DUAL - US Robotics Dual Standard supporting HST and v.32/v.42bis
HST - US Robotics Courier HST
10
v32 - Industry standard v.32/v.42bis supporting upto 9600 bps
v32b - Industry standard v.32bis/v.42bis supporting upto 14.4k bps
v22 - Industry standard v.22 supporting upto 2400 bps
MNP5 - Indicates support Microcom Network Protocol Class 5
v42b - Indicates support for CCITT v.42bis
[*] CAD/Engineering Services BBS accepts calls between 22:00-05:00 CST.
[%] LABB is a multiline system, of which only the main line is listed.
The following is a listing of the current ADEnet message
conferences.
Conference Description
--------------------------------------------------------
Autodesk Autodesk product support
A/E/C Architectual, Engineering and Construction
CAD/CAM Manufacturing, NC Programming
Civil Civil engineering
CompuGFX Computer graphics, rendering and animation
DTP Desktop publishing
ForSale Buy & Sell used equipment, job listings
Generic Generic Software product support
GIS Geographical information services
uStation Integraph Microstation support
News Industry news and press releases
Public Network wide (ADEnet) general conference
TechTalk Technical hardware and software discussions
Joining ADEnet
If you are the system operator of a BBS and interested in
joining ADEnet, please download ADENET.ZIP. Within is a more
detailed introduction to ADEnet, an application form, and all of
the necessary information and data files you'll need.
ADEnet currently supports PC-Relay, QWK/REP, and FidoNet's
echomail message networking protocols. Alacrity Software BBS
serves as the ADEnet hub for nodes using either PC-Relay or
QWK/REP. The University BBS acts as ADEnet's "bridge" to nodes
using echomail.
11
Acknowledgements
First on the list I must thank Mark VandeWettering for his
raytracer MTV. Some pieces of Vivid have been lifted directly
from MTV's code. Hopefully, I only took the bug-free ones. I'd
like to thank Mike Thompson for his various contributions both
technical and fermented. Thanks to Gregor Harrison for a lot of
help understanding lex & yacc. I still am somewhat confused but
I like it that way. Thanks to Jason Osgood of ADEnet for
providing a forum for my rantings about Vivid. Thanks to Drew
Wells for encouraging me to join CompuServe. And thanks to all
those folks who unwittingly helped Vivid through their postings
to usenet. Finally, I'd like to thank all of you who took time
to send comments (and images and beer and money) for version 1.
Coming home to a nice letter and a check in the mail rather than
just bills makes the whole week go better. Thank you.
GIF is a trademark of CompuServe
MS-DOS is a trademark of Microsoft
12
Input File Format
One thing to keep in mind while creating Vivid input files
is that Vivid's parser is case sensitive. Macros (see
preprocessor section) are also case sensitive.
Vivid uses a right-handed coordinate system for defining the
location of objects in space. A right-handed coordinate system
can be visualized as having the x axis pointing to the right, the
y axis pointing into the screen and the z axis pointing up. Each
object in a scene file will be defined as having a location in
space defined by an x, y, z triple in this coordinate system.
Colors are defined by an r, g, b triple where each component
generally falls in the range 0..1. To make picking colors easier
Vivid includes the file color.vc which contains a few dozen
predefined colors. Their names and rgb values can be had by
viewing or printing color.vc. If this file is #included at the
top of you input file these names can be used anywhere an rgb
triple is called for.
Simple math operations are now supported by the parser.
These operations are supported on numbers and on vectors (rgb
triples and xyz coordinates). The following is a list of the
operations supported. Vectors operations supported include cross
product, addition, subtraction, scaling, and dot product.
Numerical operations include multiplication, division, addition,
subtraction and exponentiation. Sine, cosine, tangent, arcsine,
arccosine, arctangent and square root functions are also
supported.
Vector ops
----------
a b c cross x y z cross product, yields a vector
a b c dot x y z dot product, yields a number
a b c + x y z vector addition, yields a vector
a b c - x y z vector subtraction, yields a vector
a b c * n scale a vector by n
a b c / n scale a vector by 1/n
-(a b c) negate a vector
Numeric ops
-----------
sin(x), cos(x), tan(x) trig functions
asin(x), acos(x), atan(x)
sqrt(x) returns square root of x
pow(x y) returns x to the yth power
*, /, +, - normal mathematical operations
It should be noted that these operations introduce some
ambiguity to the input language. This problem is aggravated by
13
the fact that the parser can only look one token ahead when it
tries to decide how to treat its current input. I encourage you
to avoid any such problems by generously using parantheses to
eliminate any possible ambiguity in your equations. For example:
n * a b c can result in either
(n*a) b c or
(n*a) (n*b) (n*c)
depending on how the parser is feeling that day.
If you really want to I'm sure that you could figure out
what the parser is doing but that may change in the future so
save yourself the trouble and just add the parentheses.
Comments can also be included in the input file. Like
comments in computer programs, comments in Vivid input files are
ignored by the input parser. Comments in Vivid use the same
syntax as comments in C++ do. Multi-line comments start with /*
and end with */. Anything between the comment delimeters is
ignored. Single line comments start with // and end at the end
of the line. For example:
/* This is a comment
which spans multiple lines */
// This is a single line comment
Comments should be used as notes in your input files to help
remind you or anyone else reading the file what the input is
trying to do. Comments can also be used to block out part of the
input file while you are setting it up to help speed up test
renderings.
Normally an input file will be made up of a studio
definition which describes the image size, antialiasing and
viewpoint followed by the definitions for lights, surfaces, and
objects. Object definitions only deal with the geometry of the
object. The surface characteristics (color, shine) of the object
are taken from the last surface definition preceding the object.
14
Preprocessor
To make writing input files easier, Vivid's parser also has
a preprocessor. Currently, the preprocessor only supports two
functions, the definition of macros and support for include
files. Because of the way I implemented the preprocessor Vivid
creates a temporary file on the disk called xyzzy.v. (Didn't I
already mention this? deja vu) At this time, Vivid does not
delete the file after it is done using it. The reason I leave
this is that it is sometimes useful to look at when trying to
figure out what the preprocessor is doing with your input
definition. Feel free to delete it at any time.
Macros allow you to associate a name with a string of
characters. When the parser sees the name in the input file it
will substitute the appropriate string before continuing. A
simple example of this is the color definitions in the file
color.vc. In color.vc the colors white and blue are defined like
this:
#define blue (0 0 1)
#define white (1 1 1)
Once defined you can then use the word "white" wherever you
would normally have to type (1 1 1). For example, to create a
blue surface with a white highlight you could then do this:
surface {
diffuse blue
shine 20 white
}
Macro names must start with a letter and may contain
letters, numbers, and the underscore character "_". Macro names
are case sensitive. Note than in the examples I define the
colors with parentheses around the rgb values. This is not
required but helps eliminate any potential parser problems as
mentioned in the section on the parser's math ability. You can
undefine a macro using the #undef keyword.
#undef blue
If you define the same macro more than once the old values
are put onto a stack and the newest one will always be used. If
you then undefine the macro, only the newest one will be deleted
and the next newest definition will then be active. If you want
to define a macro that is longer than one line you have to use
the backslash, "\", as a continuation character.
15
#define BLUE_PLASTIC \
surface { \
diffuse blue \
shine 20 white \
}
Notice that the last line does not have a backslash after
it. Once defined you can then just use the name BLUE_PLASTIC in
the input file wherever you would normally type in the whole
surface declaration.
The other preprocessor directive is #include. This allows
you to include other files into your input file. Look at the
sample input files and notice that almost the first thing in the
file is a line like:
#include color.vc
This causes the parser to read in the file color.vc which
defines a standard set of colors for use in creating input files.
Using Dan Farmer's color editor it is quite easy to create new
colors to add to this file. The include command is also useful
for including objects into your scene. Combined with the
transformation commands this will allow you to create objects as
seperate files and inlcude them into the scene at any location
and orientation. You may also inlcude multiple copies of an
object.
16
The Studio
The studio structure in the scene file defines all those
things that are neither lights, objects or clips. This includes
the resolution of the final image, the location of the camera
(viewpoint), the direction the camera is pointing, the background
color, and various rendering options. Some of the options have
default values. These are the values these options will take on
if they are left out of the studio definition. The studio
definition looks like this:
studio {
from x y z
at x y z
up x y z
angle ang
resolution i j
start line
stop line
aspect asp
projection mode
ambient acolor
background bcolor
haze density
antialias mode
threshold dist
jitter
aperture size
focal_length dist
samples n
no_shadows
no_exp_trans
caustics
depth max_depth
bunching n
}
"from" is the location of the camera.
"at" is where in the scene the camera is pointed.
"up" is a vector pointing up, usually 0 0 1. This can be
played with to roll the image around the axis of
the camera.
"angle" is the field-of-view angle given in degrees.
17
"resolution" is the size of the image in pixels, i pixels
across and j pixels down. This can also be
controlled from the command line using the -i
switch.
"start" and "stop" allow you to start and stop the
rendering at the specified line numbers. I use
this for testing new input files and isolating
bugs. Those of you with networks might want to
consider using this to split up an image for
rendering on multiple computers. After the
sections are done you can then use paste.exe to
glue them together. Currently there is a problem
with using start and the resume (-r) flag. Avoid
the combination.
"aspect" is the aspect ratio of the screen. This is the
ratio of width to height of the screen you are
rendering your images for. I've found that my
Nec 3D has an aspect ratio of about 4/3 and that
my Amiga 1084 has an aspect ratio of about 1.2.
To determine the proper aspect ratio for your
screen measure the width and height of a screen
image. The aspect ratio of your screen can be
found by dividing the width by the height.
Determining the correct aspect ratio of your
screen will insure that circles come out looking
like circles instead of ovals. Remember, aspect
ratio should the the width/height ratio of the
displayed image regardless of the image
resolution. Together with the resolution these
are used to determine the aspect ratio of the
pixels.
"projection" controls how the 3d world is mapped onto the
2d screen. The default is "flat". This is the
standard perspective projection you've all come
to know and love. "spherical" projection
produces an effect somewhat like a fisheye lens.
Things can look pretty strange. Unique to the
"spherical" mode is the field of view angle can
be greater than 180 degrees. Try a 360 degree
panorama some time. The "orthographic"
projection mode produces an image where all the
eye rays are parallel to each other. For this
mode the "angle" parameter has no meaning and is
replaced with a "width" parameter. Width defines
how wide the screen is in the world coordinate
system. Generally, I think that this mode is
useless but it was easy to code so why not? The
final mode is the "parallax" projection mode.
This produces a 2-point projection instead of a
3-point projection like the "flat" mode. In the
18
"parallax" mode, all vertical lines stay vertical
on the screen. This was implemented specifically
for architectural renderings but is sometimes
useful in other contexts. Note that "vertical"
is defined by the direction of the up vector.
"ambient" is the color of the light that is everywhere in
the image. In "the real world" when light
strikes diffuse surfaces such as walls, some of
it is scattered back into the room. This is why
you can still see under a desk even though no
light is shining directly underneath it. Most
ray tracers, including Vivid, can't handle this
diffuse interreflection. But, all hope is not
lost. To fake diffuse interreflection Vivid
allows you to set an ambient light value. This
acts like a light that is shining in every
direction at once and does not cast any shadows.
For an inside scene values of about .2 .2 .2 seem
to work well. Outside scenes look a bit more
realistic with a higher ambient value because of
the scattering of light the atmosphere does.
Most ray traced images that you will see just
have the ambient value set to 0 0 0 or black.
This produces the sharpest contrasts and gives
the image a super-real effect. The default value
for ambient is 0 0 0.
"background" is the color that will be returned if no
objects are hit while tracing a ray. Popular
choices are black and sky_blue. If haze is
defined then this is the color of the haze. (see
below) The background color defaults to black.
Alternatively you can do the following:
background {
palette.map
up x y z
}
This produces a graduated background using the
colors in the file palette.map. The file can
have any name but is required to have the .map
extension. The file is the same format as the
img2gif palette files. The first color in the
file is the color that will appear in the
direction of the up vector. If no up vector is
specified then the up vector from the studio
structure will be used.
"haze" is the density of the fog or haze in the scene.
The haze density defaults to 0. This means that
there is no haze. A value of .5 means that for
19
every unit a ray travels, half of its color is
determined by the background color. This
function is exponential, ie if the haze density
is given as .5 the color of a ray going 1 unit
will be .5 times the color of the object it hits
and .5 times the background color. A ray going 2
units will be .25 the color of the object and .75
times the background color. For most images this
parameter can be ignored and the default value of
0 used.
"antialias" determines whether or not antialiasing is
performed and what type is used. This can also
be controlled from the command line using the -a
switch. The valid modes are:
none -- Do one ray per pixel, right through the
center. Results are blocky but relatively quick.
This is the default.
quick -- This does a subsampling approximation of the
image. In areas of even color the most speedup
is gained. This is the fastest mode but the
results are not useful for much more than test
images. At best (ie on a blank image) this
should be about 15 times faster than the above
mode. In general I notice about a 3-5 times
speedup. This is a great mode for doing test
renderings.
corners -- Shoot a ray at each corner of the pixel
and average the results. Since the corners are
shared by adjoining pixels this means about one
ray per pixel. The results are almost as quick
as none but usually have a better look.
Effectively this is the same as running a
smoothing filter over the image.
adaptive -- Rays are shot at the corners of the
pixel. If they are within a certain threshold of
each other the program moves on to the next
pixel. If they differ by more than the threshold
value, the pixel is subdivided into four
subpixels and sampled again. The corners of the
subpixels are then compared against the threshold
and if they are still too far apart the are
subdivided once more. The effective result of
this is that in areas of constant or smoothly
changing intensity only one ray per pixel is
shot. At edges or other sharp color transitions
up to 25 rays per pixel may be averaged to
determine the color of the pixel. The result is
fairly good antialiasing without too much undo
overhead.
"threshold" is the threshold value used by the adaptive
20
mode of antialiasing. The default threshold is
16. Valid values are 0..255. This parameter
also affects the quick mode. In general, lower
values will produce better results but take more
time.
"jitter" is a flag telling the system to add a little bit
of randomness to the direction each ray is shot.
Combined with antialiasing this helps to break up
the patterns sometimes caused by sampling an
image on a regular grid. Images with regular
patterns such as checkerboards disappearing into
the horizon will benefit most from jitter.
"aperture" is an optional parameter which allows the ray
tracer to model a more realistic camera. The
default aperture is 0 which models a pinhole
camera. With an aperture greater than 0 objects
at the focal length (see below) will appear in
sharp focus while objects nearer or further from
the viewpoint will be blurred. The larger the
aperture, the more exaggerated the blurring will
be. Using this option will greatly increase the
amount of time needed to generate an image
because Vivid uses distributed ray tracing to
model the effects of a camera with a non-zero
aperture. This causes the number of rays
necessary to calculate the color of a pixel to
increase greatly. The default is to shoot 8 rays
instead of one ray whenever aperture is greater
than zero. This value can be controlled with the
"samples" parameter below.
"focal_length" determines the distance from the camera to
the focal plane where objects are rendered in
focus. This option is used in conjunction with
the aperture option. Objects which are a
distance equal to the focal length away from the
camera will be in sharp focus. The default for
the focal length is the distance between the
"from" and "at" points which determine the
viewpoint and the viewing direction.
"samples" controls the number of rays shot when a
non-zero aperture is used. The default is 8.
"no_shadows" causes all shadow calculations to be turned
off. The speed increase gained by turning
shadows off is especially useful when doing test
images of a new scene. The can also be
controlled using the command line switch -n.
"no_exp_trans" is a wonderfully intuitive name for a flag
21
that turns off the exponential attenuation of the
rays as they pass through transparent objects.
Got that? Let me try again. Normally when Vivid
shoots a ray through a transparent object (glass)
the color of the ray is tinted by the color of
the glass and is a function of the distance that
the ray has to travel through the glass. For
example if you have two sheets of coke-bottle
green glass where one is 1/4 inch thick and the
other is 2 inches thick, light passing through
the thicker one will be darker. The relationship
between the thickness and the amount of tinting
is exponential. This causes problems with single
sided glass because when Vivid tries to compute
the thickness of the glass the distance
calculated is from the glass to whatever wall or
floor the ray hits next. Hence the windows will
tend to be way dark. When you set the
no_exp_trans flag in the studio structure Vivid
only uses the transparent color of the surface to
calculate the tint and totally ignores the
distance that the ray travels. This tinting also
affects shadow rays.
"caustics" is an experimental flag which turns on Vivid's
faked caustics. Caustics are those neat patterns
of light that are produced as light passes
through a transparent object. I've been playing
around with a couple of ways to get some of the
effect without having to spend a few days per
image doing the real thing. The effect is pretty
subtle but does seem to make some images look
better. Joe Bob says check it out.
"depth" lets you limit the maximum recursion level to
which rays will be traced. At a depth of 1 only
eye rays are traced. A depth of 2 will trace 1st
level reflections and refractions. The maximum
value allowed is 20. This is also the default
value. This can also be changed using the
command line switch -d.
"bunching" allows you to control the branching factor of
the tree created by the bounding boxes. I'm not
really sure what an optimal value is but the
default value of 4 seems to work well for most
cases. At any rate, values less than two are
guaranteed to cause grief. Higher values will
cause the bounding box tree to branch more at
each level and therefore be shallower. Lower
values will do the opposite. I find that
experimenting with takes more time than I ever
save so the only time I use it is when I am close
22
to running out of memory. Using a higher value
like 8 or 12 will create fewer composite
(bounding box) nodes in the tree and save soom
memory. Feel free not to ignore it without fear
of missing out on something.
23
Lights
Lights come in four flavors, point, directional, spherical
and spot. Just as the name implies a point light is a light
source occupying a single point in space. It has position,
color, and attributes determining how much the intensity of the
light falls off with distance. A directional light acts like a
point light source infinitely far away with no reduction in
intensity over distance. A spherical light source actually has a
radius to it and can provide shadows with penumbra (soft edges).
This feature, however, adds a considerable amount to the time
needed to render the image. Spot lights produce a cone of light
that falls off on the edges. These are quite nice for
highlighting areas of your model. In most cases they also
produce the least number of shadow rays making them quicker than
just putting a point light inside a cone.
The definition for a point light source looks like this:
light {
type point
falloff f // defaults to 0
position x y z
color r g b
}
The falloff parameter determines how the intensity of the
light is reduced over distance(dist). In the real world the
light intensity falls off as 1/(dist*dist) (f=2). Vivid also
allows the light to fall off as 1/dist (f=1) and not to fall off
at all (f=0). Why would you want to use anything except f=2?
Simplicity is one reason. With f=0 you can set the light's color
to 1 1 1 and know that whatever objects the light falls on will
be illuminated fully regardless of the distance of the light from
the object. With f=2 you must take into account this distance.
If the object you wish to be illuminated is 3 units away from the
light then in order to get the same amount of illumination that
f=0 provides you must set the color to 9 9 9 ie 3^2. For f=1 the
color would have to be 3 3 3. In the real world much of the
light around us does not come directly from the light source. It
often bounces off of other objects on its way to the object we
are interested in. Since Vivid, like most ray tracers, does not
model this interobject diffuse reflection we can achieve much the
same effect by have the light intensity fall off linearly with
distance, ie f=1. The default value is f=0.
The definition for a directional light source looks like:
light {
type directional
24
color r g b
direction dx dy dz
}
or the direction can be replaced by a from and at pair:
light {
type directional
color r g b
from x y z
at x y z
}
The direction vector points along the direction the light is
travelling. Since the light is assumed to be at infinity, there
is no falloff parameter. If you are having difficulty
understanding how the direction parameter works is is sometimes
useful to note that direction x y z is the same as center 0 0 0
at x y z.
The definition for a spherical light source looks like:
light {
type spherical
position x y z
radius r
color r g b
falloff f
samples n
}
Spherical lights differ from point lights in that the
shadows they cast have penumbra. Normally when a ray hits a
surface a shadow ray is shot toward each light. If the shadow
ray hits any surface on the way to the light then that light is
blocked and the surface is in the shadow of the blocking object.
With spherical light sources multiple shadow rays are shot. Each
one is shot to a random point within the radius of the light. If
the light is half blocked by an object, approximately half the
shadow rays will be blocked and half will pass through to the
light. The ratio of blocked to not-blocked shadow rays is then
used to determine how strong the shadow is. As you might expect,
the extra shadow rays will add a lot of extra time to the
rendering. Some references refer to these light sources as
extended light sources. The number of shadow rays shot each time
is controlled by the samples parameter. The default value for
this is 16.
The definition for a spot light source looks like:
25
light {
type spot
position x y z
direction dx dy dz
min_angle angle1
max_angle angle2
color r g b
falloff f
}
Like the directional light, the direction parameter may be
replaced with the at x y z to specify where the light is shining.
Min_angle and max_angle define the shape of the cone of light
produced by the spot light. Everything within the min_angle
angle of the axis of the light will be fully illuminated. From
there the light intensity will fall off until max_angle is
reached. For example if you want a cone of light 30 degrees wide
with sharp edges you would define min_angle and max_angle to be
30. To get the same size light but one that fades out at the
edges you would define max_angle to be 30 and min_angle to be 0.
Each light source can also have a couple of other
parameters. They are no_shadows and no_spec. As you've probably
guessed, these allow you to turn off shadows and specular
highlights for each light. Used together with a directional
light source of low intensity (.2 .2 .2) this is often a nice
alternative to global ambient light. Global ambient light tends
to make objects appear flat whereas this technique will provide
subtle shading without the shadows and spots of your "real" light
sources.
One thing to note is that even if a light is within the
viewing scene it will not appear as an object. If you want you
lights to be visible you can wrap a transparent shell around them
using a sphere. Example:
// Define a point light at 2 3 4 that shows up in the scene
// as a light with radius 1.
light {
center 2 3 4
type point
color white
}
// glass shell
surface {
ambient white // same color as the light
transparent white // totally transparent
}
sphere {
26
center 2 3 4
radius 1
}
For details on spheres and surfaces skip ahead.
27
Surfaces
Surface structures allow you to define the surface
characteristics of the objects you are rendering such as color,
reflectivity and texture. When a surface is defined in the input
file, it is applied to all the primitives following it until a
new surface is defined. This allows multiple objects to be
entered without having to repeat the surface characteristics. A
simple surface structure looks like this:
surface {
diffuse r g b // defaults to 0 0 0 (black)
ambient r g b // defaults to 0 0 0
specular r g b // defaults to 0 0 0
shine pow // defaults to 0
transparent r g b // defaults to 0 0 0
ior num // defaults to 1.0
fuzz magnitude // defaults to 0.0
no_antialias // turn off antialiasing
}
All of these components of the surface are figured in when
the ray tracer determines the color of an object in the scene.
The diffuse color is the actual color of the object as seen when
illuminated by a full white light. A value of 0 0 0 signifies a
black object while a value of 1 1 1 indicates white. The
brightness of this component depends on the amount of light
falling on the surface at that point. The ambient term is
sometimes also referred to as the self-luminous component. This
is the color the object will appear in a totally dark scene. The
specular component specifies the reflectivity of the surface. A
value of 1 1 1 will produce a mirror-like reflection. The shine
value determines how large the specular spot will appear on a
surface. Low values, 1..10, will produce large, soft-edged
specular highlights while high values, 1000 or more, will produce
a small, sharp spot. Traditionally the brightness and color of
the spot is in direct proportion to the specular component. The
problem is that sometimes it would be nice to have a blue object
with specular highlights without having the extra overhead of
tracing reflected rays. Therefore Vivid allows a second form for
defining specular spots:
shine pow r g b
In this case the color given will be used instead of the
specular component of the surface. The transparent component
allows you to define how transparent the surface is. A value of
1 1 1 will appear glass-like because it allows all colors to pass
through while a value of 1 0 0 will produce a surface like red
28
glass since it only allows red light to pass through. A surface
with a transparent component of .9 .9 .9 will appear partially
transparent with the amount of light passed through based on the
thickness of the object the light is passing through. The index
of refraction, ior, determines how much the ray is bent as it
passes into the transparent surface. In reality this is related
to the relative density of the surface. To simulate glass values
of about 1.1 to 1.3 seem to work best. The ior of diamond is
2.6. Fuzz is a way of adding random noise to the surface normal
of the object when its color is determined. Since the diffuse
color of the object is affected by the angle the light hits the
surface this randomization can produce a sort of coarse texuture
to an object. Applied to mirrored or transparent surfaces this
produces an affect much like frosted glass. Generally, small
values of fuzz, .01 to .3, seem to work best.
The no_antialias flag tells the adaptive antialiasing to
effectively turn off for that surface. In general this is not
something that you want to do except in a few special cases. The
original reason for this parameter was that fuzzy surfaces can
cause the adaptive antialias option to shoot lots of rays and
slow down the image generation considerably. By adding the
no_antialias flag to the surface definition you still get the
benefits of the adaptive antialiasing along the edges of the
objects but you avoid the slowdown that can be caused by any
large, fuzzy surfaces. Note, however, that this will change the
look of the surface. Try cutting the amount of fuzz in half when
using this option to preserve the amount of color variation in
the surface.
As an aid to those of us that can't type, some keywords may
be abbreviated: surf, diff, amb, spec and trans. I trust that
you'll be able to figure out what goes with what.
Some examples are probably in order.
// simple red surface
surface {
diff 1 0 0
}
// self-luminous blue
surface {
ambient 0 0 1
}
// mirror with specular highlights
surface {
spec 1 1 1
shine 100
}
// glass with some reflection
29
surface {
spec .3 .3 .3
shine 30
trans .7 .7 .7
ior 1.2
}
In general, the rule of thumb is that amb+diff+spec+trans
should be less than or equal to 1 1 1. Of course since we are
defining our own universe anything is possible.
30
Bump Mapping
Bump mapping is a means of giving a surface some texture
which enhances the realism of the surface by adding ripples or
bumps to the surface. The surface isn't actually distorted but
its normal is. This allows a simple surface to appear very
complicated. Bump definitions are included inside of the simple
surface definitions, ie:
surface {
diffuse red
bump {
...
}
}
A sample wave bump map looks like this:
bump {
wave {
center 1 2 3
wavelength 2.0
amplitude 0.2
damping 0.9 // defaults to 1.0
phase 0.0 // defaults to 0.0
}
}
Center defines the source of the wave. Wavelength defines
the crest to crest distance of the wave. Amplitude defines the
maximum amount that the surface normal is bumped. Values under 1
are definitely best. The damping parameter defines how much the
amplitude falls with distance. In the example given the
amplitude will decrease by 10% for each wavelength of distance
from the source. The phase is a number between 0 and 1 which
defines a starting offset for the phase of the wave. This can be
used in animations to create a wave which appears to move
realistically by incrementing the phase by a small amount for
each frame. More than one wave may be defined within the bump
structure. By defining three or four wave sources at various
locations with differing wavelengths and amplitudes a very
realistic rippled surface can be created.
31
Turbulence can also be used to perturb the normal of a
surface. The definition of turbulence looks like this:
bump {
turbulence {
scale 1 1 1
offset 0 0 0
amplitude .5
terms 4
}
}
The turbulence function takes the location of the ray
intersection and returns a random number in the range +-
amplitude. The scale and offset factors are applied to the xyz
location before the turbulence function is called. The terms
parameter allows you to build a fractal-like surface. When
terms>1 the turbulence function is summed multiple times. Each
successive term in the sum has its scaling doubled and the
amplitude halved. This produces the varying levels of
self-similarity associated with fractals. The sample file
vivid1.v uses this feature and a non-symmetric scaling to produce
the "spun-chrome" look on the large sphere. Turbulence and wave
definitions may be included with each other inside a bump
definition.
32
Textured Surfaces
Vivid also allows the use of solid texturing to enhance the
realism of the surfaces rendered. Textured surfaces are really
just two surfaces with some definition of which appears where on
the object and how the two surfaces are blended together. The
surfaces can be "layered" in one of three patterns checker,
spherical or noise. The checker pattern produces a 3-d checker.
The size of the blocks is controlled by the scale factor. If one
of the scale parameters is 0 then the pattern is assumed not to
change along that axis. An example would be a simple
checkerboard pattern with checkers 2 units on a side colored
black and white. This pattern is defined to extend infinitely
along the z axis.
surface {
texture {
pattern checker
scale 2 2 0
offset 0 0 0 // default
fuzz 0 // default
blend 0 // default
surface { diff black }
surface { diff white }
}
}
A scale of 2 0 0 would create a pattern which changes every
2 units in the x direction but is continuous in the y and z
directions. This is equivalent to 2-unit thick slabs of material
stacked along the x axis. The spherical pattern produces
concentric layers of alternating surfaces. When one of the scale
parameters is 0 concentric cylinders are formed with the axis of
the cylinders along the zero'ed axis. This is useful for wood
textures. The spherical pattern also requires 2 radius
definitions for the layers. The first radius is used for the
first surface, etc.
surface {
texture {
pattern spherical
scale 2 2 0
radius 1
radius 2
surface { diff black }
surface { diff white }
}
}
33
The noise pattern uses the output of the noise function
directly to pick between the two surfaces. This is useful for
producing textures like granite. By using unequal scaling values
in the x y and z directions you can get a streaked looking
surface. I've also used this using tan and brown surfaces to
produce a fine wood-grain look.
surface {
texture {
pattern noise
terms 4
scale x y z
surface { diff white }
surface { diff black }
}
}
The fuzz and blend parameters may be used to soften the
edges between the two surfaces. Their values range from 0 to 1.
The blend parameter produces a smooth transition between the
surfaces. The value of the blend parameter determines the width
of this transition area. The fuzz parameter adds noise to the
point being checked in proportion to its value. This produces a
coarse, speckled transition between the surfaces.
The turbulence function mention in the bump map section may
also be applied to textured surfaces. By varying the parameters
the effect can be made to range from a slight perturbation of the
pattern, to a marble look, to excessive turbulence. A simple
example is presented below.
Due to the way Vivid's parser works if you want to bump map
a surface which is also textured the bump definition must appear
in the surface structure before the texture definition. Also
notice that the surfaces defined in a texture definition need not
be simple surfaces. They may also be textured. The following is
a definition for a checkerboard surface with checks 10 units on a
side. Half the checks are black while the other half have a
red/white marble finish.
surface {
texture {
pattern checker
scale 10 10 0
surface { diff black }
surface {
texture {
pattern checker
scale 1 0 0
blend 0.7
turbulence {
34
amplitude 3
terms 4
}
surface { diff white }
surface { diff red }
}
}
}
}
35
Vivid also allows a Mandelbrot pattern as demonstrated in
the sample input file vivid1.v. The Mandelbrot pattern was put
into Vivid as a joke one evening. Currently the format for
specifying it is terrible. The first two parameters of the scale
value determine the x y scaling of the set while the 3rd
parameter determines the maximum number of iterations. The
result of the iteration calculation is then scaled by the max
number of iterations to determine the relative percentages of the
surface parameters for that point.
OK, the way it works is like this. The actual point of
intersection, x y z, is tranlated using the scale and offset
values before being put into the Mandelbrot calculation.
new_x = x * scale_x + offset
Like I said, this is about a backwards as I could make it
and still have it work. Since the point is multiplied by the
scale rather than divided the pattern gets bigger as the scale
value gets smaller. Normally the Mandelbrot set extends from -2
to +1 along the x axis (more or less). If you want to get it to
fit from -20 to +10 you would have to scale it by 0.1 in the x
and y axes. Stupid? Yes. Now, since the offset is added on
after the multiplication that makes it work in the Mandelbrot
coordinate system rather than the world coordinate system.
Continuing the example above, if you wanted to move the center of
the set to world coordinates 300, 100 you would have to give an
offset of 30 10.
Using macros I think you can alleviate most of this garbage.
#define ITERATION_LIMIT (64)
#define SCALE (10)
#define X_OFFSET (300)
#define Y_OFFSET (100)
surf {
texture {
pattern mandelbrot
scale (1/SCALE) (1/SCALE) ITERATION_LIMIT
offset (X_OFFSET/SCALE) (Y_OFFSET/SCALE) 0
// etc...
}
Now all you have to do is change the defines and things will
work much more like you expect.
Once I figure out a reasonable way of doing this Mandelbrot
and Julia sets will become a real part of Vivid. (Yeah, I know I
said that last time but it's still true.)
36
Sphere
The sphere is the simplest of the primitives supported by
Vivid and generally the fastest to perform an intersection test
with. The format for a sphere is:
sphere {
center x y z
radius r
}
where x y z is the location in space for the center of the sphere
and r is the sphere's radius. As an example here is the
definition for two glass spheres, one which is hollow and one
which is solid.
// glass surface
surface { trans 1 1 1 shine 200 1 1 1 ior 1.2 }
// solid globe
sphere { center 1 0 0 radius .9 }
// hollow globe
sphere { center -1 0 0 radius .9 } // outer surface
sphere { center -1 0 0 radius .8 } // inner surface
Just for laughs vivid also includes a fuzzy spheres option.
These spheres appear fuzzy because they have no fixed radius. To
define a fuzzy sphere define a normal sphere and add a fuzz
parameter. This defines how much larger the radius will randomly
be. Each time the ray tracer performs an intersection test with
the fuzzy sphere, the radius to test against is randomly chosen
to lie between the radius and radius+fuzz.
// fuzzy sphere with radius between 0.5 and 2
sphere {
center 0 1 2
radius .5
fuzz 1.5
}
37
Ring
The ring primitive may also be described as a washer or
disk. The definition for a ring consists of a location, a
surface normal, and a minimum and maximum radius. The minimum
radius may be zero producing a disk without a center hole.
Because the intersection for the ring is faster than for a
polygon the ring is a good choice for use as a ground plane
underneath the objects you are ray tracing. The format for the
ring definition is:
ring {
center x y z
normal a b c
min_radius r0
max_radius r1
}
The surface normal a b c does not have to be normalized. If
you just want a disk without a center hole the min/max radius
definitions may be replaced with a single radius definition as
follows.
ring {
center x y z
normal a b c
radius r
}
Whoa, just got a clue that not everyone knows what a surface
normal is. A surface normal is a vector that is perpendicular to
a surface, ie one that points straight out from the surface. For
example, the surface normal for the floor in you room would be a
vector pointing straight up into the air. The surface normal of
your monitor is the vector pointing straight out between you
eyes. Simple enough? Ok, now a normalized vector is one which
has been scaled to have its length equal exactly 1. This is
usually done by calculating the length of the vector then
dividing each of the vector's components by the length. Vectors
of length 0 cause no end of problems.
38
Polygon
Polygons may have any number of vertices (well, a minimum of
three is required). The vertices must all lie within the same
plane otherwise the results will be strange. The order of the
vertices may be either clockwise or counter clockwise.
polygon {
points 4
vertex 1 1 0
vertex 1 -1 0
vertex -1 -1 0
vertex -1 1 0
}
This will produce a square polygon 2 units on a side
centered at the origin with a surface normal equal to 0 0 1.
39
Triangular Patch
The triangular patch is useful for building objects with
complex shapes that you want to appear smooth. The patch is
defined by three vertices and explicit surface normals for each
vertex. In general, manually entering in patches will probably
be too tedious to be of much use but when using computer
generated input files the results will be worth the extra
programming effort.
patch {
vertex 1 0 0 normal .1 0 1
vertex 0 1 1 normal 0 .1 1
vertex 0 0 .5 normal -.1 -.1 1
}
40
Cone
The cones implemented by Vivid are actually truncated cones.
They have a radius both at their base and at their apex. When
these radii are equal the cone does a fair imitation of a
cylinder. To get a pointed cone enter 0 for one of the radii.
cone {
base 1 1 1 base_radius 4
apex 0 0 5 apex_radius 1
}
Rings are useful for putting caps on the ends of cones.
Even for a cone at an odd angle the position and normal of the
ring can be easily calculated. To cap the apex end of the cone
the ring's center is equal to the apex, the ring's radius is
equal to the apex_radius and the ring's normal is equal to
apex-base. Using the example above the definition for a ring to
cap the apex end of the cone would look like this:
ring {
center 0 0 5
radius 1
normal -1 -1 4
}
41
Transformations
Vivid's transformation commands allow you to move and scale
objects. Transformation commands apply to all the primitives
following them until they are "popped" from the transformation
stack. The format for a transformation command is:
transform {
scale s
rotate x y z
translate dx dy dz
}
Scale changes the size of the objects. Scale may also be
defined as a vector to create objects that are scaled differently
in each axis. Unfortunately this doesn't work with all
primitives, only polygons and patches can be scaled
non-uniformally. The rotate command rotates the object the given
number of degrees around each axis. The translate command moves
the object. Any of these may be left out or used more than once.
They can also be used in any order and will be applied to the
objects in the order that they are given. It is very important
that you get the order correct. An object that is rotated 90
degrees around the Z axis and translated 10 units along the X
axis will end up at 10 0 0 with a 90 degree twist whereas if the
operations are applied in the other order the object will end up
at 0 10 0. Sometimes it helps to play around with real objects a
bit and work through some of the transformations first. Remember
that all rotations are done around the axes, not necessarily
around the center of the object. This should also be kept in
mind when building new objects. Put 0 0 0 at the objects
"natural" center of rotation. This will help greatly when
building scenes with the objects. For example, the natural
"center" for a car model would be at ground level in the center
of the car. This allows the car to fairly easily be placed in
the scene where you want it.
To remove a transformation from the transform stack use the
"transform_pop" command. Sometimes you will want to nest
transform commands. This is useful for creating multi-part
objects that move relative to each other but also need to move as
a whole unit. For example, say you want to create a tank model
with a turret that you can rotate. Assume that the body of your
tank model is in the file tank.vo and the turret is in turret.vo.
To place the tank in your scene, your input file would look like
this:
#define TURRET_ANGLE (30) // rotation for turret
transform { translate x y z } // move whole tank
42
#include tank.vo // include body geometry
transform { rotate 0 0 TURRET_ANGLE }
#include turret.vo // include turret geometry
transform_pop // clean up transform stack
transform_pop
Using this technique complicated models can be built and
positioned with relative ease. There is currently one major
drawback to using transformations, surface textures don't move
with the object. This isn't too big a deal for single frame
images but will make animating textured objects look very poor.
Yes, I'm working on it.
43
Clipping
Primitives can also be "clipped" to produce more complicated
shapes. Basically the way a clip works is that a primitive is
defined with a clipping surface which cuts off part of that
primitive. For example a sphere can be clipped against a plane
to produce a hemisphere or a cone can be used to clip a hole
through another cone. There are three types of clipping surface:
planes, spheres and cones. Clips are defined within a
primitive's definiton. You may have more than one clip per
primitive. Clips also transform along with their primitives.
A clipping plane is defined by a point and a normal.
clip {
center x y z
normal x y z
}
The part of the primitive on the normal side of the plane
will be kept while the part on the other side will disappear into
the Ronald Reagan Memorial Library. (You may think I'm lying but
you'll never really _know_ until you go check.) For example, if
you want to get a hemipshere of radius 1 centered at the origin
if would look like:
sphere {
center 0 0 0 radius 1
clip {
center 0 0 0 normal 0 0 1
}
}
Note that the clip's normal is pointing upward. This will
give you the top half of the sphere. If you change the normal to
0 0 -1 you will get the bottom half.
Clipping spheres are defined as:
clip {
center x y z
radius r
inside or outside
}
With a clipping sphere you can choose to either keep the
part of the primitive inside of the sphere or the part of the
primitive outside of the sphere. You may have already guessed
this but that's why the inside and outside keywords are there.
Clipping cones look like:
44
clip {
apex x y z apex_radius r
base x y z base_radius r
inside or outside
}
Just like the cone primitive you may also just define a
single radius to get a cylinder.
Sometimes you will want to apply the same clips to a group
of primitives. To do this define global clips using the
global_clip keyword:
global_clip {
clip { ... }
clip { ... }
clip { ... }
}
The clip_pop keyword will cause the previous section of
clips to be popped off the stack much like the transform_pop does
for transformations.
45
Support Programs
img2gif.exe
Once vivid has completed an image you need some way to view
the results. That's where img2gif comes in. Img2gif is used to
convert the raw img file that Vivid outputs into a gif file. The
resulting gif file can then be viewed using your favorite view
program. My favorite is Brad Montgomery's vpic. Look for it on
you local BBS. In a pinch, even fractint can be used to view
gifs.
When running img2gif you have 2 main decisions to make: a)
how should the program pick the palette and b) should the program
do any dithering of the output. Picking the palette is not
always an easy problem. Standard VGA allows us to view only 256
of the available 262,144 colors. An "average" lores image will
have about 7000 colors which we need to represent with our
palette of 256. A higher resolution image my have tens of
thousands of colors to represent. The following algorithms are
currently implemented in img2gif.
Palette File -- A palette may be input via a .map file.
This uses the same format as .map files created/read by fractint.
This option is useful for creating multiple gifs with the same
palette for animation.
Popularity -- The popularity algorithm chooses the palette
by picking the 256 colors which represent then greatest number of
pixels in the image. The remaining colors in the image are
mapped onto the palette using a minimum distance formula. The
popularity algorithm tends to work best on images with a lower
number of colors. One typical problem of the algorithm is that
small highlights may not be colored correctly. Highlights
generally only cover a few pixels so their color usually doesn't
have enough representation in the image to be chosen by the
popularity algorithm. To help alleviate this problem, img2gif
forces the corners of the color cube (white, red, green, blue,
cyan, magenta, yellow, and black) to be selected as the first
eight palette entries. Since most highlights are white this
greatly helps reduce unwanted artifacts in the resulting image.
Median Cut -- The median cut algorithm tries to choose a
more well balanced set of colors to represent the image. The
general idea of the median cut is to choose a palette in which
each entry represents about the same number of pixels in the
image. This helps to correctly color highlights that a pure
popularity algorithm might miss. Img2gif also allows you to
limit the number of pixels represented by any one color. This,
in effect, increases the importance of the colors in highlights
and other small regions of the image. With this limit set to
one, every color in the image is given the same weight without
46
regard for the number of pixels it covers.
Fixed Palette -- The fixed palette option uses a
predetermined palette instead of choosing one based on the
content of the image. This has the advantage of being much
faster. When choosing by popularity or median cut img2gif must
first build a tree structure in memory containing every color in
the image and a count of the number of pixels represented by that
color. After choosing the palette the colors in the tree must
then be mapped onto the colors in the palette. This can slow
img2gif down quite a bit. When using a fixed palette the image
colors are mapped directly onto the palette colors via simple
equations eliminating the need for the tree structure and the
costly remapping of the images colors to an arbitrary palette.
Also, the current version of img2gif can only support a tree
containing about 57,000 colors. After this my clone runs out of
RAM. The fixed palettes supported by img2gif are:
0 : A grey scale image using 256 grey scale tones. Due to
VGA limitations this will display as 64 shades on most PC
systems.
1 : Divides the color cube into 8 shades of red, 8 shades of
green, and 4 shades of blue. Generally produces fairly bad
images but kept in for nostalgia. Blue was chosen to get the
lower resolution because in general the human eye is much less
sensitive in the blue range and has a harder time focusing on
edges therefore the loss of color resolution is not missed as
much.
2 : Divides the color cube into 6 shades of red, 7 shades of
green, and 6 shades of blue. This option gives the best balance
of speed vs good color representation. I've found that it works
best with images that have a large number of colors. The
addition of dithering is usually helpful.
Dithering is the process of displaying pixels of differing
colors next to each other in such a way as to produce the
illusion of more colors. An every day example of this is your
television. Stick your nose up to the picture tube and notice
that the screen is made up of tiny red, green, and blue dots
which vary in intensity. These are the only colors your TV
actually produces but your eye combines them to produce the rest
of the spectrum. Well, at least the spectrum according to NTSC.
Floyd Steinberg dithering is the original error diffusion
dithering algorithm. Error diffusion dithering attempts to
compensate for a limited palette by insuring that the sum of the
errors in any region of the image is zero even though the colors
at each individual pixel may contain some error. At each pixel
as img2gif scans through the image the nearest color for that
pixel is chosen. Generally this color will not be exact. The
difference between the chosen palette color and the true color is
47
then added to the neighboring pixels which have not been scanned
yet. Floyd Steinberg dithering has the advantage of having a
"random" look to it. Generally, it does not produce noticeable
patterns in the output image.
Ordered dithering works by adding a fixed amount to each
pixel based on its location. The sum of these additions over a
region of the image is equal to zero. Since ordered dither does
not take into account the values of neighboring pixels it
produces fixed patterns in the images which may be distracting in
some cases. Ordered dithering combined with a fixed palette has
an advantage if you are using Vivid to produce single fames for
an animation. During an animation the background (non-moving)
regions of the image will stay constant whereas if you use Floyd
Steinberg dithering the patterns constantly shift around and
below any moving objects on the screen.
The random noise option allows you to add white noise to an
image. In some cases this may help as much as dithering. It can
also be used in conjunction with either of the dithering options.
Interesting effects may be obtained by increasing the range of
the noise. Images converted with a large amount of noise tend to
take on a distinctly grainy look. Interesting, but not overly
useful. The default range for the noise is +-8 on a 0..255
range. This value was chosen strictly because it seemed to look
good in most cases. Random noise has the advantage of being
constant from image to image. This means that smooth areas in a
series of images will not shimmer during animation.
Ok, fine, now how do I run img2gif? Well, it goes like this:
img2gif [-m #] [-f #] [-p palfile] [-d] [-o] [-r [#]] file
The default palette choosing algorithm is the popularity
method.
[-m #] chooses median cut and limits each color to represent
at most # pixels. # defaults to 64K.
[-f #] chooses fixed palette #. # defaults to 0, grey
scale.
[-p palfile] reads the palette out of the file palfile.map.
If this file does not exist the palette will be chosen by median
cut, popularity, or fixed depending on what other flags are set.
After the palette is chosen it will then be written to the file
palfile.map.
[-d] chooses Floyd Steinberg dithering.
[-o] chooses ordered dithering.
[-r #] chooses random noise +- #. # defaults to 8.
48
For example:
img2gif -f 2 -d test
will convert test.img to test.gif using fixed palette 2 and
Floyd Steinberg dithering.
Assuming that test.map does not exist
img2gif -m -p test test1
img2gif -m -p test test2
img2gif -m -p test test3
img2gif -m -p test test4
will convert test1 using median cut to choose the palette. The
palette will then be saved to test.map. Test2, test3, and test4
will then be converted using the palette in test.map.
In general the best results will be obtained by using the -m
-d flags as in img2gif -m -d test. For images that tend to be
fairly monochromatic I've found that -m -d -r 4 works well.
Adding the small amount of random noise helps break up some of
the banding. On the down side it also adds to the .gif file size
since it is tough to compress random noise well. To get nice
looking grey scale images try -f 0 -r.
49
paste.exe
The paste tool will allow you to join together two images in
raw file format either vertically (one over the other) or
horizontally (side by side), ie. two 320x200 images may be
joined together to form a 320x400 image or a 640x200 image. In
order for two images to be joined vertically the images must have
the same width. In order for them to be joined horizontally they
must have the same height.
The calling sequence for paste is:
paste [-h | -v] in_file1.img in_file2.img out_file.img
In the horizontal case in_file1.img will appear to the right
of in_file2.img. In the vertical case in_file1.img will appear
above in_file2.img.
50
up.exe
Up allows you to double an image's size vertically,
horizontally, or in both directions. The increase in size is
done by pixel duplication, no interpolation is used. The calling
sequence is:
up [-h | -v] in_file.img out_file.img
If no flag is given, up increases the image's size in both
directions.
For example if test.img is a 320x200 image
up -v test.img test2.img
will create test2.img with a resolution of 320x400.
51
down.exe
Down does the opposite of up. (surprise!) When reducing an
image's size, down averages the appropriate pixels to produce the
new pixel. The calling sequence is:
down [-h | -v] infile.img outfile.img
If no flag is given, down reduces the image in both
directions.
For example if test is a 320x200 image
down test.img test2.img
will produce test2.img with a resolution of 160x100.
52
File Formats
The information included here about the file formats is to
aid people in writing their own image manipulation utilities
compatible with the Vivid formats. I encourage you to experiment
and share any interesting results with the rest of us.
img -- This is the format of the files output by Vivid. The
images are stored 24-bits per pixel with a simple run length
encoding scheme to help keep the size down. The run length
encoding works by replacing a repetitive string of the same color
with a count value and that color written only once. "Runs" of
the same color are not allowed to continue beyond the end of the
scanline to make working a scanline at a time easier. The format
consists of a 10 byte header followed by the image data. The
16-bit numbers in the header are stored most significant byte
first. This format is compatible with that used by Alias
Research. (I think.)
<2-bytes> x size of image
<2-bytes> y size of image
<2-bytes> first scanline, usually 0
<2-bytes> last scanline, usually y size - 1
<2-bytes> number of bitplanes, always 24
<image data>
The image data format looks like:
<1-byte> a repeat count for the following color
<1-byte> blue, 0..225
<1-byte> green, 0..255
<1-byte> red, 0..255
This is repeated as many times as necessary to complete the
image. Note: runs do not wrap from one scan line to the next.
This helps simplify post-processing. It has been noted (hi Ray!)
that in some of Vivid's antialiasing modes an extra scan line is
output to the file. This may eventually get fixed but for now
the best thing to do is to always use the info in the header
rather than looking for the end of file.
map -- This is the format used for palette files. This
format was chosen to be compatible with fractint. The file is in
plain ASCII text and consists of 256 lines each containing the
red, green and blue value for that palette entry. The rgb values
are integers in the range 0..255.
53
Bibliography
For anyone interested in ray tracing and how it works the
following books are highly recommended. Further references may
be found in the bibliography at the end of Glassner's book.
"Computer Graphics, Principles and Practice, 2nd Ed.",
Foley, van Dam, Feiner and Hughes, 1990, ISBN 0-201-12110-7
"An Introduction to Ray Tracing", Andrew S. Glassner, ed.,
Academic Press, 1989, ISBN 0-12-286160-4
"Illumination and Color in Computer Generated Imagery", Roy
Hall, Springer-Verlag, 1989, ISBN 0-387-96774-5
54
Index
#define. . . . . . . . . . . . . . . . . . . . . 15
#include . . . . . . . . . . . . . . . . . . . 5, 16
ambient. . . . . . . . . . . . . . . . . . . . . 19
angle. . . . . . . . . . . . . . . . . . . . . . 17
antialiasing . . . . . . . . . . . . . . . . . . 20
aperture . . . . . . . . . . . . . . . . . . . . 21
aspect ratio . . . . . . . . . . . . . . . . . . 18
at . . . . . . . . . . . . . . . . . . . . . . . 17
background color . . . . . . . . . . . . . . . . 19
bibliography . . . . . . . . . . . . . . . . . . 54
blend. . . . . . . . . . . . . . . . . . . . . . 34
bump mapping . . . . . . . . . . . . . . . . . . 31
bunching . . . . . . . . . . . . . . . . . . . . 22
caustics . . . . . . . . . . . . . . . . . . . . 22
changes for 2.0. . . . . . . . . . . . . . . . . 3
checker pattern. . . . . . . . . . . . . . . . . 33
clipping . . . . . . . . . . . . . . . . . . . . 44
clipping plane . . . . . . . . . . . . . . . . . 44
colors . . . . . . . . . . . . . . . . . . . . . 13
command line flags . . . . . . . . . . . . . . . 6
comments . . . . . . . . . . . . . . . . . . . . 14
compound surfaces. . . . . . . . . . . . . . . . 33
cone . . . . . . . . . . . . . . . . . . . . . . 41
coordinate system. . . . . . . . . . . . . . . . 13
depth. . . . . . . . . . . . . . . . . . . . . . 22
dithering. . . . . . . . . . . . . . . . . . . . 47
down.exe . . . . . . . . . . . . . . . . . . . . 52
field of view angle. . . . . . . . . . . . . . . 17
file extensions. . . . . . . . . . . . . . . . . 5
file formats . . . . . . . . . . . . . . . . . . 53
fixed palettes . . . . . . . . . . . . . . . . . 47
Floyd Steinberg dithering. . . . . . . . . . . . 47
focal_length . . . . . . . . . . . . . . . . . . 21
from . . . . . . . . . . . . . . . . . . . . . . 17
fuzz . . . . . . . . . . . . . . . . . . . . . . 34
gif. . . . . . . . . . . . . . . . . . . . . . . 46
global clipping. . . . . . . . . . . . . . . . . 45
haze . . . . . . . . . . . . . . . . . . . . . . 19
img file format. . . . . . . . . . . . . . . . . 53
img2gif.exe. . . . . . . . . . . . . . . . . . . 46
include files. . . . . . . . . . . . . . . . . . 5
input file format. . . . . . . . . . . . . . . . 13
jitter . . . . . . . . . . . . . . . . . . . . . 21
lights . . . . . . . . . . . . . . . . . . . . . 24
directional . . . . . . . . . . . . . . . 24
point . . . . . . . . . . . . . . . . . . 24
spherical . . . . . . . . . . . . . . . . 25
spot. . . . . . . . . . . . . . . . . . . 25
macro. . . . . . . . . . . . . . . . . . . . . . 15
macro continuation . . . . . . . . . . . . . . . 15
55
mandelbrot . . . . . . . . . . . . . . . . . . . 36
map file format. . . . . . . . . . . . . . . . . 53
median cut algorithm . . . . . . . . . . . . . . 46
noise. . . . . . . . . . . . . . . . . . . . . . 34
no_antialias . . . . . . . . . . . . . . . . . . 29
no_exp_trans . . . . . . . . . . . . . . . . . . 21
no_shadows . . . . . . . . . . . . . . . . . . . 21
ordered dither . . . . . . . . . . . . . . . . . 48
palette file . . . . . . . . . . . . . . . . . . 46
paste.exe. . . . . . . . . . . . . . . . . . . . 50
polygon. . . . . . . . . . . . . . . . . . . . . 39
popularity algorithm . . . . . . . . . . . . . . 46
preprocessor . . . . . . . . . . . . . . . . . . 15
projection . . . . . . . . . . . . . . . . . . . 18
random noise dithering . . . . . . . . . . . . . 48
resolution . . . . . . . . . . . . . . . . . . . 18
resume . . . . . . . . . . . . . . . . . . . . . 6
right-handed coordinate system . . . . . . . . . 13
ring . . . . . . . . . . . . . . . . . . . . . . 38
samples. . . . . . . . . . . . . . . . . . . . . 21
solid texture. . . . . . . . . . . . . . . . . . 33
sphere . . . . . . . . . . . . . . . . . . . . . 37
spherical pattern. . . . . . . . . . . . . . . . 33
start. . . . . . . . . . . . . . . . . . . . . . 18
statistics . . . . . . . . . . . . . . . . . . . 7
stop . . . . . . . . . . . . . . . . . . . . . . 18
studio . . . . . . . . . . . . . . . . . . . . . 17
surfaces . . . . . . . . . . . . . . . . . . . . 28
threshold. . . . . . . . . . . . . . . . . . . . 20
transform. . . . . . . . . . . . . . . . . . . . 42
transform_pop. . . . . . . . . . . . . . . . . . 42
triangular patch . . . . . . . . . . . . . . . . 40
turbulence . . . . . . . . . . . . . . . . . 32, 34
up . . . . . . . . . . . . . . . . . . . . . . . 17
up.exe . . . . . . . . . . . . . . . . . . . . . 51
viewpoint. . . . . . . . . . . . . . . . . . . . 17
wave bump map. . . . . . . . . . . . . . . . . . 31
xyzzy.v. . . . . . . . . . . . . . . . . . . . 5, 15