Project2Fall14
Contents |
Project 2: Viewing 3D Scenes
This homework assignment consists of three parts, but only the first two are mandatory to get full credit (100 points). In the first part you will need to implement camera matrices and apply them to a simple scene. In the second part you will need to load 3D point clouds and display them with your viewer. In the third, optional part you will be asked to improve the visual quality of your point clouds.
This assignment is due on Friday, October 24th at 3:30pm and needs to be presented to the course staff on the due date.
The project will be discussed by the TAs on Monday, October 20th at 5pm in CSB 001.
1. The Camera Matrix (50 Points)
1a. Creating the Camera Matrix (25 Points)
As described in the lecture slides, create a camera class Camera with member variables for a 'center of projection' e, a 'look at point' d, and an 'up vector' up (10 points). The class should have an internal camera matrix C, derived from e, d and up (10 points).
Add a method called something like getGLMatrix to your camera class to access the components of the camera matrix C as an array of 16 values of type GLdouble in the order OpenGL expects them (column-major). Note that many of your Matrix4 classes use row-major order. You will need this method in part 1b. If your camera matrix already stores the matrix components in column-major order, you do not need to do a conversion but can directly pass the pointer to the matrix array instead. (5 points)
1b. Testing (25 Points)
As a basis use your source code from last week. We provide source code to generate a simple scene with a house to test your camera matrix implementation. Add this code to render the house (10 points).
Make sure the OpenGL's projection matrix is set as it was in the Cube example from assignment 1.
In your GLUT Display callback, set OpenGL's model-view matrix to your camera matrix C:
glMatrixMode(GL_MODELVIEW); glLoadMatrixf(camera.getCameraMatrix().getValues());
Render two images of the scene using these two sets of parameters for your camera matrix:
- Image 1:
- Center of projection: 0, 10, 10
- Look at point: 0, 0, 0
- Up vector 0, 1, 0
- Image 2:
- Center of projection: -15, 5, 10
- Look at point: -5, 0, 0
- Up vector 0, 1, 0.5
Add the house to your existing software application and support keyboard keys 'F2' and 'F3' to switch to it. 'F1' should show the cube from project 1. (5 points)
Compare your implementation to the correct result images shown below. If you can accurately re-create the images you will receive 5 points for each image. Note that you need to set OpenGL's lighting to 'off' with glDisable(GL_LIGHTING) to match your results.
Image 1 | Image 2 |
Notes:
- Do not use the gluLookAt function in this homework assignment (this is a one time exception).
- In addition to glutKeyboardFunc, you will need to use glutSpecialFunc to parse Function keys. There are pre-defined constants for them, they are GLUT_KEY_F1 through GLUT_KEY_F12.
2. 3D Point Clouds from Files (50 Points)
A point cloud is a 3D collection of points, representing a 3D object. These point clouds are often acquired by laser scanning, but can also be acquired with the Microsoft Kinect and special software, or by processing a large number of photographs of an object and using Structure from Motion techniques (see Microsoft Photosynth or Autodesk 123D Catc).
The XYZ file format is a very simple ASCII text-based file format for unsorted collections of 3D points. An XYZ file does not have a header, it only consists of a list of point locations, optionally with color or normals. In this exercise we are going to use a point cloud with normals. The first two lines of the file look like this:
-0.037830 0.127940 0.004475 1.223420 6.106969 -0.789864 -0.044779 0.128887 0.001905 1.351736 5.963559 -1.435807
The example defines two points. The points are separated by a line break. Within each line are six floating point numbers. The first three are the x, y, and z position of the point, respectively. The next three numbers are the normal's x, y, and z positions.
Write a parser for XYZ files with normals (10 points). It should be a simple for loop in which you read each line from the file, for instance with the fscanf command. Your parser does not need to do any error handling - you can assume that you have proper XYZ files. Add the parser to your code from project 1.
Use your parser to load these point cloud files from Stanford's 3D scanning repository:
Next you need to write the code to display the point cloud (5 points). Let us inspire you with this pseudo-code:
glBegin(GL_POINTS); for (loop over all points) { glNormal3d(normal[n].x, normal[n].y, normal[n].z); glVertex3d(position[n].x, position[n].y, position[n].z); } glEnd();
Make sure the normals are normalized, before you pass them on to OpenGL.
Add support for keyboard commands to switch to the point models when the user presses the 'F4' and 'F5' keys. You also need to support at least the keyboard commands for rotation and scale from the first homework project. (5 points)
You can use glPointSize to change the size (in pixels) of a point.
If you want to make the points round instead of square, you can use the following code:
glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_POINT_SMOOTH); glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
You will notice that the point models will not adequately fill your rendering window when they load. To render the models as large as possible without exceeding the OpenGL window, use the following approach:
- Calculate the minimum and maximum point coordinates in all three dimensions by writing three 'for' loops which traverse all vertices, one for each dimension (x,y,z), storing the smallest and largest values they come across. Display these six values in the console window. (10 points)
- Your window origin is (0,0,0), so you are going to have to translate the model towards it if its center point is not also the model's origin. Calculate the amount of translation required and create a translation matrix to center the object within the OpenGL window. Show this translation matrix in the console window (10 points)
- Find out approximately what size objects your rendering window allows and scale the model up or down until it nicely fills the window. Based on the amount of scaling necessary, you need to create a uniform scale matrix, which scales the object so that it renders as large as possible in the window, without exceeding the window size. Show this scale matrix in the console window. (10 points)
Apply this algorithm whenever you load a point model.
3. Optional: Point Sprites (10 Points)
You will notice that all your points have the same size, regardless of how close they are to the camera. This is unnatural and doesn't provide very good depth cues. Fix this by automatically adjusting the point size depending on their distance from the camera. You can use an approach of your choice, we suggest considering one of these two:
- Point Sprites: These are programmable points which are automatically scaled by OpenGL depending on their distance from the camera. A good overview of how they are implemented is given here. Note that this solution requires GLSL shader programming, which we have not yet covered in class.
- Textured Quads: If you can figure out how to draw textures, you can create a point texture and draw every point as a texture, which points towards the camera. You would draw bigger textures for points closer to the camera and smaller ones otherwise. This concept is explained under "Billboarding" here.