CS184 Assignment 4 Writeup

David Youngworth cs184-bw

Eric Abbott-Brenner cs184-ab

 

Features Intro

Our ray tracer fully implements all of the requirements for assignment 4. It supports triangle and sphere intersections, transforms, lights and shadows, materials and reflective surfaces from any camera angle and screen size, and it outputs the image to a .bmp file.

We have added a Lot of extra features to our raytracer. We have included commands and descriptions in this writeup. Our extra features include:

NOTE:

If you want to render any of these scenes yourself and aren't sure which of the scene texts we provide to use, just email us.

Commands

New Features

uniformgrid

Takes one integer argument. This command toggles the use of the uniform grid, which automatically sizes itself to encompass your entire scene. The argument specifies the number of grid cells to split the X dimension of your scene into. Use it to control the size of your grid cells.

supersample

Takes one integer argument. This command toggles the use of the supersampling antialiasing technique. The argument specifies the detail. If you put one, it will take 4 samples per pixel. If you give 2, it takes 9 samples per pixel. 3 will take 16, etc.

midzoneLuminance

            Specifies the midzone luminance value for tone mapping(one number argument).  Increasing this will increase the brightness of your scene.  This is usually a power of 2 multiplied by 0.18.

whiteLuminance

Specifies the minimum luminance value that maps to pure white(one number argument), setting this to a low number increases your brightness and causes brighter regions to tend to burn out(often a desired effect).

loadBumpMap

            One string argument.  Loads the indicated file as a normal map texture.

bumpMap

            One integer argument(an index value).  Sets the current bumpmap to be the bump map loaded at the given index(works like the vert specification in tri,

            the first bumpmap loaded corresponds to 0 and each subsequent bumpmap is one index ahead of the previous).  Setting to a value out of range

            (like -1) will result in the current bumpmap being set to null and no bumpmap is applied to the primitives you specify afterwards.

texCoord

            Six number arguments.  This specifies the current texcoords that are passed into the triangle.  For example “texCoord 0 0 1 0 0 1” will set the first vertex

            of subsequent tris to have texture coordinate (0,0), the second to (1,0), and the third to (0, 1).  Coordinate values greater than 1 will result in tiling.

loadTexture

            Same as loadBumpMap, but takes in a normal texture file.

texture

            Same as bumpMap, but applies a normal texture.

loadobj

Takes a string argument specifying the .obj file. This one command will load the .obj file and add it to the scene at coordinates 0,0,0. Use the materials and transform matrices to control the model location, size, and appearence.

Required in assignment

size

Takes two integer arguments, specifies the pixel size of the output screen.

maxdepth

Takes one integer argument, specifies the maximum number of reflected light bounces.

output

Takes one string argument, specifies the name of the output file (will add .bmp to the end)

camera

Sets up the camera. Takes 10 number arguments: first 3 specify the camera position 3D coordinates. The second 3 integers specify the coordinate the camera is looking at. 3rd 3 specify the camera's up vector. Last number specifies the view angle.

sphere

Places a single sphere in the scene. Takes 4 number arguments: first 3 specify the sphere's center's position. The last is the radius.

maxverts

Takes one integer argument, specifies the maximum number of vertices you can specify in your scene. NOTE: you must set this up before you add any triangles.

maxvertnorms

Takes one integer argument, specifies the maximum number of normal vertices you can specify in your scene. NOTE: you must set this up before you add any normal triangles.

vertex

Adds a vertex you can use for a triangle to your scene. Takes 3 number arguments which specify the 3D coordinates.

vertexnormal

Adds a vertex you can use for a normal triangle to your scene. Takes 6 number arguments which specify the 3D coordinate location and the normal vector.

tri

Adds a triangle to your scene. Takes 3 integer arguments. NOTE: You must add vertices first. The numbers represent the index of the vertices. The first vertex you added is at index 0, the second at index 1, etc.

trinormal

Adds a normal triangle to your scene. Takes 3 integer arguments. NOTE: You must add normal vertices first. The numbers represent the index of the normal vertices (which work the same way as the vertex index) The normal for the triangle is interpolated from the 3 normals given by each normal vertex.

pushTransform/popTransform

No arguments. This allows you to push or pop the current transform matrix from the matrix stack.

translate

Takes 3 number arguments. This adds a translation to the current transform matrix.

scale

Takes 3 number arguments. Adds a scale to current transform matrix.

rotate

Takes 4 number arguments. Adds a rotation to current transform matrix.

directional

Adds a directional light source. Takes 6 numbers argumnets. The first 3 specify the vector direction and the second three specify the rgb values (from 0 to 1)

point

Adds a point light source. Takes 6 number arguments. The first 3 specify the vector position and the second three specify the rgb values (from 0 to 1)

attenuation

Takes 3 numbers, and specifies the constant, linear, and quadratic attenuations.

ambient

Takes 3 numbers (from 0 to 1), specifies the rgb value for the ambient light.

diffuse

Takes 3 numbers (from 0 to 1), specifying the diffuse color of any object added after.

specular

Takes 3 numbers (from 0 to 1), specifying the specular color of any object added after.

shininess

Takes 1 number argument, specifying the shininess of any object added after.

emission

Takes 3 number arguments, specifying the emissive color in any object added after.

reflectivity

Takes 1 number argument, specifying the coefficient for reflected ray color to add in any object added after.

 

 

Basic Features

The raytracer fully meets all of the required aspects of project 4.

We used the freeImage library online to create our images rather than create a tga template. This gave us a lot of freedom in creating scenes of different file types and of using textures. We converted our .bmps to jpegs for this writeup to save some space, so some of the effect is lost.

Our raytracer can handle all of the provided test scenes. Here is scene 3: It demonstrates basic shape intersection detection, light and shadow tracing, and transforms.


scene3.jpg

Uniform Grid

We decided this would be the surest way to accelerate our raytracer.

We construct our grid dynamically so that after the scene is processed, the grid chooses a cell size based on the user specification. The user chooses how many cells should make up the X dimension of the grid. Then the grid constructs itself so that the entire scene is inside of it.

The grid traversal was a bit tricky because of finicky double number accuracy. It was difficult after a large number of cells to keep track of which cell you were currently in. We also had to account for rays that were going in a negative direction for a given dimension.

The nice thing about our grid array is that it dramatically speeds up scenes with a large number of light reflected bounces, because each ray from each bounce also uses the array to check for shadows instead of iterating through every object.

The situation where the speed up is most impressive is when there are many many objects. When we load a complex obj file or use a scene with 1000s of triangles, the grid means the difference between minutes of rendering and hours of rendering. In one of the example pics we created a scene with 3000 randomly placed reflective triangles, and it only takes 10-20 minutes to render.

The uniform grid (with a proper cell size) speeds up any of our scenes unless it has only one object. Each scene requires a little experimentation to find the optimal grid cell size.

 

This picture shows off the power of our uniform grid. There are 3000 highly reflected triangles in this scene. Rendering without an accelerator would be ludicrous. Rendering with the uniform grid takes under 15 minutes.


Office Map


Office Map

This picture is one of our best. The interreflections, lighting, and luminescence all make it interesting but also really makes rendering a pain. The uniform grid greatly improves performance on this scene.


Office Map

This picture uses many of the extra features we provide. The object loader allows us to add the ship. We are able to add texture to the ship. And we can render with 1500 randomly placed triangles (the stars) in well under 1/2 an hour because of our grid.


Office Map

Rendering .obj files

We thought it would be really cool to render object files so that we could use the raytracer with our models from hw 3. This was relatively simple to do, since we already had the support for normal triangles.

We used the nv object loader that was provided in hw 3 to load the objects into our code. We ran into some trouble because we had previously decided to use a different set of libraries for vector algebra (while nvModelLoader uses nv_algebra), but we got around that using a separate namespace.

The user can now add any .obj file he likes by using the loadobj command. Just like in OpenGl, the user can then place the object, transform it, add colors, or add textures.

Unfortunately, because we ran of time, we didn't have the chance code the loader so that any given object only has to be loaded once. To place two instances of an image, you currently have to load it twice.

Heres a simple scene with two intances of the godzilla model we made for hw 3.


Office Map

Luminance

We implemented the shading model indicated in the project documents which is essentially identical to the OpenGL shading model.  We also allow material properties to be set.  Most material properties work as in OpenGL.  Reflectivity is the coefficient for the reflected light term(so color at a point is colorBeforeReflections + reflectivity * colorOfReflectedRay).  There is a slight issue with reflections when the camera looks directly at a corner formed by two triangles(the corner appears completely dark) but this is easily resolved by adding a tiny fraction to one of the camera coordinates.  Ambient light is implemented as a material property because in the example scenes, different objects had different ambient terms.

 

We also allow the user to place point and directional light sources as indicated in the project specifications. The lights behave correctly under transformations (directional lights are unaffected by translation) and there is no limit on their number.  Additionally, the user can set attenuation with the command “attenuation const linear quadratic” as indicated in the project specifications.  The default is for there to be no attenuation.

 

Textures and BumpMapping

We implemented both textures and bump maps.  Their implementation is similar to the implementation in OpenGL.  We took advantage of the FreeImage library’s ability to detect the filetype of the image and so we allow any image format that FreeImage can recognize(tga, bmp, png, jpg, etc).  The bumpmaps are implemented using normal map textures (the z axis is aligned to the primitive’s default normal and the x axis aligned to the x axis in texture coordinates for triangles and the azimuthal unit vector for spheres).  Textures and BumpMaps are both filtered bilinearly.  We did not implement mipmaps.  The usage of textures that do not tile will result in a seam when applied to a sphere(because of how it’s mapped).  Below are images that show this off(the left is with supersample set to 1, the right is with super sample set to 2 and has both a texture and a  bumpmap on the sphere as well as a higher shininess value):

 

reflectiveTiles.jpg reflectiveBricks.jpg

Antialiasing

The last feature we implemented was antialiasing. Specifically we decided to do super sampling, since we were running out of time and that was the easiest to do.

The user can specify the level of sampling in their argument to command 'supersample'. Each pixel will get (n+1)^2 evenly placed samples (where n is user specified) and the average color our of each of the resulting rays will be placed for that pixel.

We didn't use antialiasing in most of our scenes because it multiplies our render time by a minimum of 4.

We did create a few scenes to demonstrate the usefulness of our antialiasing tool:

 

These pics were rendered at only 100 x 100 pixels. The first pic does not use anti aliasing. The second uses supersampling with 36 samples per pixel.


Office Map  Office Map

These pictures have a much higher resolution, but you can still see artifacts. The first pic does not use anti aliasing. The second uses supersampling with 9 samples per pixel.


Office Map  Office Map

This is one of our best images, and it’s made even better with just 4 samples of super sampling.


Office Map  Office Map
Office Map  Office Map 

 

And finally our code and executable:

 

Source Code

Executable



All textures and normal maps were obtained through google searches.