CS 455
Syllabus
Policies
Projects
Calendar
Slides
 
Project Overview
   Project 1
   Project 2
   Project 3
   Project 4
   Project 5
 
Old Quizzes
 
 

A Raytracer

The idea here is to either change the way things are drawn to make OpenGL-like syntax create ray-traced scenes or create a world through code that you can ray-trace. At the least, you will need to do the following:
  • Ray-trace spheres (you can either change the way you treat glBegin(GL_POINTS) and glPointSize(radius), or you can define a world with spheres. Either way is acceptable).
  • Allow for multiple lights.
  • Permit any camera location.
In practice, this will probably involve the following steps:
  • Method 1 (Change the code you have been writing thus far):
    • Leave the matrix stacks as they are, modifying points as they are generated before they are stored.
    • As points (spheres) and other objects are generated, you will need to store them all somewhere. You cannot raytrace them one at a time like you can rasterization.
    • When glFlush is called, generate a ray for each pixel as follows:
      • Loop through all the pixels, as given by the last call to glViewport(minx,miny,w,h).
      • For pixel (xi,yi):
        • (xf,yf) = ((xi-minx)*2/w - 1, (yi-miny)*2/h - 1) to convert the pixel to [-1,1] normalized coordinates.
        • Generate a ray originating at (0,0,0) with direction (x,y,-1); this is the kind of perspective created by calls to glFrustum and glPerspective.
        • Trace the ray, completely ignoring all w coordinates.
        • At the point of intersection, find the normal and light the pixel.
  • Method 2 (Forget your code and start new):
    • Start with the base code from Project 1. Basically, you just need to have OpenGL render your raster. So, you can take out your if statement with the drawmode == 2, and just draw your raster every time.
    • Set up a "world" through code. You will need some way to store objects and find intersections on them. A good way to do this is to create classes for each type of object and have it do the intersection test internally, returning the result.
    • Have a "camera" defined as a position and a viewing direction. When you change the position or viewing direction of the camera, your scene should shift accordingly.
    • Shoot a ray through each pixel in a virtual screen 1 unit in front of the camera (the center of the "screen" is probably at Pc = Camera_pos + normalized(Camera_viewing_direction)). So, to find the ray for each pixel, find the position of each pixel in the virtual screen, and the ray = normalize(Pixel_pos - Camera_pos). You will also need the Pixel_pos during the intersection tests so that you can tell how far away things are from the pixel. Remember, you want to find the closest object to the camera for that pixel.
    • Trace the ray, which essentially means to do intersection tests with all objects that it might hit (you will start out testing all objects in the scene. If you decide to do an acceleration structure, you won't have to test every object in the scene). After finding all intersections, you want to find the object closest to the camera for that pixel.
    • Once you have the intersection point and normal for the closest object, light it using a lighting model. I suggest using the one from Project 4. After you light it, initially, this is the color you return. If you do reflection and/or refraction rays, you will do a weighted some on the colors returned from those rays and return that color.
    • Do this for every pixel and draw the raster to the screen.

"Trace the ray" as noted here means find the intersection of the line passing through the ray origin in the direction of the ray with a sphere or object which is closest to the ray origin, and compute the color of that point. The lecture slides talk about how to do that. I've also written up a little thing on barycentric coordinates for ray-triangle testing you might find useful.

Some people have been having trouble with finding pixel locations in the "virtual screen". If you too are struggling with this, some instructions can be found here.

If you get that working, with spheres showing up, several lights, specular highlights and the like, that's 60 points.

Elective credit can be gained as follows:

  • Add an acceleration structure. See page 604-607 of the book. The idea here is to store the objects and spheres in such a way that most rays don't even need to check for intersections with most shapes. 15 points if you can render
    glBegin(GL_POINTS);
    for (int i=0; i<2000; i++)
    	glVertex3f(rand()*2.0/RAND_MAX-1,rand()*2.0/RAND_MAX-1,rand()*2.0/RAND_MAX-1);
    glEnd();
    
    in a reasonable time; more if you can do even larger scenes quickly.
  • Add shadows (page 580), 10 points
  • Add reflections (page 600), 10 points. You'll want to cap the reflection depth (4 is a reasonable number) so that you don't get caught in the room-of-mirrors case and either use the material specularity or some other parameter to decide how reflective an object is.
  • Add transmissive refraction (pages 576-579, 600), 15 points. You'll want to cap the refraction depth (4 is a reasonable number). You should use the alpha color value as a transparency, and add an index of refraction setting method. If you also do reflections, you will need to deal with total internal reflections appropriately.
  • Add textures to triangles (pages 628-634), 10 points for texture colors. You can use the same texture specifications as lab 4, or you can add a different texture specification if you wish. You'll need to store what texture was enabled for each triangle when it is created. An additional 5 points if the texture can specify the transparency and index of refraction at a point and you have transmissive refraction; an additional 5 points if reflectivity can also specified by texture.
  • Antialias your images, 10 or 20 points. Shoot several rays per pixel and average the results. 10 points if the number of rays is fixed, 20 if you adaptively send more rays through pixels that have high color gradients.
  • Raytracing makes very crisp images; add softness to compensate. Instead of shooting shadow/reflection/transmission rays straight, randomly offset them a little to create soft reflections/transmissions/shadows. 10 per softened thing.
  • Allow ray-other intersection. Planes are worth 5 points. Triangles are worth 10 points. Ellipsoids can be easily specified by storing the top 3x3 portion of the transformation matrix active when a point is specified (15); you can also treat spheres as blobby objects (20), add Bezier surface patches (20), or anything else you want.
  • Progressive render. At least print periodically how complete the render is (5); also add periodic screen updates for an additional 10. You will probably want to stop resizes and clear calls from doing anything until the render is complete.
  • Artistry sells science. Send me cool-looking pictures made by your renderer and I will give them credit if I (entirely subjectively) think they look nifty.


E-mail: leemhoward@gmail.com