I built a ray tracer that renders spheres
and planes and accounts for reflections and
refractions. Here are some pretty pictures from
hand-input models. Once I get the
input file parser working, I would be able to show more
pictures.
The code:
My ray tracing model is the One True
Way. Basically, a center of projection, a
direction of view, and a focal length (and an assumption
of 36x36 mm image plane)
provide a basis such that a ray cast from the eye through
a pixel (i,j) on the film is of
the form :
cop + (vector to lower left of film) + i*a + j*b
where a and b are orthogonal vectors that span the film.
Then it's a simple double
for loop.
I have one RayTrace function that
can call itself recursively (if the reflection index
or transparency is non-zero). Starting at a point,
and extending along a vector, it
computes the minimum positive (up to machine error) scaler
to extend the vector to
hit the closest object. It does this by iterating
through all the objects in the scene
(ouch). The function then computes lighting for
the closest object hit, or returns the
background color if nothing was hit. If there are
reflection and/or refraction compon-
ents, the function is called recursively for them, and
the returned colors are factored
into the final color returned.
After some issues with specular highlighting
(as described below), the lighting at a
pixel is now just about:
[1-(transparency + reflection)]*(diffuse and ambient)
+ transparency*(color from transparency ray)
+ reflection*(color from reflection ray).
Then I add to that the specular component computed from
the material properties.
Notes:
This was a lot of work, mostly in the
bug fixing area. One peculiar example was
the eleven hours I spent finding the source of intricate
designs in transparent objects.
What was happening was my rays were getting stuck on
the inner surface of the
object intersected. So for example I shoot a ray
that hits a transparent sphere. Since
there's a non-zero transparency, I then shoot a ray--independent
of all others ever
shot--starting at one side of the sphere, in the direction
of the other side, to get more
color components. But when I compute the minimum
positive intersection distance
of a ray with a sphere, I sometimes return a number that's
just barely positive, like
10^-15. So my ray would go nowhere during all the
recursions, and black would
end up as the color of the first transparency ray.
Since there are only two cases, I
would get either a nicely colored ray that got through,
or one that got stuck, but in
a very deterministic pattern if I aligned the sphere
in just the right way with the axes.
I haven't recreated the pictures since I fixed the problem
for lack of time.
There was also an interesting hack
that I used to get spcular highlights to show up
on the completely reflective balls picture above in the
point light source environment.
The typical reflection ray off of one of these balls
would not pass through the point
light source. But it may pass at a close enough
angle so that a piece of the light's
color should come back as part of the returned color
for the ray. So separate from
other things going on in the ray trace function, I check
the angle of the current ray
compared to the other light sources. If the angle
is within ~20 degrees and the light
is not occluded by an object, I'll add a piece of the
light proportional to the dot of
the light vector and the current ray raised to some power.
I only add a piece of the
light with the closest angle. Below is an example
of how this might go wrong.
What I've ended up doing about the
lighting hack is leaving it only when I am
otherwise going to return a background color for the
ray (the light is outside the
scene). In order to get specular highlights on
a reflective or transparent object, I
don't temper the specular computation by the reflection
and refraction amounts
(see above).
Notice on the left, lights aren't rendered. My hack for adding
light color to a ray, rather than rendering the
light explicitly, made this scene look awful (on right). In general
the lights should be outside of the scene for
this method to look reasonable.
Here, the camera is actually inside a sphere with a refractive index
of like 1.5. You can
see some distortion, but my intuition as to why there isn't more is:
The image plane is
very close to the surface of the surrounding ball, not leaving much
room for distortion.
Also, this model is lit with the final version of my lighting (namely,
adding the specular
component after all else has been factored into the color returned).