rt User Manualrt recognizes a variety of UNIX-style command line
options. When no options are specified, rt will run in
interactive mode with default values for all rendering options.
-H, --help : Display usage information
and exit.
-I, --noninteractive : Run in
non-interactive mode.
-Q, --quiet : Run quietly - output errors
only.
-s <filename> : Use filename as
input .ray file. Default is none.
-d <filename> : Use filename as
output image file. Default is none.
-z <width> <height> : Set image size to
width x height pixels. Default is 300 x 300.
-r <depth> : Set recursive depth to
depth levels. Default is 0.
-c <limit> : Set contribution limit to
limit intensity. Default is 0.
-j <rays> : Set number of jitter rays to
rays per pixel. Default is 0.
-h <rays> : Set number of shadow rays to
rays per shadow test. Default is 0.
-f <rays> : Set number of focal blur rays to
rays per pixel. Default is 0.
-y <angle> : Set fisheye lens field of view to
angle degrees. Default is 0.
-b : Turn off bounding boxes.
-n : Turn off Snell's Law refraction calculations.
-p : Turn off color projection.
If one of the -I or --noninteractive options
is not specified first in the list of arguments, rt will run
in interactive mode. In this mode, an OpenGL window is created to allow
interactive camera placement and setting of render options before
raytracing. Any command line arguments that are specified replace the
default render options values when in interactive mode, but they can still
be changed from within the OpenGL context.
If the -s options is used, the specified file will be
loaded and displayed in polygon mode immediately. The -d
option is ignored.
If either -I or --noninteractive is the first
option supplied to rt, no OpenGL window will be created.
Instead, the source file will be read in and raytraced to the destination
file, all without requiring any additional user input. This is useful for
batch renders or complex scenes. Any command line arguments specified
replace the default rendering options in the final image.
The -s and -d options are required for
non-interactive mode.
The -Q or --quiet options will suppress the
printing of progress and options information when running in
non-interactive mode, for when silent raytracing is desired. Error
messages will still be printed.
The purpose of the OpenGL interface is to allow for rapid development
of RAY files for raytracing. Previously, RAY file creation was a long and
involved process as obtaining visual results meant raytracing the file.
Camera positioning was extremely difficult, because it was non-interactive
and required manual editing of the direction and up vectors. The OpenGL
interface provided by rt greatly improves this process by
providing a quick and interactive means of viewing the scene and
positioning the camera. The interface accepts mouse commands within the
active window, as well as menu commands via a GLUT popup menu.
When a RAY file is loaded, it is immediately displayed in the window, polygon rendered using OpenGL, the GLU, and GLUT libraries. This is a facsimile of what the scene looks like, as best as OpenGL is able to approximate. Many effects will look strange, like transparency and CSG, while others will be completely absent, like bump mapping or fisheye lens effects. OpenGL mode exists to allow for more rapid development of scene geometry only - polygon rendering is inherently less powerful than a direct illumination method like raytracing.
The raytraced iamge will appear in the window in place of the polygon rendered scene after it's been created. When raytracing, if Progressive Rendering is turned on, the raytraced image will appear line by line on top of the OpenGL polygon rendered view of the scene. Some discrepancies may exist in exact object placement - errors of a few pixels are common. We're not sure why this happens, but we wish it didn't.
The raytraced image will continue to be displayed until the view is
changed with the mouse, when polygon mode will be resumed. Once that has
happened, the raytraced image is lost. For this reason, it is not
recommended to use the OpenGL interface to perform long, complicated
renders. Establish a camera position and then raytrace the scene via
rt's non-interactive mode.
The mouse and keyboard control various aspects of rt when
the window is active.
left mouse : rotate view yaw (left-right) and pitch
(up-down)
shift left mouse : rotate view roll (around view
direction)
middle mouse : translate along x-axis (left-right) and
y-axis (up-down)
shift middle mouse : translate along z-axis (along
view direction)
right mouse : access popup menu
Q key : quit rt
Raise the popup menu by clicking and holding with the right mouse button inside the window.
File->Open... : load and display a rayfile
File->Reload : reload and redisplay the current rayfile
File->Save Image : write current raytraced image to a
file; image file type is specified by the three-letter suffix on the
file name, defaulting to BMP
File->Save Rayfile : write current scene to a rayfile;
rayfiles that include other rayfiles may not write correctly
Render->Raytrace : raytrace the scene from the current
camera view, with the current set of options
Render->Image Size... : set the width and height of the
view area; manually increasing the size of the window won't work.
Render->Jittering... : set the number of rays randomly
cast through each image pixel; use 1 to cast one random ray through each
pixel, or 0 to cast one uniform ray through each pixel
Render->Shadow Rays... : set the number of rays
randomly cast for shadow tests; use 1 to cast one random ray for each
shadow test, 0 to cast one uniform ray for each shadow test, or -1 to turn
off shadow testing
Render->Recursive Depth... : set the maximum level of
recursion to use when calculating reflections and transmisions
Render->Contribution Limit... : set the minimum
contribution level to use when calculating reflections and transmissions
Render->Focal Blur Rays... : set the number of rays
randomly cast for depth of field effects; use 0 to disable
Render->Fisheye Lens Angle... : set the angle of view
of the fisheye lens; use 0 to disable
Render->Toggle Snells Law : turn on/off refraction
calculations through thick objects via Snell's Law
Render->Toggle Bounding Boxes : turn on/off bounding
box enhancement to ray intersection testing
Render->Toggle Progressive : turn on/off progressive
rendering
Options->Toggle Lighting : turn on/off lighting
calculations; with lighting off, only ambient and emissive contributions
are calculated
Options->Toggle Transforms : turn on/off group
transforms
Options->Toggle Textures : turn on/off texture
maps
Options->Toggle Transparency Maps : turn on/off
transparency maps
Options->Toggle Bump Maps : turn on/off bump maps
Options->Toggle Cutout Maps : turn on/off cutout maps
Options->Toggle Transparency : turn on/off transmitted
rays and transmitted light
Options->Toggle Backface Culling : turn on/off backface
culling in OpenGL mode; useful to determine which direction normals face
Options->Toggle Color Projection : turn on/off
projection of color through transparent objects
Print Options : print to standard output the current
configuration of all rendering options
Help : print to standard output a help message
Quit : quit rt
rt recognizes a variety of different file formats for
input and output. The scene description format is RAY, and the image
file formats are BMP and PPM.
The RAY file format is a losely defined syntax for scene
specifications. It has been tailored to fit our exact needs, and so
unfortunately, it isn't a standard format useable in any other modellers
or renderers. However, this means it's perfectly suited for the needs of
rt and CS155.
To learn more about the RAY format, read the full specification.
Two image formats are supported by rt - BMP and PPM.
BMP is Microsoft's raw bitmap format. rt supports writing
24-bit 3-channel BMPs in binary format. For more information on the BMP
specification, take a look here
or here.
PPM is a very simple, easy to understand, read, write and edit format
for storing 24-bit 3-channel image data. rt supports writing
ascii PPMs. For more information on the PPM specification, take a look here.
At well over 10,000 lines, rt has a large number of
features to allow fine control over your final raytraced image. Many of
these features are implementations of popular rendering algorithms and
require a bit of explaining to make the algorithm and design choices
clear.
rt can raytrace a standard set of 3D shapes: spheres,
triangles, cones, cylinders, boxes, and tori. Specification of
orientation is not allowed for any primitive - the nature of intersection
testing makes such calculations extremely complicated. If a primitive is
orientable, the z-axis is used. To acheive more complicated positioning
and orientation, group objects are provided, which maintain local
coordinates via an arbitrary 4x4 tranformation matrix. Examples of
matrices to perform various transformations (translate, rotate, scale)
can be found in the OpenGL Programming Guide. Use matrix
multiplication to compose multiple simple transformations into a
single transformation matrix.
rt supports a standard set of light sources: directional,
point and spot. Area lights are not supported. Directional lights are
lights infinitely far away, so all light falling in the scene has uniform
direction. Point and spot lights are treated as having no volume,
existing somewhere within the scene. Since they have finite distance to
objects in the scene, they support attenuation (constant, linear and
quadratic). These lights are modelled after OpenGL 1.2's light
sources.
rt supports surface material properties modelled after
OpenGL 1.2. A material specification consists of ambient, diffuse, and
specular responses, as well as emissive light, shininess and transparency
coefficients and a refractive index. Materials are used to determine
color and intensity of an intersection point on some shape in the
scene. The color at an intersection, also called the excident
light at that point, is calculated as follows.
E = EA + EE + ED + ES + ER + ET
EA = CA * IA
ED = CH * CD * D ( IF + IB * ktrans ) * ( 1.0 - ktrans )
ES = CH * CS * S ( IF )
ER = CS * ReflectedRay ET = CD * ktrans * TransmittedRay
where
E = excident light / color at intersection
EA = excident ambient component
EE = excident emissive component
ED = excident diffuse component
ES = excident specular component
ER = excident reflected component
ET = excident transmitted component
IF = incident light on surface's front
IB = incident light on surface's back
CA = material's ambient response
CD = material's diffuse response
CS = material's specular response
CH = light shadow color
ktrans = material's opacity
D ( ... ) = calculation of diffuse reflection of incident light
S ( ... ) = calculation of specular reflection of incident light
ReflectedRay = excident light calculated at intersection point of reflected recursive ray cast
TransmittedRay = excident light calculated at intersection point of transmitted recursive ray cast
CH, the projected color of a shadow from a transparent object, is only taken into account when color projection is turned on. It's calculated by starting at white at the light's position and then following the ray to the intersection point. Along the way, the value is multiplied by the color of any transparent objects encountered along the way. If any opaque objects are encountered, it's set to black. When it reaches the intersection point, the color obtained is the multiplier on the incident light due to occlusions from that light source.
Material's can have associated with them texture maps, bump maps, transparency maps and cutout maps. Texture maps modulate the diffuse and ambient response of the material. Transparency maps modulate the ktrans of the material. These maps are only applied to a material if the shape using the material has the appropriate option turned on. That is, if a material has a texture specified and a shape uses that material but doesn't have texture mapping turned on, the shape will be rendered without the texture map.
The default camera models a simple pinhole camera. It occupies a point in space and the distance to the image plane in front of it is determined by the half height angle, supplied in the RAY file. There are no near or far clipping planes - any object some positive distance in front of the camera will be rendered. By default there is no focus control and the standard perpespective projection is used.
Depth of field effects have two controls. The #focal_blur directive in a RAY file sets the focal length and aperture for the camera, while the focal blur rays setting sets the number of camera rays to cast. The effect is implemented by jittering the camera's position and direction about some focal point in the scene. The camera is displaced from its position by some random amount and then rotated to point at the focus. for each ray normally cast through a pixel, multiple rays are cast with by the jittered camera. When combined with Super Sampling, the total number of rays cast through each pixel is the number of focal blur rays times the number of jitter rays. Increasing the number of focal blur rays drastically increases the length of time of the render.
rt can also render images with a fisheye lens effect.
The fisheye lens angle specifies how large the viewing area should be, in
degrees from the camera's direction. The allowable range for this setting
is between 0 and 180. The final rendered image will not be rectangular,
depending on the viewing angle. The most common use is 90 degrees to get
a hemisphere view of the entire scene in front of the camera, which
results in a circular image. The equations used to do the projection
calculation can be found here.
To generate the final rendered image, rays are cast through each pixel of the image, which is a plane in front of the camera, perpendicular to the camera's direction vector. Cast rays are then intersected with the scene. This is handled by the scene heirarchy - each RAY file has a top-level group which every object in the file is contained in. A ray is intersected with the scene by intersecting it with this group. Groups handle intersection testing by transforming the ray from global coordinates to its local coordinates, and then intersecting the ray with each shape within the group. Individual shape primitives handle intersection testing according to their geometry. Thus, a ray is recursively intersected with the entire scene thanks to the recursive nature of the scene heirarchy.
The intersection process is sped up by the addition of bounding boxes. Each group maintains it's own bounding box, defined as the sum of all the bounding boxes of the objects contained inside it. When testing ray intersection, the ray is first testing against the bounding box - if the test succeeds, the ray is intersected with the group's objects normally, but if the test fails, the intersection test immediately fails. This optimization relies on good use of group directives in the RAY file to group spatially-near objects together; otherwise, the bounding box tests will not provide a significant speed increase, and could potentially slow things down.
A more reliable optimization on the intersection testing process is the use of octrees (or any other space-partitioning data structure, such as a BSP tree). An octree is a container that can either hold a list of objects or eight child octrees. A global octree is first constructed and all the objects in the scene are added to it (for simplification of computation, objects' bounding boxes are used). If the octree's edge length is greater than some threshold, or the number of objects inside the octree is greater than another threshold, the octree subdivides itself and places all its objects into one (or more) of its eight child octrees. This process is recursed until the space is adequately partitioned. Once the octree is constructed, intersection testing can carry on the same as it did before - the ray is intersected with the top-level octree, and if it passes, the ray is then intersected with everything inside it (either objects, or other octrees). The use of octrees for an average case scene (without pathological placement of objects) will turn the otherwise linear intersection test process into a logarithmic one. For more information on octrees, take a look here.
rt has two mechanisms for controlling the number of levels
of recursively cast rays (used to calculate reflection and transmission).
The first is the recursive depth setting, which defaults to 0. This value
is the maximum level of recursion that will be calculated. For example,
if recursive depth is set to 1, at most one reflection ray and one
transmission ray will be cast from the intersection point found by the
original ray cast from the camera. These rays are only cast when they
might be used in the calculation - that is, if a material is 100% opaque,
no transmition ray will be cast. Similary, if a material is 100% diffuse,
no reflection ray will be cast.
The other mechanism rt supplies to limit the level of
recursion is the contribution limit setting. Each recursive ray cast has
a smaller and smaller influence on the final color of the image pixel,
because of the multipliers on the ray's return value (a reflected ray is
multiplied by the material's specular color, and a transmitted ray is
multiplied by the material's ktrans). Eventually, recursive rays will
have an insignificant influence and their calculation is a waste of time.
The contribution limit is the threshold that determines when a recursive
ray's contribution to the final pixel color is insignificant. If
contribution limit is 0.1 and a material's ktrans is 0.01, then even if
the maximum recursive depth hasn't been reached, no recursive transmitted
ray will be cast because it's maximum contribution is 0.01 and that's less
than the contribution limit. The default contribution limit is 0,
which means there is no limit and recursive rays will be cast
exhaustively. Depending on the materials in a scene and the recursive
depth setting, there may be drastic improvements in rendering times if
the contribution limit is set to something like 0.01 or 0.05.
rt implements super sampling (jittering) as an
anti-aliasing technique. Rather than casting a single ray through the
center of each pixel in the image, multiple rays are cast, randomly
through the pixel and the color values are averaged together. This
reduces the aliasing artifacts from a regular sample rate by making the
samples irregular within the pixel. Of course, increasing the number of
rays cast per pixel drastically increases the total render time. Jitter
values around 10 provide good results. When jittering is combined
with the depth of field effect, the total number of
rays cast through
each pixel is the number of focal blur rays times the number of jitter
rays.
rt also uses super sampling to simulate the soft shadows
generated by real lights. Modelling a light source as a point with no
volume means that it produces sharp shadows - any point in space is very
clearly in or out of shadow with respect to the light. Real lights have
some volume and so a point in space can be totally in or totally out of
its shadow, or partially shadowed, where some but not all of the light
source's volume is visible to the point. To simulate this effect, rather
than cast a single shadow ray for each light, rt can cast
multiple rays jittered about the light source's position, test each one
for visibility, and return a number indicating what percentage of the
sources' light is visible. Increasing the number of shadow rays cast has
a large effect on the total render time. Values around 10 provide good
results. This has no effect on directional lights - they still produce
sharp shadows. It's possible to jitter the directional light's direction
vector and cast multiple shadow rays, but that feature was left out of
rt.
If a texture map is used on a shape, it will determine the color at any point on that shape's surface. This color can either be retrieved from an image file or determined by some procedural method. If an image file is used, it must be parameterized onto the surface. If a procedural texture is used, then the color value can simply be computed from the location of the point in question.
In cutout mapping, rt actually removes pieces of the surface of
an object. If the map is being done with an image file, it's parameterized onto
the surface just as it would be for texture-mapping. For procedural mapping, we
simply calculate the color for any given point on the surface. In either case,
the intensity of the color value of the map for a point on the surface is used to
determine whether a point should be considered part of the surface. If the
intensity is less than 0.5, then the point will not be considered a valid
intersection. Otherwise, it remains part of the shape.
For transparency mapping, the intensity is calculated in the same manner that it is for cutout mapping. Rather than actually removing pieces of the surface, we use this intensity to determine the transparency of the shape at this point. If the intensity of the color is 1.0, the surface will be entirely opaque. If the intensity is 0.0, the surface will be entirely transparent.
In bump-mapping, the normal vector is skewed based on the color gradient of the map around the sample point. For the following explanation, (aside from a few special cases), the "up" vector is considered to be a unit vector in the z-direction, and the "right" vector is computed by crossing the up-vector with the normal.
If the map is being computed from an image file, then the image coordinates
are calculated just as they are for texture-mapping. rt obtains the
intensity of the four pixels surrounding the sample point. The change in
intensity in the x-direction is used to scale the right-vector, and the change in
y-intensity is used to scale the up-vector. Both of these changes are scaled by
the value specified with the shape being bump-mapped, with the result being added
to the normal vector.
If, instead, procedural bump-mapping's being done, then the gradient is
computed in the x-, y-, and z-directions. (The choice of some offset for the
sampling to compute the gradient is arbitrary. For a point (x, y, z)
rt looks at (x +/- 0.05, y +/- 0.05, z +/- 0.05) and calculates
intensity at each point.) The normal is skewed as before, however it is also
skewed by adding in the z-gradient times the cross-product of the up and right
vectors.
The CSG interface supports four binary operations and one unary operation. These are:
Objects a and b may be simple primitives, groups, macro instances, or rayfile instances.
A CSG object will only be visible at points on the surfaces of its member primitives. Thus, if the Inv operation is used to create an unbounded CSG volume (for instance, trying to draw the complement of a sphere) results may not be what was expected.
The CSG object is rendered by intersecting the cast ray with each of its primitives. The closest of these intersections is then tested to see whether it's a valid point in the CSG volume. If not, it's discarded and a ray is cast recursively from the point of intersection. This will repeat until either a valid intersection is found or the ray has passed through the CSG object. Material properties for the intersection are those of the primitive which had the first valid intersection. An alternative would be to allow the CSG object to have its own material specification, and to ignore the materials of the shapes contained within - however, this limits the possibilities for the sort of images a CSG object can create.
Note: "open" cylinders and cones - those without endcaps - are treated as solid volumes for the purposes of CSG.
Procedural texturing in rt makes use of color gradients to
determine the color of an object. A gradient is specified as a set of pairs,
mapping real numbers to an RGB colors. Given any real number, rt can
look in the gradient table to determine where it falls, then do linear
interpolation between neighbors to determine the color to use. Given the
gradient
#grad_begin -n g1 --
0.0 0.0 0.0 0.0
0.5 0.0 0.0 1.0
1.0 0.0 1.0 0.0
#grad_end
a value of 0.0 would produce black, 0.25 medium blue, 0.5 bright blue, 0.75 blue-green, and 1.0 green.
The procedural textures in rt are based on coherent noise
functions designed by Ken Perlin. A color gradient must be defined for the
texture, and a summation function may optionally be specified as well. (The
summation function should take only one variable.)
The noise functions produce noise in one, two, three, or four dimensions that is locally smooth (no discontinuities). Perlin's original source for the noise functions can be found here. For an explanation of the underlying math, check here. Hugo Elias' websote provides a good explanation of how to use this coherent noise to create interesting textures.
The noise functions used will return a value in the interval [-1, 1].
rt uses this to generate an output value for a specified persistence
and number of octaves. Given a function that returns a noise value for a point
(x, y, z), this value is:
Perlin (x, y, z) {
sum = 0;
sum_amplitudes = 0;
for (i = 0; i < octaves; ++i)
{
frequency = 2^i;
amplitude = persistence^i;
if (doing standard summation)
sum += noise(x * frequency, y * frequency, z * frequency) * amplitude;
else // a function has been defined for the summation
sum += function(noise(x * frequency, y * frequency, z * frequency)) *
amplitude;
sum_amplitudes += amplitude;
}
return sum / sum_amplitude;
}
The value computed here is then used as a lookup in the gradient to determine the color to be used at (x, y, z).
Harvey Mudd College
Professor Elizabeth Sweedyk
Stephen DiVerdi
Ethan Drucker
Joshdan Griffin
Jason Wither
© 2002