CSE168
Spring Quarter, 2004
Assignment #4
Student: Alex Kulungowski
Title: Glasslich
Techniques implemented during the course of this assignment:
transparent (refractive) materials including Fresnel effects and Beer's Law
soft shadows
antialiasing
caustics photon mapping
Perlin noise w/ turbulence
embarrassingly parallel ray tracing (scatter decomposition) with MPI
Summary Description
Earlier in the quarter, I found the following 3-D model of the bones of the
human hand and decided I'd work it into my final project for CSE168:
http://www.cc.gatech.edu/projects/large_models/hand.html
I figured a ply-to-obj translator would be an easy thing to find. The only
translator that turned up went the wrong direction, however, so I had to write
my own:
#!/usr/bin/perl -w
use strict;
my $filename = "hand.stripped.ply";
open(FILE, "< $filename") or die "Can't open file, $filename: $!\n";
my @verts;
my @normals;
my @triples;
my $float_pattern = "(-?\\d+(?:\\.\\d+)?(?:e-?\\d+)?)";
#Whew. I should have used scanf()...
while (my $line = <FILE>)
{
if ($line =~ m/^$float_pattern\s+
$float_pattern\s+
$float_pattern\s+
$float_pattern\s+
$float_pattern\s+
$float_pattern\s*$/x)
{
push(@verts, "v $1 $2 $3\n");
my ($n1, $n2, $n3) = (-$4, -$5, -$6);
push(@normals, "vn $n1 $n2 $n3\n");
}
elsif ($line =~ m/^\d+\s+(\d+)\s+(\d+)\s+(\d+)\s*$/)
{
my $one = $1 + 1;
my $two = $2 + 1;
my $three = $3 + 1;
push(@triples, "f $one//$one $two//$two $three//$three\n");
}
else
{
die "Unrecognized line: $line\n";
}
}
close(FILE);
$filename = "hand.obj";
open(FILE, "> $filename") or die "Can't open file, $filename: $!\n";
print FILE @verts;
print FILE @normals;
print FILE @triples;
close(FILE);
The first iteration of the above script had some problem with the normals, and
for a while I wasn't even sure the normals supplied were anything other than
the boring planar (from the triangle's perspective, that is) variety. After
generating some test scenes for comparison, I convinced myself otherwise:
Planar Normals

Nonplanar Normals

I then set about implementing transparent materials, which proved to be a
rather frustrating experience due to errors stemming from an inconsistent
mixture of normalized and unnormalized ray directions. I have to blame
Shirley for some of this: he's the one who suggested leaving ray directions
unnormalized in order to facilitate instancing -- a technique I didn't even
use. I feel much more comfortable with everything normalized, anyway, and
it turned out to be very necessary for transparents for some reason:

You can't really tell from the above image, but I also include Fresnel effects
and Beer's Law in the lighting calculations for transparent materials. In the
final image, the effect of Beer is very noticeable.
For my scene, I initially had the following idea:

I don't have a modeling program, and Ayam kept crashing my machine, so the
scene I finally settled on is not much more complicated than the above, at
least geometrically.
Next I implemented soft shadows and antialiasing, which I unfortunately do
not have any example scenes for aside from the final images. They demonstrate
both techniques quite nicely, I think.
I then built a caustics photon map using photonmap.cc to trap LS+D photons. I
set things up so that only specific objects are illuminated by caustics
photons. I knew the floor was a caustics target, but wasn't too sure about the
sphere. Either way didn't seem to make much difference:
Sphere Without Caustics

Sphere With Caustics

I considered implementing a global photon map, as well, but I'd already set my
mind on a scene with a lot of specular materials, so I figured it wasn't really
necessary. By this time, I'd included the Perlin noise and turbulence code I
found in Texturing and Modeling: A Procedural Approach, Third Ed. with
an eye toward approximating marble:

There are some obvious problems with the above image. The shadows are clearly
aberrant, the caustics beneath the hand are too bright, something is amiss with
the sphere, and, to use the vernacular, the marble just ain't. I tried
a couple of off-the-cuff ideas, including covering the slab with a pane of
clear material:


It didn't work too well, though I did like the greenish color of the glass.
And what's with the sphere?
It turns out the bottom of the sphere intersected the slab and the caustic was
actually illuminating the part of the slab inside the sphere. Adjusting the
center of the sphere finally gave me the caustic I'd been looking for:

Even though I was partial to the lower turbulence Perlin noise, it didn't
exactly look like marble. I cranked up the frequency of the turbulence and
got something different, if not more "realistic".

Now I wanted the hand have some more of that Beer-inspired greenish tint to
it. I increased the depth of the ray tree and added some more diffuse color to
the glass.

By this time, I realized how tired I was of waiting for things to render on my
phlegmatic 450MHz PIII, so I fired up my account on ACS's Beowulf cluster,
Valkyrie, and parallelized miro using MPI. I used an embarrassingly parallel
technique called scatter decomposition, which is a highfalutin' way of saying
that I randomly assigned pixels to processors and carried out normal ray
tracing from there. I'd parallelized an unaccelerated, non-Monte Carlo ray
tracer two quarters ago, but since my version of miro has quite a bit of
pseudorandomness to it, I knew that I would have problems with seed values.
This indeed turned out to be the case:



There were two conflicting PNG issues I needed to deal with. First, all of
the Monte Carlo techniques require a different stream of random numbers for
each processor. The SPRNG solved this problem. Second, the Perlin noise needs
the pseudorandom number stream to be the same on all processors. I just
hardcoded an arbitrary time in the call to srand() and left the calls to rand()
in the Perlin noise function unaltered.
This is the first image I successfully rendered on Valkyrie (the noisy shadows
are the result of using one random sample on the area light):

Finally. The finished scenes. This is an early image rendered on the
aforementioned PIII. Considering the amount of time it took to render, and
with the sphere looking like it does, you can imagine my disappointment.
Actually, I wasn't that disappointed by the sphere; the scanning artifacts on
the hand are another matter entirely:

This is a scene produced by Valkyrie. The psuedomarble now has a specular
sheen to it:

This is my submission for the rendering competition. It was produced on
Valkyrie, as well:

Here is the serial code for the assignment without images or mesh:
Code only: CSE168_assignment4_code.zip
Here is the serial code for the assignment including images and the
hand mesh. This file is quite large (> 20MB):
The whole enchilada: CSE168_assignment4.zip
Here is the parallel code. It does not include any images or the mesh:
Parallel code: CSE168_assignment4_parallel.tar.gz