Project 2: 3D Models and Lighting
In this homework assignment you're going to practice how to:
- load OBJ files with polygons (not just points)
- render 3D models with triangles
- control objects with the mouse
- set up light sources and material properties
Watch a demo of a previous year's homework project that includes some extra credit work, but differs in some of the detail from this year's project.
Start with your code from project 1. We're going to build on top of it for this project. You don't need to retain the point rendering functionality.
- This is a good resource for learning modern OpenGL.
- The first half of this project should be doable with the material from the lectures in week 2. The second half will require knowledge from week 3.
- This video demonstrates roughly what is expected, except that it does not include normal coloring and adds more light sources.
1. 3D Model Loader (20 Points)
You already know how to load point clouds. The 3D model files from project 1 (Bunny, Bear, Dragon) contain surface descriptions as well, by means of triangle connectivity.Besides vertices and vertex normals you are going to have to parse the files for connectivity. It is defined with the letter 'f' for face. Each line starting with the letter 'f' lists three sets of indices to vertices and normals, which define the three corners of a triangle. The numbers are indices into the vertex and vertex normal lists (lines starting with 'vn'). Note that the indices are 1-based (start with index 1). Example:
f 31514//31514 31465//31465 31464//31464
To your parser from project 1 add parsing the 'vn' lines to load normals, and the 'f' lines to load triangles. Then modify your code to display the OBJ models with triangles instead of the cube. Allow switching between them just like in project 1 with the F1, F2 and F3 keys (or keys of your choice).
Make sure you copy your centering and resizing code from project 1 so that the models approximately fill your graphics window.
2. Mouse Control (30 Points)
Disable or remove your code that spins the models automatically. From now on you need to support the mouse to control your 3D models. Add functionality to allow the following operations on the displayed 3D model:
Scaling the model (15 Points)
Support the mouse wheel to scale the model up or down, using matrix transformations (not by modifying each of the vertex positions like in project 1). If you don't have a mouse wheel, use the right mouse button. If you don't have that, use two-finger drags on the touch pad. If your computer doesn't support that either, use the shift key along with the mouse button to scale.
Rotating the model (15 Points)
While the left mouse button is pressed and the mouse is moved, rotate the model about the center of your graphics window. We will refer to this operation as "trackball rotation". This video shows how this should work.
The figure below illustrates how to translate mouse movement into a rotation axis and angle. m0 and m1 are consecutive 2D mouse positions. These positions define two locations v and w on an invisible 3D sphere that fills the rendering window. Use their cross product as the rotation axis a = v x w, and the angle between v and w as the rotation angle.
Horizontal mouse movement exactly in the middle of the window should result in a rotation just around the y-axis. Vertical mouse movement exactly in the middle of the window should result in a rotation just around the x-axis. Mouse movements in other areas and directions should result in rotations about an axis a which is not parallel to any single coordinate axis, and is determined by the direction the mouse is moved in.
Once you have calculated the trackball rotation matrix for a mouse drag, you will need to multiply it with the object-to-world transformation matrix of the object you are rotating.
For step by step instructions, take a look at this tutorial. Note that the tutorial was written for Windows messages, instead of GLFW mouse events. This means that you'll need to replace the "CSierpinskiSolidsView::OnLButtonDown", "CSierpinskiSolidsView::OnMouseMove", etc. with an appropriate GLFW equivalent.
3. Define Lights and Materials (20 Points)
In order to render the 3D models as realistically as possible, write shaders to render them with the Phong illumination model and per pixel lighting. Per pixel lighting means that you have to do all of your light reflection calculations in the fragment shader. For the shader to work, you will have to define at least one light source as well as different materials for each of your 3D models. Write vertex and fragment shaders to support the features listed below. In this part of the project, you should use fixed positions for the light. But know that in part 4 you're going to have to make the light movable, so you may want to already introduce variables instead of using constant values.
Materials (10 Points)
Assign each of the 3D model files different material properties, following the instructions below. Each object should have a different color of your choice.
- One of the models (your pick) should be very shiny (i.e., high specular component), with no diffuse reflection.
- Another model should only use diffuse reflection, with zero shininess.
- The third object should have significant diffuse and specular reflection components.
Support keyboard key 'n' to switch between the rendering modes of normal coloring and your new Phong illumination model:
- Normal coloring is useful to check if your surface normals have been calculated correctly. This way of coloring is done by interpreting a vertex's normal as an RGB color: you will have to shift the value range of the x, y and z components of the normal, which is -1..1, to the range of RGB colors which is 0..1. This means that you have to add 1, then divide by 2. The normal's x value should map to red, y to green and z to blue.
- In Phong render mode, you render your 3D models more photo-realistically, determined by their materials.
- This table of material properties may inspire you to select interesting material parameters. But note that there are specific requirements for the materials you use, which make it necessary to eliminate one or more reflection components (ambient, diffuse, specular) when you define your own materials.
Light source (10 Points)
Create a point light to illuminate your 3D models. The light should have a color of your choice, but cannot be white or very dark. Use quadratic attenuation when calculating the light intensity. The light source needs to have a color and a position.
- -10 if all code is there but lighting doesn't work
4. Interactive Light Controls (30 Points)
To test the effect of your light sources, display and make the light source movable with the mouse (rotate it around the model with your trackball controls).
Light Representation (10 Points)
To see the light source, display this sphere in the position of the light source and in its color.
The sphere needs to be scaled down to be about 1/4 inch wide on the screen, just big enough to be clearly visible. It's best to scale it down with a uniform scale matrix just before the model matrix transformation (or as part of the model matrix).
To draw the sphere in the color of the light source you should use the light color as the light's ambient reflection value, and use no diffuse or specular reflection (they wouldn't work properly because the light source is inside of the light source geometry).
Light Position (20 Points)
Allow the user to select what is rotated when the mouse is moved with the mouse button down: keyboard key '1' rotates just the 3D model (and leaves the light source fixed in world coordinates). '2' should rotate just the light source. '3' should rotate both model and light source while keeping their relative positions constant.
Regarding scaling, which you previously implemented with the mouse wheel (or similarly): In mode '1', you should still scale the 3D model like before. But in mode '2', the mouse wheel should now change the distance of the light from the center of the graphics window. In mode '3' the mouse wheel should do both of the above operations.
Below is a table summarizing these interactions:
|Mode||Mouse Button||Mouse Wheel (or similar)|
|'1'||Rotates 3D model about its center. Light source stays fixed for the viewer.||Scales 3D model about its center. Light source stays fixed for the viewer.|
|'2'||Rotates the light source around the center of the 3D model. 3D model stays fixed for the viewer.||Moves the light source closer to or further from the center of the 3D model.|
|'3'||Rotates both 3D model and light source by the same amount.||Scales the 3D model about its center and moves the light source like above.|
- -2 for each mouse operation that is almost but not quite correct.
- Learn OpenGL provides vertex and fragment shader code, as well as the corresponding C++ code for different lighting parameters. The shader does almost exactly what you need. Find out how it differs from the equations given on the discussion slides for this homework project and make the few modifications.
- Lighthouse 3D also provides excellent tutorials for the necessary shaders: for directional lights, point lights and spot lights.
- This tutorial provides very useful information on light parameters in chapters 6 and 7. An additional tutorial on different light types is provided in chapter 8.
5. Extra Credit (10 Points)
You can receive up to 10 points of extra credit if you do one or more of the following things:
1) Add a directional light source to the scene and make its direction controllable with your virtual trackball. (3 points)
2) Add a spot light source to the scene and make its direction controllable with your virtual trackball. (4 points) The spot light needs to have the following parameters:
- Direction of center of cone
- Spot cutoff
- Spot exponent
3) Allow the user to turn on and off each light source individually. (2 points)
4) Create a visual editor to allow the custom modification of the colors and shading parameters of your light source and surface materials. Use the 'c' key to display the color editor. The editor needs to be exclusively mouse controlled. You can either write your own OpenGL code to generate GUI widgets such as buttons or sliders, or you can use an existing open source library for it, such as NanoGUI.
You'll get points for the modification of the following parameters:
- The object's colors and other parameters for ambient, diffuse and specular reflectivity. (5 Points)
- The light's color and other properties: if using a spot light: cone angle, edge falloff; else: attenuation mode (constant, linear, quadratic). (5 Points)