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:
E-mail: leemhoward@gmail.com |