Difference between revisions of "Project3Fall13"

From Immersive Visualization Lab Wiki
Jump to: navigation, search
(Created page with "=Project 3: Rasterization= In this project you will need to implement your own software rasterizer. We provide a code template for the interface between your software rasteri...")
 
(Undo revision 8475 by Jschulze (talk))
 
(27 intermediate revisions by one user not shown)
Line 1: Line 1:
 
=Project 3: Rasterization=
 
=Project 3: Rasterization=
  
In this project you will need to implement your own software rasterizer. We provide a code template for the interface between your software rasterizer and OpenGL.  
+
In this project you will need to implement your own software rasterizer. This means that you are going to implement the entire graphics pipeline from 3D vertices to filled triangles in a software frame buffer yourself. We provide a code template for the interface between your software rasterizer and OpenGL, which is needed to display the frame buffer on the screen.  
  
<b>The description is going to go online by early afternoon on Oct 12th</b>
+
This assignment is due Friday, October 18th. It will be discussed by TA Matteo on Monday, October 14th at 3pm in Center Hall 105.
  
<!--
+
We provide [[rasterizer.cpp | a code template]] for you which displays a software frame buffer on the screen. Your task is to rasterize your scene (described below) into this frame buffer. Throughout this assignment <b>do not use any OpenGL routines which aren't already in the base code!</b> Instead, use <b>your own</b> vector and matrix classes from assignment #1 and add your own rasterization code.  
The project has three parts. You can obtain full credit (100 points) for completing the first two parts. The third one is optional.
+
+
This project is due on <b>Friday October 14, 2011</b>. You need to present your results in the lab as usual. The homework introduction in the computer lab will be on <b>Monday, October 10</b> at 3pm (Lex Lacson).
+
  
==0. Getting started==
+
==1. Rendering Points (30 points)==
 
+
===Base Code===
+
 
+
We provide [[rasterizer.cpp|base code]] for you which displays a frame buffer on the screen. Your task is to rasterize your scene into this frame buffer. Throughout this assignment do not use any OpenGL routines which aren't already in the base code! Instead, use <b>your own</b> vector and matrix classes from assignment #1 and add your own rasterization routines.
+
 
+
==1. Rendering vertices (30 points)==
+
  
 
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.
 
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 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>)
+
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>10 points</b>)
  
 
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>)
 
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>)
  
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:
+
To verify that 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 that image. (<b>5 points</b>)
 
+
* Aspect ratio: window dependent (<tt>window_width</tt>/<tt>window_height</tt>)
+
* Vertical field of view: 60 degrees
+
* Near, far clip planes: 1, 100
+
* Center of projection: -10, 40, 40
+
* Look at point: -5, 0, 0
+
* Up vector 0, 1, 0
+
 
+
==2. Rasterization and z-buffering==
+
 
+
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.
+
 
+
===2a. Basic rasterizer with linear color interpolation (<b>30 points</b>)===
+
+
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>.
+
 
+
===2b. Perspectively correct interpolation (<b>20 points</b>)===
+
  
<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>
+
==2. Rendering Triangles (40 points)==
  
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>
+
Next 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.
  
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>.  
+
Fill the triangles using linear interpolation of colors using barycentric coordinates, as discussed in class. 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.  
  
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.
+
To test your rasterization code, first render the house from part 1 in the two orientations. Allow switching to the two views of it on function keys 'F8' and 'F9'.
  
===2c. Two-level hierarchy (<b>20 points</b>)===
+
Once that works, add support for the spinning cube from assignment 1 and 2, but render it with your software rasterizer, and assign different colors to the vertices, so that none of the faces are rendered in a solid color. Allow switching to it with function key 'F1'.
  
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>)
+
Then add support for the five OBJ files from assignment 2 and allow switching to them with function keys 'F2' through 'F6', just like in assignment 2, but again, render them with your software rasterizer and display the rendering time (in milliseconds).
  
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>)
+
In Windows, the [http://www.cplusplus.com/reference/clibrary/ctime/clock/ clock()] function allows you to measure time. In Linux (and Mac OS?), use [http://docs.sun.com/app/docs/doc/816-5168/gethrtime-3c?a=view gethrtime()] or a different function to measure the time.
  
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.
+
Measure and take notes of the rendering times for each of the five 3D models.
  
==3. Optional Exercise: Performance Optimization (<b>max. 10 points</b>)==
+
Your score will consist of the following components:
  
Rasterization is the computational bottleneck in many rendering systems. Therefore, optimizing this part of your rendering pipeline is a worthwhile endeavor. The goal of this optional part of the project is to squeeze as much rendering performance as possible out of your rasterizer. In order to get the points, you need to demonstrate your optimized algorithm in comparison to the non-optimized algorithm, which you should do by supporting key strokes: 'n' for non-optimized, 'o' for optimized. You also need to display the frame rate (e.g., in the console window), and use complex enough geometry to produce a noticeable change between non-optimized and optimized mode.
+
* Triangles render in correct depth order (using your z-buffer algorithm): <b>15 points</b>
 +
* Correct coloring of triangles: <b>15 points</b>
 +
* Function keys supported as described: <b>5 points</b>
 +
* Measured rendering times for all five OBJ files: <b>5 points</b>
  
You can choose <b>one of the two</b> following optimization techniques.  
+
==3. Optimization (30 Points)==
  
===Multi-level hierarchy (<b>10 points</b>)===
+
Extend your rasterizer by adding a two-level hierarchy as discussed in class, toggled on and off with the 'o' key. The main idea is to split each projected triangle's bounding box into n*n smaller tiles of equal size. Experiment with different numbers for n (start with 2x2 tiles, then 3x3, then 4x4, ...) and pick one that works particularly well (you will notice that the performance degrades when there are too many tiles). Before testing each pixel within a tile, the rasterizer determines if the triangle overlaps with the tile (we suggest an algorithm for this intersection test on the course slides). The whole tile can be skipped if this is not the case. Allow rendering of all of your 3D models with this optimization (cube, house and OBJ files) (<b>20 points</b>). Note that on newer computers this algorithm will only result in a speedup with low-polygon objects, such as the cube.
  
Extend the two-level hierarchy from part 2c to a multi-level hierarchy with adaptive tile sizes. This strategy allows you to start with large tiles, and discard large areas that do not overlap with the triangle. By splitting tiles that overlap partially with the triangle into smaller tiles, you avoid the overhead of a two-level hierarchy with large tiles. This technique is also known as a [http://en.wikipedia.org/wiki/Quadtree Quadtree].
+
To demonstrate how the algorithm works, outline the tile boundaries in red. Toggle this mode on and off with the 'b' key. (<b>5 points</b>)
  
===Multi-threading (<b>10 points</b>)===
+
Test the performance of the tiling approach by measuring the rendering times for each of the five OBJ files. Write those numbers down next to the rendering times without optimization (<b>5 points</b>).
  
Rasterization is an "embarrassingly parallel" operation. Any number of threads may, in parallel,  test whether pixels are inside a triangle and perform z-buffering. Chances are that your CPU either has multiple cores or supports hyper-threading. This means that rasterizing using multi-threading should increase rendering performance. The idea is to start several threads (depending on the number of cores your CPU has, times two if hyper-threading is supported) to rasterize each triangle. Each thread could compute the pixels of one line of pixels, moving on to the next unassigned line when done. In the two-level scheme, the threads could work on different tiles.
+
==4. Optional: Translucent Triangles (10 Points)==
  
Here are a couple of pointers to get started:
+
Build a scene out of two spheres from part 2, 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. Add this scene to your rasterization program by switching to it with the 'F10' key (<b>3 points</b>)
  
* [http://www.devarticles.com/c/a/Cplusplus/Multithreading-in-C/ Multithreading in Windows]
+
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 (<b>3 points</b>).
* [http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html Multithreading in Linux]
+
  
-->
+
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. Toggle depth sorting on and off with the 't' key. (<b>4 points</b>)

Latest revision as of 23:53, 11 April 2015

Contents

Project 3: Rasterization

In this project you will need to implement your own software rasterizer. This means that you are going to implement the entire graphics pipeline from 3D vertices to filled triangles in a software frame buffer yourself. We provide a code template for the interface between your software rasterizer and OpenGL, which is needed to display the frame buffer on the screen.

This assignment is due Friday, October 18th. It will be discussed by TA Matteo on Monday, October 14th at 3pm in Center Hall 105.

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

1. Rendering Points (30 points)

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 geometry from homework assignment 2 as your geometry.

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 (window_width and window_height) and call it from the reshape 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. (10 points)

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 sample scene. For this part of the assignment, create a method rasterizeVertex which projects each vertex of the house to image coordinates and sets the color of the corresponding pixel to white using drawPoint. (15 points)

To verify that 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 that image. (5 points)

2. Rendering Triangles (40 points)

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

Fill the triangles using linear interpolation of colors using barycentric coordinates, as discussed in class. 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.

To test your rasterization code, first render the house from part 1 in the two orientations. Allow switching to the two views of it on function keys 'F8' and 'F9'.

Once that works, add support for the spinning cube from assignment 1 and 2, but render it with your software rasterizer, and assign different colors to the vertices, so that none of the faces are rendered in a solid color. Allow switching to it with function key 'F1'.

Then add support for the five OBJ files from assignment 2 and allow switching to them with function keys 'F2' through 'F6', just like in assignment 2, but again, render them with your software rasterizer and display the rendering time (in milliseconds).

In Windows, the clock() function allows you to measure time. In Linux (and Mac OS?), use gethrtime() or a different function to measure the time.

Measure and take notes of the rendering times for each of the five 3D models.

Your score will consist of the following components:

  • Triangles render in correct depth order (using your z-buffer algorithm): 15 points
  • Correct coloring of triangles: 15 points
  • Function keys supported as described: 5 points
  • Measured rendering times for all five OBJ files: 5 points

3. Optimization (30 Points)

Extend your rasterizer by adding a two-level hierarchy as discussed in class, toggled on and off with the 'o' key. The main idea is to split each projected triangle's bounding box into n*n smaller tiles of equal size. Experiment with different numbers for n (start with 2x2 tiles, then 3x3, then 4x4, ...) and pick one that works particularly well (you will notice that the performance degrades when there are too many tiles). Before testing each pixel within a tile, the rasterizer determines if the triangle overlaps with the tile (we suggest an algorithm for this intersection test on the course slides). The whole tile can be skipped if this is not the case. Allow rendering of all of your 3D models with this optimization (cube, house and OBJ files) (20 points). Note that on newer computers this algorithm will only result in a speedup with low-polygon objects, such as the cube.

To demonstrate how the algorithm works, outline the tile boundaries in red. Toggle this mode on and off with the 'b' key. (5 points)

Test the performance of the tiling approach by measuring the rendering times for each of the five OBJ files. Write those numbers down next to the rendering times without optimization (5 points).

4. Optional: Translucent Triangles (10 Points)

Build a scene out of two spheres from part 2, 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. Add this scene to your rasterization program by switching to it with the 'F10' key (3 points)

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 (3 points).

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. Toggle depth sorting on and off with the 't' key. (4 points)