<--Back to Projects
<--Home

COS 426 Assignment #3:Ray Tracing (Part 2)


Chris Tralie
Platform: Windows Vista SP1 Using Microsoft Visual Studio 2005
Assignment Specification


Ray-Scene Intersections


Handle scene traversals with modeling transformations (Corrected)

NOTE: My code only worked for pure translations last time, so I corrected it here
I keep a matrix that's the product of all of the transformations that have been done so far going along the scene graph. Every time the recursion goes a step deeper, multiply this matrix on the right by the newest transformation (NOTE: I multiplied on the left in the previous submission, which was a mistake and would only end up working for pure translations). This product of all transformations (I'll call it the "accumulation matrix") represents a transformation from the local coordinates of the specific object in question to the world coordinates of all objects.
Before checking the ray-primitive intersection at that step, multiply the ray by the inverse of the transformation matrix to put the ray back in the local object coordinates (where stuff is simple, like axis-aligned cones and cylinders and pure spheres). Then, perform the ordinary intersection tests. After the intersection has been performed, multiply the calculated intersection point and the normal by the accumulation matrix to put them back in the regular world coordinates, and recalculate t (since scaling may have occurred).

After I realized there was a mistake with my first implementation, I created a sort of "stress test" of a combinations of rotations, scales, and translations to test this. I did this because if these operations aren't done in the correct order, the results could be catostrophically different. Here's the (correct) result of the test below:
raypro scale.scn scale.jpg -width 400 -height 400


Accelerate ray-scene intersection with bounding box checks

Augment your code for ray-scene intersection to check whether a ray intersects the bounding box for each child of a scene graph node before calling R3Intersects recursively for that child. If the ray hits the bounding box, check the parametric value along the ray against the least parametric value seen so far for a ray-primitive intersection previously found during the same recursive traversal and avoid descending into the child if the parametric value of the ray-bbox intersection is greater. Note that the bounding box for each node is stored in the coordinate system of the parent node to facilitate these checks) (I forgot this the first time and had quite a nasty bug that took me hours to find).

Here are some timing differences for different scenes (with full lighting effects, secondary rays, etc. enabled to accentuate the differences).
CommandNo OptimizationBounding box optimization
raypro hierarchy.scn out.jpg -width 512 -height 5125.643 sec4.74 sec
raypro transform.scn out.jpg -width 512 -height 5126.713 sec5.556 sec
raypro dinopet_reflect.scn out.jpg679.473 sec40.188 sec(!!)

Note that the savings are huge when a mesh is in the scene (since it has to check every triangle for every ray if it decides that it needs to check the mesh), especially when secondary ray checking and shadow checking gets factored in (later).



Lighting


Phong Illumination



Phong illumination includes all of the "primary ray" terms in the above equation: direction emission from a source (IE), ambient reflection (IAL), and diffuse and specular reflections from each light in the scene (IL). There are also three different types of lights possible: point lights (attenuation with distance), spot lights (attenuation with angle from the source), and directional lights (no attenuation, and no change in direction, i.e. they are all parallel like rays from the sun). Below are some simple scenes demonstrating aspects of phong illumination:
NOTE: This is where things start to get exciting, because this is where color starts to appear instead of just black or white for whether or not an object was in the way.
NOTE ALSO: Only include reflections in the upper-hemisphere around a material (this applies for specular and diffuse reflections)

raypro sphere.scn sphere.jpg raypro cube.scn cube.jpg raypro teapot.scn teapot.jpg
raypro cylinder.scn cylinder.jpg raypro skewcylinder.scn skewcylinder.jpg raypro cone.scn cone.jpg
raypro hierarchy.scn hierarchy.jpg raypro transform.scn transform.jpg -width 512 -width 512 raypro materials.scn materials.jpg -width 1000 -height 1000
raypro spotlight.scn spotlight.jpg -width 512 -height 512




Texture Mapping


R2Pixel GetTextureColor(R3Intersects* hit)

The object is to come up with texture coordinates that pick out pixels in a 2D image to map to the 3D surface. The pixels in the texture change the kd parameter for diffuse reflections.
I use the following texture in all of my examples:

Textured sphere


I used spherical coordinates to make this mapping. That is, a position on the sphere is given by (theta, phi, R), where theta is the angle a vector from the center makes with the x-axis (ranging from 0 to 2PI) and phi is the angle it makes with the y-axis (ranging from 0 to PI) in the sphere's coordinates. I simply make the texture coordinates theta along the width of the image and phi along the height of the image (scaled so that 0 to 2PI spans the width of the texture for theta, and 0 to PI spans the height of the texture for phi):
raypro checker_sphere.scn checker_sphere.jpg -width 512 -height 512



Textured cylinder


Put this in cylindrical coordinates, and map the angle a point on the surface makes with the x-axis to points along the width of the texture, and map the height along the cylinder to the height of the texture.
raypro checker_cylinder.scn checker_cylinder.jpg -width 512 -height 512


Textured cone


raypro checker_cone.scn checker_cone.jpg -width 512 -height 512


Textured box


I use the following mappings to figure out which parts of the texture image get mapped to which parts of the cube:

raypro checker_box.scn checker_box.jpg -width 512 -height 512




Shadows


Every time an intersection occurs, cast a ray from the the point of intersection towards each light. If the ray intersects with another object in the scene before it reaches a light, then do not include diffuse and specular reflections for that light.
raypro forShadow.scn forShadow.jpg raypro forShadow2.scn forShadow2.jpg raypro forShadow3.scn forShadow3.jpg




Global Illumination


Specular Reflection


Trace a secondary ray from every ray-surface intersection in the direction of perfect specular reflection, compute the irradiance IR for that ray recursively, and include it into your illumination calculation using ks * IR. Rays should be traced up to the specified maximum number of ray intersections (max_depth) or until the luminance of the radiance along a ray is below a threshold (min_luminance)
NOTE: I added a feature to the debugger that traces secondary rays to a depth of 1 and draws them in green to show what specular reflections from other objects might look like:

Here are some results of this operation:
raypro dinopet_reflect.scn dinopet_reflect.jpg raypro dinopet_reflect2.scn dinopet_reflect2.jpg
(I changed the direction of the light here, so the shadow is different)

Transmission


Trace a secondary ray from every ray-surface intersection in the direction of perfect transmission (without refraction), compute the irradiance IT for that ray recursively, and include it into the illumination calculation using kt * IT. This is only done for non-opaque surfaces -- i.e., ones where kt is non-zero. Rays are be traced up to the specified maximum number of ray intersections (max_depth) or until the luminance of the radiance along a ray is below a threshold (min_luminance).
raypro transmission.scn transmission.jpg

Refraction


Trace a secondary ray from every ray-surface intersection in the direction of perfect refraction according to Snell's Law (instead of in the direction of perfect transmission), compute the irradiance IT for that ray recursively, and include it into the illumination calculation using kt * IT. This is done for non-opaque surfaces only -- i.e., ones where kt is non-zero. Rays are be traced up to the specified maximum number of ray intersections (max_depth) or until the luminance of the radiance along a ray is below a threshold (min_luminance).

Snell's Law:
N1 * sin(theta1) = N2 * sin(theta2)
Where N1 is the index of refraction of the medium the ray is in currently, and N2 is the index of refraction of the medium into which the ray is entering.

Re-arrange Snell's Law to get:
(N1 / N2) = (sin(theta2)) / (sin(theata1))
To to construct the new ray going out (V), use the following formula in terms of L (the vector going to the eye) and N (the normal at the point of intersection):
(NOTE: Lparallel is the parallel projection of L onto N, and Lperp is the perpenducular projection of L onto N)
V = -Lperp * (n1 / n2) - Lparallel * (sqrt(1 - ||Lperp2) / ||Lparallel||)
11.051.1
1.21.51.8




Interesting Scene


My Interesting Scene (The main file is room.scn). I tried to model my room (a screenshot of this is shown in the art contest submissions)



Art Contest Submissions






Expected Total Point Earnings for Assignment 3


Bold means required
OperationPoints
Generate a ray for each pixel1
Intersect a ray with a sphere1
Intersect a ray with an axis-aligned box1
Intersect a ray with a triangle mesh2
Intersect a ray with an axis-aligned cylinder2
Intersect a ray with an axis-aligned cone2
Intersect a ray with a scene1
Handle scene traversals with modeling transformations1
Accelerate ray-scene intersection with bounding box checks1
Phong Illumination2
Texture mapping1
Shadow Rays1
Specular Reflection2
Transmission1
Refraction2
Make an interesting scene1
Art Contest Submissions1
Total23

<--Back to Projects
<--Home