Introduction:
For my final project, I wanted to make better looking
images come out of my very limited raytracer.
Specifically,
I looked to dampen aliasing effects caused by discrete sampling and
hard shadows caused by point light sources.
There are two approaches that I have implemented, a jittered supersampling
approach and a contrast-driven super-
sampling approach that is more effiecient for similar output.
I will discuss these in order.
Jittered Supersampling with Area Light Sources
The raytrace_with_planes2.m matlab file allows the
user to specify the object space, resolution, supersampling
resolution, and the support of gaussian blur used in the reconstruction.
Here is how the method works:
-Create an image of resolution*n^2
jittered samples, where n is the resolution multiplier the user specified.
The n^2 samples per pixel
are from randomly generated (uniform distrobution) rays in the pixel area.
Further,
the shadow rays cast upon
intersection are jittered in their direction, to approximate an area light
source. The
multiple samples per pixel
allows a nice averaging to take place in the penumbra (area barely in shadow).
-Reconstruct the final image
from the samples. The user-specified support for the gaussian filter
is in terms of
the final image pixels.
The filter is applied over 3x3 pixel areas to obtain the final image.
The issues I ran in to were in reconstruction. The gaussian serves
as a weighted average filter around a pixel. But
in order to know how to weight a particular sample in the support area,
we needed to remember where that
sample's ray jittered to, as it was randomly placed within the pixel's
area. Also, the sum of all the weights used in
the calculation of a pixel value must be 1 in order to avoid flooding
or dimming, no matter how many samples
were involved in the calculation (as there are fewer along the edges
of the image). Lastly, I noticed that gaussian
used in reconstruction, if too large, produces badly blurred pictures,
while if too small, leaves aliasing in the image.
It was difficult to find a balance.
The program creates good looking images. I
noticed a tradeoff in the number of samples per pixel verses the
extent of penumbras in the image. A large area light source produces
speckle in the penumbra unless (I believe)
exponentially more samples are cast per pixel. Also, though the
distrobution over the pixel's area is supposed to
be uniform, I found that a jaggy effect still occurs in the jittered
supersampled image (see figure 3). I cannot
explain this except to say that tying what should be a random ray's
direction to the center of a pixel may lead to
non-uniformity in the overall image's sample distrobution. Below
are example outputs.
Figure1: (left to right, top to bottom) Progression of scene.
1. Classic one sample per pixel ray trace. 2. Filtered
with a gaussian in an attempt to ease the hard shadows.
3. 64 jittered samples per pixel with a large
area light source. 4 and 5. Successively smaller light sources
to lessen the speckle found in 3. Image 5 looks great.
Figure 2: Closeup for comparison. On the left is my program,
on the right the original raytracer.
Figure 3: 1. Original raytracer output. 2. My program's
better output. 3. Original convolved with a small filter.
4 and 5. A very small version of the
jittered supersample image and a closeup.
The jittering was at 64 samples per pixel, and the output is a 256x256
image, so 4 is a 12 MB bitmap.
Notice a jaggy effect is visible, though noisier
than it would be otherwise. In that I could spread around the dots
on one of these borders in a way
that would make a nicer image, I feel this supersampled
jittering may not produce an ideal distrobution (lead in to Mitchell's
stuff below). However,
it may just be a programming artifact (I explain):
this jitter image is stored as a 2d array and while the rays cast being
stored in the array are grouped
by the pixel they belong to, there is no garanteed
order within the samples for a pixel--they are just random jitterings from
the center of the pixel.
This sounds convincing.
An Implementation of Don Mitchell's SIGGRAPH '87 Paper
("Generating Antialiased Images at Low Sampling Densities")
This was a cool paper and easy to understand.
One of the few papers where implementation details were not
completely dense (kinda makes you wonder why it would be accepted).
There are three parts to the implement-
ation, which I will go over in order: low density initial sampling,
contrast-driven local supersampling, and reconstr-
uction. We start with by setting a grid over the image we are
making that is "4 times finer than the display pixel
lattice (i.e., there are 16 grid points per pixel area)" (p.66).
We will work with this sampling space throughout.
As we made note of above, uniform distrobution jittered
sampling may not be ideal, and much work has been
put into finding a good all-purpose sampling. Mitchell uses efficiently
generated Poisson-disk samples as a low
density initial sampling of the object space, averaging about 1 sample
(out of the 16 possible) per pixel. The
equations quickly are (for a potential sample point):
T
= (4*D(i-1,j) + D(i-1,j-1) + 2*D(i,j-1) + D(i+1,j-1))/8 + (random in range
(1/16 +- 1/64))
SELECT = {0(no) is T < .5; 1(yes) otherwise}
D(i,j) = T - SELECT
the
X's are determining factors in whether or not O will be an initial sample.
So what are related to diffusion values for previous potential samples
are combined to determine a diffusion for
the current potential sample and decide whether to take a sample at
the current place. The resultant sparse (in
terms of the 16 grid points per pixel lattice) sampling can now be
tested for high-contrast areas.
We would like to supersample in areas of high contrast
in order to keep as accurate information as possible
about the space we're imaging. For the samples within a 3x3 pixel
area (or 12x12 in the finer lattice), find the
following contrast for the three color channels:
C = (Imax-Imin) / (Imax+Imin)
The thresholds for each channel have been found experiementally: .35,
.25, .5 for red, green, blue respectively.
If the threshold is passed for a particular area, then randomly choose
another 8 or 9 samples per pixel in the
area (so 72 more than are already the low density samples we just considered).
There are two potential problems with my implementation
here. First, the contrast testing window is not
moving smoothly throughout the samples--the windows are non-overlapping
(as can be seen by the square
supersampling areas below). This may introduce (or keep) some
of the same aliasing problems we are trying to
get rid of. However, this would only leave blurred splotchiness
as evidence, where areas that maybe should
have been supersampled were just barely missed (notice that there is
not a continuous supersampling of the
planar intersections in figure 5 below). Secondly, I pick the
72 more samples in an area I wish to supersample
by uniformly distributed randomness, selecting a grid point for sampling
if I have not picked it yet. This may
introduce into the supersampling the same element of uniform distrobution
that above created the noticeable
jaggies in the jittered sampling. The images look good however,
and I am not sure how this potential problem
would express itself in the end.
The final stage is reconstruction. This is
done with the application of successively larger weighted-average
filters, because of the properties Mitchell found them to have in terms
of alliasing, as well as so that dense
sampling does not dominate final color computation. First we
apply a half-pixel squared (or 4 fine grid points)
filter on the samples. We don't include unsampled grid points
in the computation (they are not considered
zero). This leaves an image of point samples that have spead
out a little. Apply the filter again and the samples
get even wider support. The last step is a full pixel averaging--so
over the 16 grid points and their samples (if
they were sampled) per pixel, simply average. One may wonder
why the support of this last averaging filter is
only one pixel and not more as would usually be required to produce
antialiased images. The successive app-
lications of the 2x2 filter took care of introducing color elements
from neighboring pixels.
There were only a couple of issues I ran into in
implementing this part. First, as with the gaussian reconst-
ruction in the previous section, we need to remember how many and which
samples were in a given filter app-
lication, so that we can normalize the sum of weights to prevent flooding
or dimming. Secondly, the 2x2 filter
I apply twice computes under this support: ,
where XO is the sample value being recomputed, based
on all four. In that I always apply this filter left to right,
top to bottom, I may be accentuating (or dampening
less) certain image attributes (the weights clockwise from XO might
be .4 .22 .22 .16 for example). It might
be cool to apply the filter once left-right-top-bottom, and then the
second application be right-left-bottom-top.
This may make the support of the overall filtering a little wider for
better smoothness (though more blur). In
fact, this dilemma is similar to the Poisson-disk sample generating
done above, where Mitchell mentions that
scanning back and forth (like an ox on a field...) instead of left
to right all the time may help isotropy (though
he did not implement it). Also, the filters applied during the
reconstruction are smoothly convolved with the
samples (the windows do overlap, not as before for the supersampling).
Lastly, I just want to note that after
spending hours making small changes to the coefficients in the averaging
filters, I gained almost no additional
intuition about the reconstruction phase (all the pictures look pretty
similar, regardless of variation in the
weights).
And that is my implementation of Mitchell's
low sample density antialiased image creation algorithm.
Example figures are shown below.
Conclusion
For my final project, I looked into ways I could
make my simple raytracer produce prettier pictures, in terms
of aliasing and hard shadows. Firstly, I implemented a (user
specified) high density jittered supersampling
approach with jittered light vectors to simulate area light sources.
I got good results but was dissappointed by
the excessive computation and the easy-to-overblur nature of the algorithm.
In response I implemented an algorithm described
by Mitchell in a SIGGRAPH '87 paper. I end up with
similar quality pictures at a small fraction of the computational cost
of my first program. There is very little
aliasing and much less blur than before. But I have come to believe
that we can never really finish the job of
making the best image possible, as there are so many directions to
look for it in, with different sampling and
supersampling and reconstruction techniques.
Figure 4: Progression of Mitchell's algorithm: A grid at 4x final resolution
will be non-uniformly sampled. 1. Low density Poisson disk sampling
points (~1.2 samples per pix).
2. The low density initial sampling (look closely).
3 and 4. Contrast driven adaptive supersampling (~8 additional samples
per pixel) and the resultant samples. 5 and 6.
Successive applications of a two by two (half pixel
squared, in terms of the final resolution) weighted-average filter.
7. Application of the 4x4 (full pixel) box filter. 8. The
classic raytraced image, for comparison. 7
and 8 are 64x64 pixel images shown at the supersampling resolution of the
others.
Figure 5: Same progression of Mitchell's algorithm as above.
I believe the empty dots in the seventh image (the final image in the progression)
are because of areas that were
completely empty of samples, which is pretty unlikely.
Figure 6: (clockwise) comparison of Mitchell's, classic single sample
per pixel, and my
16 sample per pixel (no matter what) approach from
above. Of course, my Mitchell
implementation provides similar quality for a small
fraction of the raytracing time.
Think of the last approach as having a pure-white
sampling density in the figure 4
progression above.
Figure 7: My Mitchell implementation (left) verses my raytrace_with_planes2.m.
The
images are at 64 pixel resolution, zoomed in for
better comparison. I would say
that they are similar enough for the fraction of
computation that Mitchell's requires.