Difference between revisions of "Project3SP15"

From Immersive Visualization Lab Wiki
Jump to: navigation, search
(4. Per Pixel Colors (15 Points))
 
(35 intermediate revisions by one user not shown)
Line 7: Line 7:
 
The homework discussion for this project will be on <b>Monday, April 13th</b>.
 
The homework discussion for this project will be on <b>Monday, April 13th</b>.
  
==0. Getting started==
+
==Getting started==
 
+
===Base Code===
+
  
 
We provide [[rasterizer.cpp|base code]] for you which displays a software frame buffer on the screen. Your task is to rasterize your scene into this frame buffer. In this assignment you are not allowed to use any OpenGL calls which aren't already in the base code. Instead, use your vector and matrix classes from assignment #1 and add your own rasterization routines.
 
We provide [[rasterizer.cpp|base code]] for you which displays a software frame buffer on the screen. Your task is to rasterize your scene into this frame buffer. In this assignment you are not allowed to use any OpenGL calls which aren't already in the base code. Instead, use your vector and matrix classes from assignment #1 and add your own rasterization routines.
  
<!--
+
==1. Rasterize Vertices (20 Points)==
==1. Rendering vertices (30 points)==
+
 
 +
In the first step of building your own rasterizer you need to project the vertices of the 3D models from assignment 2 to the correct locations in the output image (frame buffer).
  
The goal of the first step towards building your software rasterizer is to project vertices of given geometry to the correct locations in the output image (frame buffer). Use the [[house-proj3.cpp|house geometry]] from homework assignment 2 as your geometry.
+
You should use the same model, camera and projection matrices as in assignment 2, so that you can use the rendering results from it to verify that your software rasterizer works correctly. We recommend that you start with your code from assignment 2 and copy-paste code from rasterizer.cpp where you need it.  
  
You can re-use your model (M), camera (C), and projection (P) matrices from the previous assignment. Add a viewport matrix (D). Implement a method to set the viewport matrix based on the window size (<tt>window_width</tt> and <tt>window_height</tt>) and call it from the <tt>reshape</tt> function. Your program must correctly adjust projection and viewport matrix, as well as frame buffer size when the user changes the window size. Correctly means that the house needs to remain centered in the window and get uniformly scaled to match the window size. (<b>5 points</b>)
+
Add support for the 'e' key to switch between your rendering engines: OpenGL from the previous assignment and your new software rasterizer. When in software rendering mode, use the - (minus) and + (plus) keys to go back and forth between the different parts of this homework project, which all build upon another.
  
Then write a method to rasterize a vertex. You can use <tt>drawPoint</tt> from the base code to set the values in the frame buffer. Call this method from the draw callback (<tt>display</tt> function in base code) for every vertex in the sample scene. For this part of the assignment, create a method <tt>rasterizeVertex</tt> which projects each vertex of the house to image coordinates and sets the color of the corresponding pixel to white using <tt>drawPoint</tt>. (<b>15 points</b>)
+
Add a viewport matrix (D) to your code, and implement a method to create D based on the window size (<tt>window_width</tt> and <tt>window_height</tt>) and call it from the <tt>GLUT reshape</tt> function. Your program must correctly adjust projection and viewport matrix, as well as frame buffer size when the user changes the window size, just like in your previous assignment.
  
To make sure your implementation is correct, use the same values for camera and projection matrix as in Image 2 of Exercise 1c of homework assignment 2, and compare the result of your rasterized vertices to the image. (<b>10 points</b>) As a reminder, here are the values again:
+
Then write a method to rasterize a vertex. You can use <tt>drawPoint</tt> from the base code to set the values in the frame buffer. Call this method from the draw callback (<tt>display</tt> function in base code) for every vertex in the 3D model. For this part of the assignment, create a method <tt>rasterizeVertex</tt> which projects each vertex of the house to image coordinates. At this stage, render every point in bright white.
  
* Aspect ratio: window dependent (<tt>window_width</tt>/<tt>window_height</tt>)
+
'''Grading:'''
* Vertical field of view: 60 degrees
+
* -5 if rasterized image doesn't resize the same way as in OpenGL mode
* Near, far clip planes: 1, 100
+
* -10 if rasterized image doesn't respond to keyboard keys
* Center of projection: -10, 40, 40
+
* -5 if not all 3 models load
* Look at point: -5, 0, 0
+
* -10 if vertex positions wrap around when off screen
* Up vector 0, 1, 0
+
* -5 if bounding box is not fully traversed (leaving blank lines)
  
==2. Rasterization and z-buffering==
+
==2. Rasterize Triangles (40 Points)==
  
For this part of the project you will need to implement a triangle rasterizer based on barycentric coordinates as discussed in class. The rasterizer should first compute a bounding box around the triangle, limited to the extent of the triangle. It then needs to step through all pixels of the bounding box and test if they lie within the triangle by computing their barycentric coordinates.
+
Now you will need to render the objects' triangles instead of just the vertices. Use the Barycentric interpolation algorithm to determine whether a framebuffer pixel is inside or outside of the triangle you are rasterizing. To do this you should first compute a bounding box around the triangle, limited to the extent of the triangle, then step through all pixels in the bounding box and test if they lie within the triangle by computing their barycentric coordinates. Pick a random color for each triangle and use it throughout the triangle.  
  
===2a. Basic rasterizer with linear color interpolation (<b>30 points</b>)===
+
Notice that because you are not depth sorting the triangles, some of the foreground triangles might get overwritten by background triangles - we will fix this in the next step.
+
Implement <b>linear</b> interpolation (as opposed to hyperbolic interpolation) of colors using barycentric coordinates. Implement a z-buffer data structure to resolve visibility when rendering multiple triangles. For z-buffering, you should linearly interpolate z/w and scale it from [0,1] and use it as the value in the z-buffer.  
+
  
Use this [[colorful-house.cpp|colorful house geometry]] to test and demonstrate your algorithm. Use the same camera and projection matrices as in exercise 1. Scores: correct depth display (using z-buffer): <b>15 points</b>; correct linear color interpolation: <b>15 points</b>.
+
'''Grading:'''
 +
The same deductions apply as in part 1 if not already deducted there.
  
===2b. Perspectively correct interpolation (<b>20 points</b>)===
+
==3. Z-Buffer (25 Points)==
  
<b>Note that this algorithm will be discussed in more detail in the lecture on Oct 11. In the meantime you can safely skip to part 2c and revisit this part later, unless you can figure out the equations from the lecture slides.</b>
+
So far the triangles are rendered in the order in which they are listed in the file. Triangles rendered later will overwrite those that were rendered earlier. This approach causes problems with occlusion.
  
Implement perspectively correct interpolation of colors using hyperbolic interpolation. Apply it to the colorful house from exercise 2a. Add keyboard support to switch between linear ('l' key) and hyperbolic ('h' key) interpolation: use the <tt>glutKeyboardFunc</tt> callback (see base code). <b>15 points</b>
+
The remedy is to implement the z-buffer algorithm. Linearly interpolate z/w for every point using the Barycentric interpolation weights and scale it to the range of 0 to 1, between the near and far planes. The result is the z-value, which you need to compare with the previously stored z-buffer value for this pixel. Make sure that you clear the z-buffer (initialize with 1) whenever you clear the frame buffer.
  
The house geometry is not a great example for this section of the assignment, because the visual difference between linear and hyperbolic interpolation is very subtle. So we ask you to additionally render a more suitable object. Create a black-and-white striped triangle in the following way: set one vertex's color to (1,1,1) and the other two to (0, 0, 0).  After computing the interpolated color use the following repetitive function on each component of the color to generate the repetitive stripe pattern: <tt>f(x) = ((int)floor(10*x)) % 2</tt>.
+
'''Grading:'''
 +
* -10 if z-buffer indices are incorrectly calculated
 +
* -5 if z-buffer is not initialized correctly for every frame
 +
* -5 if z-buffer does not resize correctly on window resizes
  
Compare the result to the same striped triangle rendered with the linear interpolation from exercise 2a. <b>Choose model, camera and projection matrices with strong perspective distortion to make the difference obvious.</b> Like with the house, allow the user to switch between linear ('l' key) and hyperbolic ('h' key) interpolation. <b>5 points</b>. Note: you will only get full credit if your perspective distortion is strong enough to see an obvious difference between the two modes.
+
==4. Per Pixel Colors (15 Points)==
  
===2c. Two-level hierarchy (<b>20 points</b>)===
+
While triangle overlaps are now correctly resolved, the triangles look very boring. When rasterizing a triangle, change out the random color to a per pixel shading algorithm: use barycentric interpolation to interpolate the vertices' normal vectors within the triangle. Then color each pixel by interpreting the normal at it as an RGB color: the x component determines the amount of red, y determines green, z for blue. Note that the x/y/z values range between -1 and +1, so to map them to colors you'll have to add one and divide by two, to bring them into the desired range of 0 to 1.
  
Extend your rasterizer by adding a two-level hierarchy as discussed in class: The main idea is to split each projected triangle's bounding box into <b>n*n</b> smaller tiles of equal size. Before testing each pixel within a tile, the rasterizer determines if the triangle overlaps with the tile. The whole tile can be skipped if this is not the case. Use the house geometry from exercise 1, not the colorful house. (<b>10 points</b>) To demonstrate how the algorithm works, outline the tile boundaries of one triangle in the frame buffer in red. (<b>5 points</b>)
+
'''Grading:'''
 +
* -10 if colors are not interpolated across triangles
  
Test the performance of the tiling approach by measuring rendering times for at least three different numbers of tiles (different values of <b>n</b>): let the house rotate about its origin and measure the time it takes to render 100 frames of the rotating house. Report the average frame rate (=number of frames rendered per second) in the console window. Support three different tile sizes and allow the user to switch between them using the keys '1', '2', and '3'. Don't draw the bounding boxes for this performance test. Your algorithm must show a speedup for certain values of <b>n</b>, compared to <b>n</b> = 1. What value of <b>n</b> gives you the best performance? (<b>5 points</b>)
+
==5. Extra Credit: Translucent Spheres (10 Points)==
  
Note: In Linux, the C++ function [http://docs.sun.com/app/docs/doc/816-5168/gethrtime-3c?a=view gethrtime()] can be used to measure time; in Windows, [http://www.cplusplus.com/reference/clibrary/ctime/clock/ clock()] can be used.
+
Build a scene out of two [http://ivl.calit2.net/wiki/files/sphere.obj spheres], with one spinning around the other, rotating around the Y axis, so that one sphere is sometimes in front and sometimes behind the other sphere. The spheres should never intersect.  
  
==3. Optional Exercise: Performance Optimization (<b>max. 10 points</b>)==
+
Make both spheres translucent by mapping an opacity value (=alpha value) of roughly 50% (or 0.5 on a scale between 0 and 1) to all triangles.
  
-->
+
Render the overlapping spheres correctly, as if they were made out of translucent glass: to do that the triangles need to be rendered in back-to-front order. To accomplish this you will need to sort all triangles of both spheres from back to front (based on their distance from the camera), every time you render a frame. To sort the triangles, calculate the center point of each triangle, project it into camera coordinates, and use the resulting z value as the sorting criterion.

Latest revision as of 12:22, 17 April 2015

Contents

Project 3: Software Rasterizer

In this project you will need to write your own software rasterizer. We provide some code that will allow you to integrate your rasterizer with OpenGL.

The project is due on Friday, April 17th, 2015 at 1pm. You need to present your results in the CSE basement labs as usual, grading starts at 12:15pm.

The homework discussion for this project will be on Monday, April 13th.

Getting started

We provide base code for you which displays a software frame buffer on the screen. Your task is to rasterize your scene into this frame buffer. In this assignment you are not allowed to use any OpenGL calls which aren't already in the base code. Instead, use your vector and matrix classes from assignment #1 and add your own rasterization routines.

1. Rasterize Vertices (20 Points)

In the first step of building your own rasterizer you need to project the vertices of the 3D models from assignment 2 to the correct locations in the output image (frame buffer).

You should use the same model, camera and projection matrices as in assignment 2, so that you can use the rendering results from it to verify that your software rasterizer works correctly. We recommend that you start with your code from assignment 2 and copy-paste code from rasterizer.cpp where you need it.

Add support for the 'e' key to switch between your rendering engines: OpenGL from the previous assignment and your new software rasterizer. When in software rendering mode, use the - (minus) and + (plus) keys to go back and forth between the different parts of this homework project, which all build upon another.

Add a viewport matrix (D) to your code, and implement a method to create D based on the window size (window_width and window_height) and call it from the GLUT reshape function. Your program must correctly adjust projection and viewport matrix, as well as frame buffer size when the user changes the window size, just like in your previous assignment.

Then write a method to rasterize a vertex. You can use drawPoint from the base code to set the values in the frame buffer. Call this method from the draw callback (display function in base code) for every vertex in the 3D model. For this part of the assignment, create a method rasterizeVertex which projects each vertex of the house to image coordinates. At this stage, render every point in bright white.

Grading:

  • -5 if rasterized image doesn't resize the same way as in OpenGL mode
  • -10 if rasterized image doesn't respond to keyboard keys
  • -5 if not all 3 models load
  • -10 if vertex positions wrap around when off screen
  • -5 if bounding box is not fully traversed (leaving blank lines)

2. Rasterize Triangles (40 Points)

Now you will need to render the objects' triangles instead of just the vertices. Use the Barycentric interpolation algorithm to determine whether a framebuffer pixel is inside or outside of the triangle you are rasterizing. To do this you should first compute a bounding box around the triangle, limited to the extent of the triangle, then step through all pixels in the bounding box and test if they lie within the triangle by computing their barycentric coordinates. Pick a random color for each triangle and use it throughout the triangle.

Notice that because you are not depth sorting the triangles, some of the foreground triangles might get overwritten by background triangles - we will fix this in the next step.

Grading: The same deductions apply as in part 1 if not already deducted there.

3. Z-Buffer (25 Points)

So far the triangles are rendered in the order in which they are listed in the file. Triangles rendered later will overwrite those that were rendered earlier. This approach causes problems with occlusion.

The remedy is to implement the z-buffer algorithm. Linearly interpolate z/w for every point using the Barycentric interpolation weights and scale it to the range of 0 to 1, between the near and far planes. The result is the z-value, which you need to compare with the previously stored z-buffer value for this pixel. Make sure that you clear the z-buffer (initialize with 1) whenever you clear the frame buffer.

Grading:

  • -10 if z-buffer indices are incorrectly calculated
  • -5 if z-buffer is not initialized correctly for every frame
  • -5 if z-buffer does not resize correctly on window resizes

4. Per Pixel Colors (15 Points)

While triangle overlaps are now correctly resolved, the triangles look very boring. When rasterizing a triangle, change out the random color to a per pixel shading algorithm: use barycentric interpolation to interpolate the vertices' normal vectors within the triangle. Then color each pixel by interpreting the normal at it as an RGB color: the x component determines the amount of red, y determines green, z for blue. Note that the x/y/z values range between -1 and +1, so to map them to colors you'll have to add one and divide by two, to bring them into the desired range of 0 to 1.

Grading:

  • -10 if colors are not interpolated across triangles

5. Extra Credit: Translucent Spheres (10 Points)

Build a scene out of two spheres, with one spinning around the other, rotating around the Y axis, so that one sphere is sometimes in front and sometimes behind the other sphere. The spheres should never intersect.

Make both spheres translucent by mapping an opacity value (=alpha value) of roughly 50% (or 0.5 on a scale between 0 and 1) to all triangles.

Render the overlapping spheres correctly, as if they were made out of translucent glass: to do that the triangles need to be rendered in back-to-front order. To accomplish this you will need to sort all triangles of both spheres from back to front (based on their distance from the camera), every time you render a frame. To sort the triangles, calculate the center point of each triangle, project it into camera coordinates, and use the resulting z value as the sorting criterion.