In this assignment, you will add an interactive preview of the scene, and implement Phong Shading in your ray tracer. For interactive display, you will use the OpenGL API that uses graphics hardware for fast rendering of 3D polygons. Note: with some configurations, software emulation might be used, resulting in slower rendering. You will be able to interactively pre-visualize your scene and change the viewpoint, then use your ray-tracer for higher-quality rendering. Most of the infrastructure is provided to you, and you will just need to add functions that send the appropriate triangle-rendering commands to the API to render or paint each kind of Object3D primitive. In OpenGL, you display primitives by sending commands to the API. The API takes care of the perspective projection and the various other transformations, and also rasterizes polygons, i.e., it draws the appropriate pixels for each polygon. (In lecture, we will talk about how this is done using the rendering pipeline). In addition, the infrastructure we provide takes care of the user interface and how the mouse controls the camera.
To use OpenGL on Athena, you will first need to obtain access to the OpenGL libraries and header files. To do this, from an Athena prompt, type:
add mesa_v501
All files implementing OpenGL code should include the OpenGL header files:
// Included files for OpenGL Rendering #include <GL/gl.h> #include <GL/glu.h> #include <GL/glut.h>We provide an updated Makefile to link with the OpenGL libraries on Athena Linux. If you are using Windows, then you may need to download the OpenGL libraries yourself from http://www.opengl.org.
void glCanvas::initialize(SceneParser *_scene, void (*_renderFunction)(void));
The initialize routine takes two parameters: The first is a pointer to the global scene. The second is the function that will perform the raytracing. The GLCanvas class is set up so that the renderFunction takes no parameters and has a void return type. From within the real-time interface (with the mouse cursor within the frame of the GL display window), you can call the render function by pressing 'r'. Once the initialize routine is called, the GLCanvas will take over control of the application and will monitor all mouse and keyboard events. This routine will not return, although the application can be terminated by pressing 'q', by closing the window, or calling exit().
Use the left mouse button to rotate the camera around the center of the scene, the middle mouse button to translate the scene center (truck), and the right mouse button to move the camera closer to or further from the scene (dolly). To prevent weird rotations of the camera, it is necessary to store the original up vector of the camera and define a new "screen up" vector that is the normalized orthogonal up vector for the current direction vector. You can test your implementation at this point. In the GLCanvas::display() function is a call to the provided drawAxes() function, which will allow you to debug your camera implementation.
Once you start working on your Object3D paint methods (described below), you should comment out the call to drawAxes. Once your paint methods are complete, verify that your camera manipulation code is correct by moving the camera, rendering the scene & then comparing the pre-visualization to the raytraced result.
PhongMaterial::PhongMaterial(const Vec3f &diffuseColor, const Vec3f &specularColor, float exponent);
Make the original Material class pure virtual by adding a pure virtual method Shade that computes the local interaction of light and the material:
virtual Vec3f Material::Shade (const Ray &ray, const Hit &hit, const Vec3f &dirToLight, const Vec3f &lightColor) const = 0;
It takes as input the viewing ray, the Hit data structure, and light information and returns the color for that pixel. Implement the the Blinn-Torrance version of the Phong model taught in lecture. We suggest this version simply because it is what OpenGL uses, and the pre-visualization will thus be more similar.
Note: We've only included one type of light source in our scenes, directional light sources, which have no falloff. That is, the distance to the light source has no impact on the intensity of light received at a particular point in space. So you may ignore the r2 term in the Phong lighting model for this assignment. Next week we will add a second type of light source, a point light source, and the distance from the surface to the light will be important.
In the examples below we illustrate an artifact that occurs at grazing angles for wide specular lobes (small exponents). To solve this problem, the specular component can be multiplied by the dot product of the normal and direction to the light instead of simply clamping it to zero when this dot product is negative. You may implement either method in your ray tracer. To enable the specular lobe fix in OpenGL, a 3-pass rendering has been provided in the code (by default only the single pass rendering is performed). It is not required that you use or understand this code.
glBegin(GL_TRIANGLES); glVertex3f(x0, y0, z0); glVertex3f(x1, y1, z1); glVertex3f(x2, y2, z2); glEnd();
Alternatively, you can directly specify an array of floats for each vertex using glVertex3fv(float *array). To set the triangle normal, use one of the following commands before specifying the vertices:
glNormal3f(float x, float y, float z); // List of floats glNormal3fv(float *arr); // Array of floats
Remember that you can compute the normal of a triangle using a cross product.
glBegin(GL_QUADS); glNormal3f(nx, ny, nz); glVertex3f(x0, y0, z0); glVertex3f(x1, y1, z1); glVertex3f(x2, y2, z2); glVertex3f(x3, y3, z3); glEnd();
In OpenGL, you may include 3n vertex positions within the glBegin and glEnd commands to draw n triangles (or 4n vertices to draw n quads):
glBegin(GL_QUADS); for (iPhi=...; iPhi<...; iPhi+=...) for (int iTheta=...; iTheta=...; iTheta+=...) { // compute appropriate coordinates & normals ... // send gl vertex commands glVertex3f(x0, y0, z0); glVertex3f(x1, y1, z1); glVertex3f(x2, y2, z2); glVertex3f(x3, y3, z3); } } glEnd();
You will implement two versions of sphere normals: flat shading (visible facets) and Gouraud interpolation. By default your previsualization should use flat shading; that is, simply the normal of each triangle, as you would for polygon rendering. When the -gouraud option is specified, your pre-visualization should render with Gouraud interpolation, and use the true normal of the sphere for each vertex (set the vertex normal before specifying each vertex position). Note how this improves the appearance of the sphere and makes it smoother. OpenGL performs bilinear interpolation between the shaded color values computed at each vertex. Remember that this is not as good as the Phong interpolation described in class (which interpolates the surface normals and then performs the lighting calculation per pixel).
glPushMatrix(); GLfloat *glMatrix = matrix.glGet(); glMultMatrixf(glMatrix); delete[] glMatrix;
Then, recursively call the paint() method of the child object. After this, you must restore the previous matrix from the stack using:
glPopMatrix();
If you do not save and restore the matrix, your transformation will be applied to all the following primitives!
  If you're interested, here's the scene description file grammar used in this assignment.
  If you're interested, here's a list of command line arguments used in this assignment.
raytracer -input scene3_01_cube_orthographic.txt -size 200 200 -output output3_01.tga -gui
raytracer -input scene3_02_cube_perspective.txt -size 200 200 -output output3_02.tga -gui
raytracer -input scene3_03_bunny_mesh_200.txt -size 200 200 -output output3_03.tga -gui
raytracer -input scene3_04_bunny_mesh_1k.txt -size 200 200 -output output3_04.tga -gui
raytracer -input scene3_05_axes_cube.txt -size 200 200 -output output3_05.tga -gui
raytracer -input scene3_06_crazy_transforms.txt -size 200 200 -output output3_06.tga -gui
raytracer -input scene3_07_plane.txt -size 200 200 -output output3_07.tga -gui -tessellation 10 5
raytracer -input scene3_08_sphere.txt -size 200 200 -output output3_08.tga -gui -tessellation 10 5 raytracer -input scene3_08_sphere.txt -size 200 200 -output output3_08.tga -gui -tessellation 20 10 raytracer -input scene3_08_sphere.txt -size 200 200 -output output3_08.tga -gui -tessellation 10 5 -gouraud raytracer -input scene3_08_sphere.txt -size 200 200 -output output3_08.tga -gui -tessellation 20 10 -gouraud
raytracer -input scene3_09_exponent_variations.txt -size 300 300 -output output3_09.tga -gui -tessellation 100 50 -gouraud
and with the OPTIONAL specular fix:
raytracer -input scene3_10_exponent_variations_back.txt -size 300 300 -output output3_10.tga -gui -tessellation 100 50 -gouraud
and with the OPTIONAL specular fix:
raytracer -input scene3_11_weird_lighting_diffuse.txt -size 200 200 -output output3_11.tga -gui -tessellation 100 50 -gouraud
raytracer -input scene3_12_weird_lighting_specular.txt -size 200 200 -output output3_12.tga -gui -tessellation 100 50 -gouraud
and with the OPTIONAL specular fix:
See the main Assignments Page for submission information.