# Project 2: 3D Models

In this homework assignment you're going to practice how to:

• render polygons in modern OpenGL
• control objects using the mouse
• set up light sources
• set material properties so that your objects look more interesting

You can find a demo with extra credits implemented here: https://youtu.be/OseU4-1cTYc

## 1. Rendering using modern OpenGL (10 Points)

Download and build the starter code for project 2, which renders the Cube with modern OpenGL, through the use of a VAO (Vertex Array Object), VBOs (Vertex Buffer Object), and EBOs (element buffer object). In order to make the use of the programmable pipeline possible, a shader class was added to the starter code, along with a sample vertex and fragment shader. At the moment, the sample fragment shader causes all objects to be colored pink. You will be fixing this later when you begin working with lights.

Notes:

• This is a good resource for learning modern OpenGL.

## 2. 3D Model Loader (20 Points)

You already know how to load point clouds. It turns out that 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. Note that the indices are 0-based (start with index 0). Example:
`f 31514//31514 31465//31465 31464//31464`

Copy your OBJ loader code from project 1 into the new project, and add parsing 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.

Make sure you copy your centering and resizing code from project 1 so that the models more or less fill your graphics window.

## 3. Mouse control (30 Points)

If you still have your spin-while-idle code, now is the time to disable it. From now on we support the mouse to control your 3D models. Add functionality to allow the following operations on the displayed 3D model:

### Scaling the model (10 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 's'/'S' keys to scale.

### Rotating the model (20 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.

To help you understand the code better, here is a line-by-line commented version of the trackBallMapping function:

```Vec3f CSierpinskiSolidsView::trackBallMapping(CPoint point)    // The CPoint class is a specific Windows class. Either use separate x and y values for the mouse location, or use a Vector3 in which you ignore the z coordinate.
{
Vec3f v;    // Vector v is the synthesized 3D position of the mouse location on the trackball
float d;     // this is the depth of the mouse location: the delta between the plane through the center of the trackball and the z position of the mouse
v.x = (2.0*point.x - windowSize.x) / windowSize.x;   // this calculates the mouse X position in trackball coordinates, which range from -1 to +1
v.y = (windowSize.y - 2.0*point.y) / windowSize.y;   // this does the equivalent to the above for the mouse Y position
v.z = 0.0;   // initially the mouse z position is set to zero, but this will change below
d = v.Length();    // this is the distance from the trackball's origin to the mouse location, without considering depth (=in the plane of the trackball's origin)
d = (d<1.0) ? d : 1.0;   // this limits d to values of 1.0 or less to avoid square roots of negative values in the following line
v.z = sqrtf(1.001 - d*d);  // this calculates the Z coordinate of the mouse position on the trackball, based on Pythagoras: v.z*v.z + d*d = 1*1
v.Normalize(); // Still need to normalize, since we only capped d, not v.
return v;  // return the mouse location on the surface of the trackball
}
```

More to come