Difference between revisions of "Project2Fall12"

From Immersive Visualization Lab Wiki
Jump to: navigation, search
(1. Camera and View Frustum)
(3. Optional Project: Height Map (10 points))
 
(44 intermediate revisions by one user not shown)
Line 1: Line 1:
=Project 2: Interactive Viewing=
+
=Project 2: Viewing 3D Models=
  
This homework assignment consists of four parts, but only the first three 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 build a virtual trackball to rotate your 3D scene with the mouse. In the third part you will need to load 3D models files and display them with your viewer.
+
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 models files and display them with your viewer. The third, optional part requires building a very simple flight simulator.
  
 
This assignment is due on '''Friday, October 10'''.  
 
This assignment is due on '''Friday, October 10'''.  
 
It will be introduced by TA Sid on '''Monday, October 8th at 2:30pm''' in lab 260.
 
It will be introduced by TA Sid on '''Monday, October 8th at 2:30pm''' in lab 260.
  
==1. The Camera Matrix==
+
==1. The Camera Matrix (40 Points)==
  
===1a. Camera (10 points)===
+
===1a. Creating the Camera Matrix (20 Points)===
  
As described in the lecture slides, create a camera class <tt>Camera</tt> with member variables for a 'center of projection' <tt>e</tt>, a 'look at point' <tt>d</tt>, and an 'up vector' <tt>up</tt> ('''5 points'''). The class should have an internal camera matrix <tt>C</tt>, derived from <tt>e</tt>, <tt>d</tt> and <tt>up</tt> ('''5 points''').
+
As described in the lecture slides, create a camera class <tt>Camera</tt> with member variables for a 'center of projection' <tt>e</tt>, a 'look at point' <tt>d</tt>, and an 'up vector' <tt>up</tt> ('''10 points'''). The class should have an internal camera matrix <tt>C</tt>, derived from <tt>e</tt>, <tt>d</tt> and <tt>up</tt> ('''5 points''').
  
<!-- This topic has not yet been covered in the lectures this year.
+
Add a method <tt>getGLMatrix</tt> to your camera class to access the components of the camera matrix <tt>C</tt> as an array of 16 values of type GLdouble in the order OpenGL expects them (column-major). You will need this in part 1b. ('''5 points''') If your camera matrix already stores the matrix components in OpenGL compatible format, you do not have to do this but can directly pass the pointer instead (and will also get the 5 points).
  
===1b. View Frustum (10 points)===
+
===1b. Testing (20 Points)===
  
Create a class <tt>Frustum</tt> which defines a projection matrix of type <tt>Matrix4</tt>. Create a class method to generate the projection matrix from a <i>near plane</i> <tt>near</tt>, <i>far plane</i> <tt>far</tt>, <i>aspect ratio</i> <tt>aspect</tt>, and a <i>vertical field of view</i> <tt>fov</tt> (<b>6 points</b>). This matrix is referred to in the lecture slides by the name <tt>Ppersp</tt>. Add a method to set OpenGL's projection matrix <tt>GL_PROJECTION</tt> from the class internal projection matrix (<b>4 points</b>).
+
As a basis you can use your source code from last week. We provide [[house.cpp|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''').
  
<b>Note</b>: Do not use <tt>gluPerspective</tt> or <tt>glFrustum</tt> to implement the projection matrix, but use the equations from the lecture slides instead, and load projection matrix into OpenGL with <tt>glMatrixMode(GL_PROJECTION); glLoadMatrixd(Persp);</tt>.
+
Set OpenGL's projection matrix as it was in the Cube example from assignment 1 with the following code in GLUT's Reshape callback function:
  
-->
+
<pre>
 +
  glMatrixMode(GL_PROJECTION);
 +
  glLoadIdentity();
 +
  glFrustum(-10.0, 10.0, -10.0, 10.0, 10, 1000.0);
 +
  glTranslatef(0, 0, -20);
 +
</pre>
  
===1c. Testing (10 points)===
+
In your GLUT Display callback, set OpenGL's model-view matrix to your camera matrix <tt>C</tt>. Do not use the [http://www.opengl.org/sdk/docs/man/xhtml/gluLookAt.xml <tt>gluLookAt</tt>] function in this homework assignment - but you are allowed to use it in future assignments.
  
We provide [[house.cpp|source code]] to generate a simple scene to test your implementation. Set the object transformation matrix (model matrix) to the identity matrix and render two images of the scene using these two sets of parameters:
+
<pre>
 +
  glMatrixMode(GL_MODELVIEW);
 +
  glLoadMatrixf(camera.getCameraMatrix().getValues());
 +
</pre>
 +
 
 +
Render two images of the scene using these two sets of parameters for your camera matrix:
  
 
* Image 1:  
 
* Image 1:  
** Aspect ratio: 1
+
** Center of projection: 0, 10, 10
** Vertical field of view: 60 degrees
+
** Near, far clip planes: 1, 100
+
** Center of projection: 0, 0, 40
+
 
** Look at point: 0, 0, 0
 
** Look at point: 0, 0, 0
 
** Up vector 0, 1, 0
 
** Up vector 0, 1, 0
 
* Image 2:
 
* Image 2:
** Aspect ratio: 1
+
** Center of projection: -15, 5, 10
** Vertical field of view: 60 degrees
+
** Near, far clip planes: 1, 100
+
** Center of projection: -10, 40, 40
+
 
** Look at point: -5, 0, 0
 
** Look at point: -5, 0, 0
** Up vector 0, 1, 0
+
** Up vector 0, 1, 0.5
  
Compare your implementation to the test images shown below ('''5 points''' for each image). Note that the images below were rendered with lighting off (<tt>glDisable(GL_LIGHTING)</tt>).
+
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 <tt>glDisable(GL_LIGHTING)</tt>.
  
[[Image:house1.jpg]]
+
{| style="text-align: center;"
[[Image:house2.jpg]]
+
| [[Image:house1-half.png]] || [[Image:house2-half.png]]
 +
|-
 +
| Image 1 || Image 2
 +
|}
  
==2. Virtual Trackball (50 points)==
+
==2. Displaying 3D Models from Files (60 points)==
  
Implement a ''virtual trackball'' which allows a user to rotate an object interactively with the mouse. Your solution should translate clicking and dragging of the mouse into a rotation matrix, which you then use to rotate the scene. Rotations around all three coordinate axes should be supported. A sample executable demonstrating the trackball functionality is available for [[Media:trackball.zip|Windows]] and [[Media:trackball-linux.bin|Linux]]. If the executable does not work on your computer, here is a [[Media:cube.mpg|video of it.]] To access mouse coordinates, you will need to use GLUT's callback functions [http://www.opengl.org/resources/libraries/glut/spec3/node50.html glutMouseFunc()] and [http://www.opengl.org/resources/libraries/glut/spec3/node51.html glutMotionFunc()]. Note that successive trackball rotations must build on previous ones; at no point should the model snap back to a previous or default position.
+
The OBJ file format is a very simple ASCII text based file format for triangle meshes. In its basic form, an OBJ file contains a list of triangle vertices indicated by the letter <tt>v</tt>, followed by an array of indices to form triangles indicated by the letter <tt>f</tt>. We provide a [[Media:ObjReader.zip|C++ class that reads OBJ files]]. Add this code to your rendering engine. You have to write the necessary code to create OpenGL geometry out of the 3D data structure ('''20 points'''). Use a method of your choice to make the tessellation of the object visible, for instance by using different colors (random or following an algorithm) for different triangles, wire frames around the triangles ('''5 points''').
  
The figure below illustrates how to translate mouse movement into a rotation axis and angle. <tt>m0</tt> and <tt>m1</tt> are consecutive 2D mouse positions. These positions define two locations <tt>v</tt> and <tt>w</tt> on a 3D virtual sphere that fills the rendering window. Use their cross product as the rotation axis <tt>a = v x w</tt>, and the angle between <tt>v</tt> and <tt>w</tt> as the rotation angle.  
+
Add support for keyboard commands to select and switch between one of five <tt>.obj</tt> files ('''5 points'''). You can parse key presses with the [http://www.opengl.org/resources/libraries/glut/spec3/node49.html <tt>glutKeyboardFunc</tt>] command, for which you can find a good tutorial [http://www.lighthouse3d.com/tutorials/glut-tutorial/keyboard/ here].
  
[[Image:trackball.jpg]]
+
These five OBJ files are available for download. Map each of them to one of the keys '1' through '5'.
  
Horizontal mouse movement in the middle of the window should result in a rotation around the y-axis. Vertical mouse movement in the middle of the window should result in a rotation around the x-axis. Mouse movements along the boundary (horizontal and vertical) should result in rotations at least partially around the z-axis.  
+
* [http://ivl.calit2.net/wiki/files/sphere.obj Sphere]
 +
* [http://ivl.calit2.net/wiki/files/teddy.obj Teddy]
 +
* [http://ivl.calit2.net/wiki/files/teapot.obj Teapot]
 +
* [http://ivl.calit2.net/wiki/files/cow.obj Cow]
 +
* [http://ivl.calit2.net/wiki/files/bunny.obj Bunny]
  
<!-- This link seems to be down. Check again later.
+
You will notice that without further measures, the objects in the OBJ files may be too small or too large for your rendering window. To render the objects as large as possible while still completely fitting in the window, use the following approach:
[http://viewport3d.com/trackball.htm Here] you will find a more detailed description of the implementation of a virtual trackball.
+
-->
+
  
You will notice that you can either rotate the camera around a static object space, or the object space with respect to a stationary camera. We recommended (but not required) using a stationary camera and rotating the object space.
+
* Calculate the minimum and maximum vertex coordinates in all three dimensions ('''5 points''') by writing three 'for' loops which traverse all vertices, one for each dimension, storing the smallest and largest values they come across.
  
You get points for the following accomplishments:
+
* Your window origin is zero, so you are going to have to translate the model towards it if its origin is not already zero. Based on the amount of translation, you need to create a translation matrix to center the object ('''5 points''').
  
* The object space rotates about its origin ('''20 points''').
+
* Find out approximately what size objects your rendering window allows, for instance by drawing the sphere model (which is one unit wide) and scaling it up or down until it fits in 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. ('''5 points''')  
* The trackball rotates correctly with regards to mouse movement (e.g., mouse to the right -> object rotates to the right) ('''25 points''').
+
* Clicking and dragging ''anywhere'' in the window, including close to the edge or corners of the window, does not crash the application ('''5 points''').
+
  
==3. Displaying Triangle Meshes from Files (20 points)==
+
* Allow the user to trigger this automatic size adjustment by pressing the 'a' key ('''5 points''').
  
The .obj file format is a very simple ASCII text based file format for triangle meshes. In its basic form, an .obj file contains a list of triangle vertices indicated by the letter <tt>v</tt>, followed by an array of indices to form triangles indicated by the letter <tt>f</tt>. We provide a [[Media:ObjReader.zip|C++ class that reads .obj files]]. You should add this code to your rendering engine. The <tt>.zip</tt> file also contains a code sample that demonstrates the use of this class. You have to add the routines to create OpenGL geometry out of the 3D data structure ('''4 points'''). Add support for a command line parameter to specify the name of the <tt>.obj</tt> file to load ('''1 point''').  
+
The 's' key should toggle a rotation of the object around its y axis, similar to the cube in the base code. To toggle means that repeated key presses on 's' will start and stop the rotation ('''5 points''').
  
One problem is that you don't know the extent of the object stored in the file. The stored triangle coordinates may be too small or too large for your rendering window. To fix this, calculate the minimum and maximum coordinates in all three dimensions ('''5 points'''), and find out what size objects your rendering window allows. Based on these values you need to create a translation matrix ('''5 points''') and a uniform scale matrix ('''5 points''') which, together, transform the object so that it fills the rendering window.
+
Make the code robust enough that the user can change the 3D model, adjust its size and start/stop the rotation at any point by pressing the respective keys, without having to observe a specific order ('''5 points''').
 
+
Here are a few sample .obj files for testing. Make sure they all work, because you will be asked to show some of them during homework grading.
+
 
+
* [http://ivl.calit2.net/wiki/files/sphere.obj Sphere]
+
* [http://ivl.calit2.net/wiki/files/teddy.obj Teddy]
+
* [http://ivl.calit2.net/wiki/files/teapot.obj Teapot]
+
* [http://ivl.calit2.net/wiki/files/cow.obj Cow]
+
* [http://ivl.calit2.net/wiki/files/bunny.obj Bunny]
+
  
 
<!-- To upload the above files, I had to upload them directly to the Wiki server! -->
 
<!-- To upload the above files, I had to upload them directly to the Wiki server! -->
  
==4. Optional Project: Height Map (10 points)==
+
==3. Optional Project: Height Map (10 points)==
  
Generate and display a 3D mesh out of a 2D height map image. Wikipedia has a great [http://en.wikipedia.org/wiki/Heightmap description of this topic]. Allow the user to interactively fly over the height map, similar to a simple flight simulator, using keyboard or mouse. You can use the height map image from the Wikipedia page, which you will also find below, or create your own with a paint program or another method of your choice.  
+
Generate and display a 3D mesh out of a 2D height map image. Wikipedia has a great [http://en.wikipedia.org/wiki/Heightmap description of this topic]. Allow the user to interactively fly over the height map, similar to a simple flight simulator. You can use the height map image from the Wikipedia page, which you will also find below, or create your own with a paint program or another method of your choice.  
  
 
<center>
 
<center>
Line 95: Line 94:
 
To get full credit you need to implement the following features:
 
To get full credit you need to implement the following features:
  
* Load the height map image and create a 3D mesh out of it ('''4 points'''). You can either read the Wikipedia PNG image file with your own reader, or read [[Media:Heightmap.pgm|this PGM image file]] with [[pgm-loader.cpp|this piece of C code]].
+
* Load the height map image and create a 3D mesh out of it ('''4 points'''). You can either read the Wikipedia PNG image file with your own reader, or read [[Media:Heightmap.pgm|this PGM image file]] with [[pgm-loader.cpp|this piece of C code]]. Note that this code returns a one dimensional array, which you have to interpret as a two-dimensional array based on the width of the image.
  
 
* Use a color gradient from blue (water) to yellow (sand), green (grass), grey (rock) and white (snow) to color the terrain polygons, depending on their height ('''2 points''').
 
* Use a color gradient from blue (water) to yellow (sand), green (grass), grey (rock) and white (snow) to color the terrain polygons, depending on their height ('''2 points''').
  
* Create a separate navigation mode apart from that of the trackball, in which the user can navigate by steering left/right, up/down, and change the velocity of the flight ('''3 points'''). Scale the terrain up to a size appropriate for a flight simulator scenario ('''1 point''').
+
* Create a navigation mode, in which the user can rotate the camera left or right (with keys 'a' and 'd'), move up or down (with keys 'w' and 's'), and change the velocity of the flight ('m' for slower, 'k' for faster) ('''3 points'''). Scale the terrain to a size appropriate for a flight simulator scenario ('''1 point''').
  
 
If you use the Wikipedia height map, the resulting terrain should look similar to this, except that it needs to be colored as described above:
 
If you use the Wikipedia height map, the resulting terrain should look similar to this, except that it needs to be colored as described above:

Latest revision as of 00:18, 13 October 2012

Contents

Project 2: Viewing 3D Models

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 models files and display them with your viewer. The third, optional part requires building a very simple flight simulator.

This assignment is due on Friday, October 10. It will be introduced by TA Sid on Monday, October 8th at 2:30pm in lab 260.

1. The Camera Matrix (40 Points)

1a. Creating the Camera Matrix (20 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 (5 points).

Add a method 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). You will need this in part 1b. (5 points) If your camera matrix already stores the matrix components in OpenGL compatible format, you do not have to do this but can directly pass the pointer instead (and will also get the 5 points).

1b. Testing (20 Points)

As a basis you can 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).

Set OpenGL's projection matrix as it was in the Cube example from assignment 1 with the following code in GLUT's Reshape callback function:

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glFrustum(-10.0, 10.0, -10.0, 10.0, 10, 1000.0);
  glTranslatef(0, 0, -20);

In your GLUT Display callback, set OpenGL's model-view matrix to your camera matrix C. Do not use the gluLookAt function in this homework assignment - but you are allowed to use it in future assignments.

  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

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).

House1-half.png House2-half.png
Image 1 Image 2

2. Displaying 3D Models from Files (60 points)

The OBJ file format is a very simple ASCII text based file format for triangle meshes. In its basic form, an OBJ file contains a list of triangle vertices indicated by the letter v, followed by an array of indices to form triangles indicated by the letter f. We provide a C++ class that reads OBJ files. Add this code to your rendering engine. You have to write the necessary code to create OpenGL geometry out of the 3D data structure (20 points). Use a method of your choice to make the tessellation of the object visible, for instance by using different colors (random or following an algorithm) for different triangles, wire frames around the triangles (5 points).

Add support for keyboard commands to select and switch between one of five .obj files (5 points). You can parse key presses with the glutKeyboardFunc command, for which you can find a good tutorial here.

These five OBJ files are available for download. Map each of them to one of the keys '1' through '5'.

You will notice that without further measures, the objects in the OBJ files may be too small or too large for your rendering window. To render the objects as large as possible while still completely fitting in the window, use the following approach:

  • Calculate the minimum and maximum vertex coordinates in all three dimensions (5 points) by writing three 'for' loops which traverse all vertices, one for each dimension, storing the smallest and largest values they come across.
  • Your window origin is zero, so you are going to have to translate the model towards it if its origin is not already zero. Based on the amount of translation, you need to create a translation matrix to center the object (5 points).
  • Find out approximately what size objects your rendering window allows, for instance by drawing the sphere model (which is one unit wide) and scaling it up or down until it fits in 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. (5 points)
  • Allow the user to trigger this automatic size adjustment by pressing the 'a' key (5 points).

The 's' key should toggle a rotation of the object around its y axis, similar to the cube in the base code. To toggle means that repeated key presses on 's' will start and stop the rotation (5 points).

Make the code robust enough that the user can change the 3D model, adjust its size and start/stop the rotation at any point by pressing the respective keys, without having to observe a specific order (5 points).


3. Optional Project: Height Map (10 points)

Generate and display a 3D mesh out of a 2D height map image. Wikipedia has a great description of this topic. Allow the user to interactively fly over the height map, similar to a simple flight simulator. You can use the height map image from the Wikipedia page, which you will also find below, or create your own with a paint program or another method of your choice.

Heightmap.png
Height map image from Wikipedia

To get full credit you need to implement the following features:

  • Load the height map image and create a 3D mesh out of it (4 points). You can either read the Wikipedia PNG image file with your own reader, or read this PGM image file with this piece of C code. Note that this code returns a one dimensional array, which you have to interpret as a two-dimensional array based on the width of the image.
  • Use a color gradient from blue (water) to yellow (sand), green (grass), grey (rock) and white (snow) to color the terrain polygons, depending on their height (2 points).
  • Create a navigation mode, in which the user can rotate the camera left or right (with keys 'a' and 'd'), move up or down (with keys 'w' and 's'), and change the velocity of the flight ('m' for slower, 'k' for faster) (3 points). Scale the terrain to a size appropriate for a flight simulator scenario (1 point).

If you use the Wikipedia height map, the resulting terrain should look similar to this, except that it needs to be colored as described above:

Heightmap rendered.png
3D terrain generated from height map