In this assignment, you will implement a rasterization library in software that emulates the way 3D scenes are rendered on the GPU. Your software rasterizer should support the following features that we have covered in class: triangle rasterization, supersampling, affine and perspective transformations, z-buffering, and perspective-correct interpolation.
We will use SDL2 for window management, and GLM for vector and matrix datatypes. GLM provides convenient vector and matrix operations following GLSL syntax. Go through the linked page and learn the operations, so that you can use them instead of re-implementing everything like vector addition, dot products etc. yourself. Generally all the GLSL operations on the linked page are supported in GLM, except for precision qualifiers and “swizzling”.
The code framework for this assignment is posted at https://git.iitd.ac.in/col781-2302/a1. I suggest you clone it using Git instead of simply downloading it, in case I update it in the future.
This code framework defines, in the file src/api.inc
, a
simple rasterization API for drawing objects made of triangles and
displaying them in a window on the screen. You can look at
examples/e1.cpp
for an example of how this API can be used,
and read the comments in src/api.inc
for further
details.
The API is implemented by two different classes. One named
COL781::Hardware::Rasterizer
is defined in
src/hw.*pp
; it performs hardware rasterization on the GPU
using OpenGL. If you compile the project right now, the executable
e1
produced by examples/e1.cpp
will use this
class to draw the tick mark described in class.
The other implementation of the API is named
COL781::Software::Rasterizer
and is declared in
src/sw.hpp
; it is intended to perform software
rasterization on the CPU. However, its implementation in
src/sw.cpp
is incomplete, so it cannot be used right
now!
Your main job in this assignment is to add your own code to
src/sw.cpp
to make all the provided examples work with your
software rasterizer. I suggest you do this incrementally, implementing
enough methods to make examples/e1.cpp
work, then do
examples/e2.cpp
, and so on. You can change the rasterizer
used by each example by commenting/uncommenting the two
namespace R = ...
lines. Note that the software rasterizer
class uses different types than the hardware rasterizer, but the
function calls are the same, so the same example code can use either
implementation.
As you modify the software rasterizer implementation, please keep a few things in mind:
Attribs
and
Uniforms
) to add more methods if you need. However, you
should not change their purpose: the Attribs
class should
represent the attributes of one vertex or one
fragment, not the entire array of attributes for all vertices.vsIdentity
, fsConstant
, etc.) to
understand how they work.examples/e*.cpp
.Here are some further details on how to proceed:
e1
and e2
just require you to
implement a clear
method that clears the framebuffer by
setting all pixels to a given colour, a triangle rasterization procedure
that draws a single triangle onto the framebuffer, and a
drawObject
method that draws an arbitrary triangulated
shape specified via vertex coordinates and triangle vertex indices.
Since this example is 2D, you can ignore the w and z
coordinates for now.
initialize
method. You may assume that n must be a
perfect square. Once supersampling is on, the user should be able to
draw the scene as usual and automatically obtain anti-aliased results.
Verify this by modifying the initialize
calls in
e1
and e2
and checking that the triangle edges
look smoother.From e3
onwards, you will have to add support for
rendering 3D triangles. The modeling, viewing, and projection
transformations will already be provided by the user and applied by the
vertex shader. Your job is to do perspective division,
perspective-correct interpolation, and depth testing.
glm::vec4(x, y, z, w)
to a
glm::vec3(x/w, y/w, z/w)
. This should not change the
results of any of the 2D examples since their w is always 1,
but it should make example e5
look like a rotating 3D
square.enableDepthTest()
is called, to avoid changing the 2D
examples. Then examples e3
and e4
should show
correct visibility like in lecture 7. When clearing the screen, remember
to clear the z-buffer as well. Also verify that this continues to work
when supersampling is enabled.e5
is drawn correctly. It should
not look like the distorted gradient in lecture 8.With this, you should be able to run all five of the provided examples with your software rasterizer, and get results comparable to those produced by the hardware.
A secondary goal in this assignment is to use this API to draw some
interesting scenes. For each scene, create a new .cpp
file
under examples/
and add it to
CMakeLists.txt
.
Submit your assignment on Moodle before midnight on the due date. Your submission should be a zip file that contains your entire source code for the assignment, not including any binary object files or executables. The zip file should also contain a PDF report that includes the following:
Separately, each of you should individually submit a short response in a separate form regarding how much you and your groupmate(s) contributed to the work in this assignment.