Thursday, April 9, 2009

Adding a Fresnel term

I've attempted to add a Fresnel term to the dielectric.

To start, I rendered a sphere with an index of refraction of 1.00, no Fresnel term, no reflections:


Here's another sphere, no reflections, index of refraction 1.33:


Now with a Fresnel term, index of refraction 1.00:



Also with a Fresnel term, index of refraction 1.33:


Those last two images don't look quite right. The reflections are way too strong and are pretty blown out.

I believe that I'm using the equations at http://en.wikipedia.org/wiki/Fresnel_equations to add the Fresnel term.

Tuesday, April 7, 2009

Dielectrics

Here's a couple of images of a pieces of "green glass." In this first image, both mediums have an index of refraction of 1.0:

In this next image, the index of refraction starts as 1.00, but then changes to 1.39:
Reflections are currently not implemented. Notice where total internal reflection begins? Notice how the rays are bent away from the viewpoint? This is what I would expect when the index of refraction becomes greater.

Here's an example where the transition is from 1.39 to 1.00:
Notice how the rays are bent towards the viewpoint?

I suspect that these images may be correct, well, as correct as they can be without implementing reflections and using a Fresnel term to make sure that energy is conserved.

I'm using Snell's law to calculate the direction of the refracted rays

Friday, March 27, 2009

Assignment #5a

Assignment #5: Acceleration Data Structures

Try #2. Differences noted a bit later

This assignment adds the Octree primitive for improved performance. The ability to load OBJ files has also been added.

Get the code here

How to get and build the code:

wget http://cs.unm.edu/~jbowles/cs413/a5/jbowles-assign5a.tar.bz2
tar jxf jbowles-assign5.tar.bz2
cd jbowles-assign5
make
./raytracer --width=512 --height=512 --reflections --shadows --maxdepth=20

For testing, I used a type of "Sphere Flake" built with approximately 2 million spheres. The octree dramatically sped up the rendering process.

Total number of spheres: 2,015,539
Without Octree With Octree Change
Time to build sphere flake (s) 1.5 1.5 0
Time to build Octree (s) N/A 45.5 N/A
Time to render (s) 76883 49 76834
Total time (s) 76885 96 76789 or 99.87% increase


Here are the images generated with the two different methods. The octree looks slightly different - notice the darker patches and the small chunks missing on the outside of the sphere flake. While this image looks very similar to my first post about assignment 5, smaller sphere flakes rendered properly, which was not happening before, and this larger octree took about 18 seconds longer to render and longer to build. Things are clearly getting better, but improvements still need to be made. My improvements consist of fixes to stupid coding errors.

Image of scene without octree:
Scene with octree:

What's different between #5 and #5a? Well, I made a couple of stupid mistakes.

1) Traversal: for(int i = 0; i < 7; i++) will not traverse all 8 child nodes. Duh. Incredibly stupid mistake.
2) ounding boxes needed to have the min and max corners forced. Like #1, stupid mistake
3) Rays that start inside of bounding boxes don't have their intersections calculated properly. Obvious once I thought about it, no fix implemented yet.

I've implemented fixes for 1 & 2, but not three. I tried backing off the camera to avoid #3 but still see some issues. Things are getting better.

Tuesday, March 24, 2009

Assignment #5

Assignment #5: Acceleration Data Structures

This assignment adds the Octree primitive for improved performance. The ability to load OBJ files has also been added.

Get the code here

How to get and build the code:

wget http://cs.unm.edu/~jbowles/cs413/a5/jbowles-assign5.tar.bz2
tar jxf jbowles-assign5.tar.bz2
cd jbowles-assign5
make
./raytracer --width=512 --height=512 --reflections --shadows --maxdepth=20

For testing, I used a type of "Sphere Flake" built with approximately 2 million spheres. The octree dramatically sped up the rendering process.

Total number of spheres: 2,015,539
Without Octree With Octree Change
Time to build sphere flake (s) 1.5 1.5 0
Time to build Octree (s) N/A 34.5 N/A
Time to render (s) 76883 42 76841
Total time (s) 76885 78 76807 or 97.3%
Intersection Tests 629019024 588972081 4004693
Failed Intersection Tests 608663340 527464523 81198817
Percent successful intersection tests 3.2% 10.4% 7.2%


Using the octree results a 97.3% speed increase. Very nice. However, I'm surprised by the number of intersection tests that still have to be performed. This makes me wonder if I'm counting those correctly.

Here are the images generated with the two different methods. The octree looks slightly different - notice the darker patches and the small chunks missing on the outside of the sphere flake. This seems to indicate that some of the spheres didn't make it into the octree voxels.

Image of scene without octree:
Scene with octree:

Friday, February 27, 2009

Assignment #4

This assignment adds texture mapping and antialiasing to the basic raytracer in assignment #3.

There are two texture maps and mapping methods:
  1. A PNG image of the earth mapped to a sphere using a transform from XYZ coordinates to spherical coordinates.
  2. A procedural checkerboard texture map for the plane. The color for the plane is calculated based on the intersection point.

The antialiasing technique used fairly simple. It takes the number of samples requested and generates that number of equally spaced rays through the corresponding pixel. Each ray's color is determined and the colors are averaged

Adding some jitter to the samples will provide better antialiasing. It would have been added to this version of the ray tracer, but too much time was spent rewriting the code from the previous assignment and fighting with C++. It isn't C++'s fault that my coding skills are rusty. That's my excuse for the simplistic antialiasing :)

The antialiasing removed the jaggy edges from the spheres, triangles and checkerboard pattern on the plane. It also made the earth texture less speckled.

The difference between 16 samples/pixel and 128 samples/pixel is subtle. I suspect that if the surfaces were not being modeled as perfectly smooth that the difference between 16 and 128 samples per pixel would be much more noticeable.

Interestingly, the rewrite sped up rendering by 60%. This was very surprising considering the number of abstractions added to the code.


tar jxf jbowles-assign4.tar.bz2
cd jbowles-assign4
make
./raytracer --width=512 --height=512 --reflections \
--shadows --samples=16


Usage: ./raytracer [options]

options:
--width Window width
--height Window height
--reflections turn on reflections
--maxdepth maximum number of reflections
(default 3)
--shadows turn on shadows
--samples square root of the number of
samples per pixel.
--perf turn on performance measurement
rendering

To exit, pressing Apple-Q, escape, or just q.


Output generated on a MacBook Pro 17" 2.4GHz dual core. Size of each image is 512x512. Each image can be clicked on to view a larger 1280x1024 version.

1 sample/pixel:
4 samples/pixel:
16 samples/pixel:
32 samples/pixel:
128 samples/pixel:

Alternate viewpoints:





Render times:
Samples 512x512 render time (s) 1280x1024 render time (s)
1 0.323498 1.716881
4 1.189341 6.245954
16 4.617202 25.190776
32 7.222273 39.810833
128 36.107344 188.703291

Friday, February 13, 2009

Assignment #3

Assignment #3 - basic ray tracer. Features:
  • Diffuse lighting
  • Ambient lighting
  • Specular highlights
  • Shadows
  • Reflections
  • Simple anitialiasing
  • High dynamic range color
  • Geometric objects: spheres, planes, triangles
  • Perspective is maintained regardless of requested window size - pixels remain "square"
How to build and run:
Platform: Mac OS X 10.5.6, XCode 3.0 / gcc 4.0.1

tar jxf jbowles-assign3.tar.bz2
cd jbowles-assign3
make
./raytracer --width=512 --height=512 --reflections \
--shadows --samples=3

Usage: ./raytracer [options]

options:
--width Window width
--height Window height
--reflections turn on reflections
--maxdepth maximum number of reflections
(default 3)
--shadows turn on shadows
--samples square root of the number of
samples per pixel.
--perf turn on performance measurement
rendering

To exit, pressing Apple-Q, escape, or just q.

Output generated on a MacBook Pro 17" 2.4GHz dual core. Size of each image is 512x512.

./raytracer --width=512 --height=512
1.114634 seconds to render
Number of rays: 262144



./raytracer --width=512 --height=512 --shadows
1.161857 seconds to render
Number of rays: 446464



./raytracer --width=512 --height=512 --shadows --reflections
1.270463 seconds to render
Number of rays: 693328



./raytracer --width=512 --height=512 --shadows \
--reflections --samples=5
32.375095 seconds to render
Number of rays: 17334027

Optimizations

It was time to optimize my raytracer and gprof turned up something unexpected: most of the time was being spent in vec3f constructors. I expected most of the time to be spent checking for intersections. It was time to turn on gcc optimizations.

The result: the constructor calls disappear after passing either a -O or -O1. Best performance was to be had at -O3.

This raytracer is being compiled on a MacBook Pro 17", 2.4GHz Intel Core 2 Duo with 4GB of RAM. gcc:

gcc -v
Using built-in specs.
Target: i686-apple-darwin9
Configured with: /var/tmp/gcc/gcc-5465~16/src/configure --disable-checking -enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.0/ --with-gxx-include-dir=/include/c++/4.0.0 --with-slibdir=/usr/lib --build=i686-apple-darwin9 --with-arch=apple --with-tune=generic --host=i686-apple-darwin9 --target=i686-apple-darwin9
Thread model: posix
gcc version 4.0.1 (Apple Inc. build 5465)

Image size: 512x512, 1 plane, two spheres, 1 triangle. Average run times for 5 runs each:
Average Run Time Optimization Debugging and profiling
1. 8.1604598 None yes
2. 2.0264776 -O yes
3. 2.036941 -O1 yes
4. 2.2078138 -O2 yes
5. 1.2405112 -O3 yes
6. 1.2331454 -O4 yes
7. 1.1143894 -O3 no
8. 1.1208828 -O6 no
9. 1.1019208 -O4 no

Notes:

  1. 1. gprof shows that most of the time is spent in vec3f constructors

  2. 2. gprof shows that most of the time is spent in sphere and plane intersections,
    but I still see more calls than expected to vec3f constructors

  3. 3. This generates a different binary than the previous test and runs at approximately
    the same speed. Still more vec3f constructor calls than expected.

  4. 4. -O2 yields no real change from -O1

  5. 5. gprof yields expected results, big speedup from -O1 and -O2

  6. 6. Seems to be the same as -O4

  7. 7. Gained 1/10th of a second from dropping debugging and profiling

  8. 8. -O6 shows no gain over -O3

  9. 9. -O4 without debugging and profiling is 1/100th of a second faster than -O3, but that isn't big enough of a change to say that something changed. There could just be less load on this system.