Ray tracing is a method of rendering a visual scene by tracing simulated rays of light in reverse from a camera or eye location, through each pixel of a user-defined image plane, into a three-dimensional scene (also user-defined), and then back to the originating light source. An intersection test is made between the ray and every object in the scene. If no objects are intersected, the pixel for the current ray is assigned a default background color. If an object is intersected, the color of the pixel is computed by taking into account the physical properties of the object intersected (transparency, reflectiveness, roughness, specularity, size, shape, etc...), the position of the object relative to other objects in the scene, and the angle of incidence of the ray with respect to the surface normal at the point of intersection. Texture maps and shadow calculations may also be included.
Because ray tracing is an estimation of processes occurring in nature, resulting images appear very photorealistic. The image quality, however, is paid for with render times which can be orders of magnitude above those for other rendering algorithms.
A ray traced image by me.............
Mmmmmmm...................pretty.
Begin by defining a coordinate system. Use whatever system you like, be it left-handed, right-handed, left footed, or spherical, but be consistent. Vector math goes horribly wrong if you intermix coordinate systems without proper conversion. Rays will end up shooting out the back of your head and will likely blind fellow students, thus creating a tangled web of litigation and debugging which could have otherwise been avoided. For example, let's use a left-handed coordinate system with unit vectors n0, n1, and n2, such that if you are looking in the n2 direction, n0 would be to your right, and n1 would be straight up through the top of your head.
Second, create a camera by defining its position Pe, say at the origin (0,0,0), and view direction, Vv, in the ONE world space coordinate system you previously defined, say n2. Now, to keep your head from spinning, define an up direction,Vup, for the camera. Any up could do, but choose n1 for simplicity. So basically the camera is aligned with the world space coordinate system.
Third, define an image plane at some distance, d (in the n2 view direction), of size S0 in the n0 direction and S1 in the n1 direction. From here, it is intuitively obvious that (I always wanted to say that)
Pp = PE + (d)n2 + ( (2i/S0)-1 ) (S0/2) n0 + ( (2j/S1)-1 ) (S1/2) n1where Pp is the world space location of the pixel (i,j). Since it is not obvious, I'll explain (unlike a lot of bastard Aerospace books I know). The idea is to shoot a ray through every pixel on the image plane. This means you have to find the ray vector from the camera to the center of each pixel (i,j) by simply adding unit direction vectors until you get to the pixel of choice. The above equation does exactly that by starting at the camera location Pe and adding the vector to the center of the image plane by going the distance, d, in the n2 direction. Now you need to move to pixel (i,j) from the center of the image plane which will involve adding or subtracting two vectors, one in the n0 direction and one in the n1 direction (because you were smart enough to align your camera with the world space coordinate system). The maximum vector lengths will be half the width (S0) or height (S1) of the image plane, which is where the length divided by two portion of the equation comes from. The first terms of the vectors represent the relative location of the pixel on the image plane, scaled so the vector will range between 0 and 1.
Now, subtracting the camera location from the pixel location defines an "inverse" ray which has traveled from a light source, through your scene, and into your camera. Any point on the ray can be defined as
P = Pe + n t, where n is the unit vector along the ray and t is a distance along the ray greater than or equal to zero.
Now hit render and out pops the image...........you wish (of course, if you were really smart you'd use a commercial ray tracer instead of writing your own because, odds are, they've done it better and made it faster. But that's neither here nor there). To render anything, a light source needs to be defined. We'll use a point light source with no falloff since it is the simplest case: rays travel in all directions equally. For this all you need is to do is define the location of the light in your world space. Try to keep it outside of the objects you put in your scene or you'll spend hours debugging when you render black images. Coding more complicated light sources will be left as an exercise for the student (yeah, right).
OK, by now you are either sleeping because you've already done this stuff, you are sleeping because you haven't done this stuff and hate math and programming, or you are sleeping because you've been pulling all-nighters even though you might like to know more about how ray tracing works. I'll deal with the third group first: take Ergun's VIZA 656 course in the spring (all you 654 folks this semester KNOW you want too!). Second group: I'll stop using math from now on (with a few exceptions). First group: have a nice nap.
Once you have a camera, some rays, and a light source, you need to place an object in your scene. Objects which can be defined by a single parametric equation, such as a sphere, are simple to ray trace. For each ray, determine if there is an intersection with an object in your scene. This is done by substituting the ray equation into the object equation (for a simple case) and solving the resulting quadratic equation for real values of 't'. If a real value exists, plugging 't' back into the ray equation yields the intersection point of the ray and an object. If two real values exist for an object, the smallest value represents the intersection point closest to the camera, i.e. the potentially visible point.
With an intersection point you can determine the unit vector to the light source and then calculate the angle between the unit vector and the surface normal. If the angle is between 0 and 90 degrees, the point will be visible to the camera (assuming no shadows) and a color can be determined by adding the contributions of diffuse, ambient, and specular color (similar to the shaders written for Renderman assignment #2). Your objects and associated attributes can be defined in an external text file.
If the object is reflective, you would follow the same ray tracing procedure from the first object intersection point, to the second, to the third, etc., until there were no more object intersections, until a maximum number of reflections had been executed, or until the effective reflectiveness of objects diminished to a point where they made no significant contribution. You would then calculate the current pixel color by recursively adding contributions by all objects intersected from last to first. Repeat the process for every pixel and write out the image data.
Tracing rays through a scene with reflective objects can be extremely time consuming. Consider adding anti-aliasing to the software by averaging the computed colors of multiple rays shot for each pixel. Then consider averaging computed colors of multiple rays shot for each pixel for each reflected ray of every intersection. The number of compute cycles and headaches increase exponentially. Plus, tack on the fact that with reflections, you can't (well, you could, but it doesn't happen in the real world) cull objects which are outside the viewing area of the camera since they could appear in reflections of objects that are. This is one reason why Renderman can't render reflections. Renderman culls objects which are outside the cameras viewing area, and objects are broken down into subpatches before shaders are applied. Since the subpatches no longer have ties to the surrounding geometry, only the object (and light) shaders are considered. Reflected colors could not be added into the equation.
So, ray tracing: use it, don't abuse it, and have a great Christmas break (get the hell out of town!).
References
Akleman, Ergun. Course Notes, VIZA 656, Spring 2000.
Glassner, Andrew S. An Introduction to Ray Tracing. New York: Academic Press, 1990.
Stevens, Roger T. Fractal Programming and Ray Tracing with C++. Redwood City: M&T Publishing, 1990.
Watkins, Christopher D., Stephen B. Coy, and Mark Finlay. Photorealism and Ray Tracing in C. New York: M&T Publishing, 1992.