# ECE4893A/CS4803MPG: Multicore and GPU Programming for Video Games

## Fall 2009

## Homework #2: “Roll Your Own” 3-D Rendering

## Due: Tuesday, Sept. 15 at 23:59:59 (via T-square)

**Late policy: The homework will be graded out of 100 points. We will
accept late submissions up to Saturday, Sept. 19 at 23:59:59; however,
for every day that is it is overdue,
we will subtract 20 points from the total.**

We understand thst sometimes multiple assignments hit at once, or other

life events intervene, and hence you have to make some tough choices. We’d

rather let you turn something in

late, with some points off, than have a “no late assignments

accepted at all”

policy, since the former encourages you to still do the assignment

and learn something from it, while the latter just grinds

down your soul. The

somewhat aggressive late penalty is not

intended to be harsh – it’s intended to

encourage you to get things in relatively on time (or just punt if you have

to and not leave it hanging over you all

semester) so that you can move on to

assignments for your other classes.

**Read these instructions completely and carefully before beginning your
work.**

Using a high-level scripting language of your choice, write a program that

implements the

geometry transformations and lighting calculations Prof. Lee discussed in

lecture to render

an image of a scene consisting of a single 3-D object.

For this assignment, you shouldn’t

worry too much about “modularity,” “reuse,” “extensibility,” “good taste,”

etc.,

and you shouldn’t worry at all about speed.

This is a “quick and dirty”

assignment that is primarily intended to

make you review the material Prof. Lee has covered and make sure that

you understand it. Direct3D, OpenGL, and XNA (using BasicEffect)

handles most of this “behind the

scenes,” but we want

to make sure you understand what is going on behind the scenes. Also, you

wind up coding much

of this “behind the scenes” work explicitly when you write vertex shaders

in languages such as

HLSL/Cg; hence, there is value in first testing your understanding of

these basic computer

graphics concepts using

a simple language like MATLAB before we add the additional complexities of

shader languages on

top of it.

Your lighting model should include ambient and emissive components, as well

as diffuse

and specular components arising from a single light source.

At the top of your program, you should set variables that determine:

- The position and RGB color of the light source.
- The RGB color of the ambient light.
- The position and orientation of the camera.
- The position and orientation of the object.
- The “field of view” and the “near” and “far” distances

the perspective projection viewing frustum.

You may assume an aspect ratio of one. (See slide

24 of the “3D Rendering Pipeline (II)” slide set.)

When we run your code, we should be able to change the variables at the top

to render

different scenes. The variables should be given easily understandable names.

The first time we ran this course,

the students were required

to find

their own 3-D model and figure out how to read it in. This turned out to be

pretty challenging. So, this year, we are going to let you benefit of

using some of the models they converted to a “raw triangle” format:

shuttle,

cessna,

ikarab.

Pick one that you like.

To give credit where it is

due, I have added the names of the students who converted the models to

raw triangle format in the

filename.

The files consists of rows of

9 numbers, which are just the x,y,z coordinates of the three vertices of

the triangles.

You may use one of these model for your assignment, or

if you are feeling ambitious, you may find and use a model not given here

if you can figure out how to read it in.

(This won’t be worth more points, but if you’re a Halo fan, for instance,

and find a model of the Master Chief – go for it! It could be fun.)

In the interest of simplicity, you

should feel free to use the same emissive color for all the facets, the

same specular

color for

all the facets, etc.

If you feel like doing something more sophisticated, where

different facets have different properties,

you are welcome to do so, but it is not required for full credit.

For this assignment, use a “flat shading” model; have your program

compute its

own normal for each flat-faced triangle based on the vertex

information for that

triangle.

At an appropriate point in your processing chain, you should perform

“backface culling” and

remove those facets that are facing away from the camera. (Be careful to

make sure the model you are using is following the conventions you

are expecting it to!)

<!–**Clarification: It seems that a lot of models
out there are not consistent in following either a right hand or left
hand rule. We want to see the line(s) in your code that perform(s) this
culling
operation, but if you see that half your facets randomly disappear when
you turn this on because the modeler was sloppy, feel free to comment it
out.** –>

Once you get things

into “screen coordinates,”

you only need to worry

about “clipping in z,” i.e. delete all

facets whose z-values all fall outside the viewing frustum in

the z-dimension. (If only some of the vertices

fall outside the z-dimension, go ahead and

render it.) We’ll let the scripting

language’s native triangle drawing features worry

about clipping in x and y.

Instead of using a z-buffer to handle the fact that some facets will

obscure other

facets,

use “z-sorting.” Z-sorting was popular when memory was

expensive; for instance,

the Playstation 1

uses z-sorting. Real-time

implementations typically use some sophisticated data structures to

do the sorting; here, you can

just use the “sort” command built into whatever scripting language

you use. For each facet, compute the average of the z-values of its

vertices, and then sort

the facets in order of

these z-value averages. Then, render the facets in order of farthest

to closest.

Again, don’t worry about efficiency when doing the culling and sorting.

It doesn’t matter at this stage if your program runs more slowly with

culling than without it. All we care about is that you understand the

core operations.

**Implementation language:**

You should choose a

scripting language that has built-in matrix and vector operations, as well

as a mechanism to draw

filled 2-D triangles on the

screen – we will let the language handle the

rasterization process for you.

**The language you choose may have built
in 3-D graphics operations, but you should not use them for this
assignment!**

We recommend using MATLAB; it has all the operations you need

“out of the box,” including

dot and cross products; you can compute many dot and cross products at

once with a single

line of code. It should be available on

most campus lab machines, such as the library and CoC and

ECE computing labs. (You also may be able to get some use out of

octave or

FreeMat,

which are open-source MATLAB equivalents, although I haven’t

tried their graphics features so I’m not sure about that part.)

MATLAB’s vectorization features let you write compact,

expressive code.

MATLAB is now used in the intro CS class for

engineers, and is also extensively used

throughout the ECE curriculum, particularly in ECE2025: Introduction to

Signal Processing.

CS students will have been less likely to be exposed to it;

however, an advanced CS undergraduate, who has

had exposure to many different kinds of programming

languages, will have little difficulty picking it up.

In any case, if you are CS major, you will find

MATLAB to be a worthy weapon to add to your arsenal,

as it lets you try out a variety of numerical

algorithms with a minimal amount of fuss. Here

is an examples session at a MATLAB prompt that illustrates

various features. ECE students will find this familiar; CS students

should be able to quickly

get a “feel” for the language.

>> % MATLAB comments start with a % sign >> % type 'help command' into MATLAB to get help on a particular command >> % 'ones(rows,columns)' generates a rows-by-columns matrix of 1s >> % * by itself is matrix multiplication, but .* will do elementwise multiplication >> % a semicolon at the end of a command suppresses output >> a = ones(3,1) * (9:-2:1) a = 9 7 5 3 1 9 7 5 3 1 9 7 5 3 1 >> b = (11:-2:7)' * ones(1,5) b = 11 11 11 11 11 9 9 9 9 9 7 7 7 7 7 >> c = a + b c = 20 18 16 14 12 18 16 14 12 10 16 14 12 10 8 >> d = a * b ??? Error using ==> mtimes Inner matrix dimensions must agree. >> d = a .* b d = 99 77 55 33 11 81 63 45 27 9 63 49 35 21 7 >> % compute columnwise cross product >> cross(a,b) ans = -18 -14 -10 -6 -2 36 28 20 12 4 -18 -14 -10 -6 -2 >> % compute columnwise dot product >> dot(a,b) ans = 243 189 135 81 27 >> 1 / (c + 3) ??? Error using ==> mrdivide Matrix dimensions must agree. >> 1 ./ (c + 3) ans = 0.0435 0.0476 0.0526 0.0588 0.0667 0.0476 0.0526 0.0588 0.0667 0.0769 0.0526 0.0588 0.0667 0.0769 0.0909 >> dude = [1 2 3; 5 6 7; 11 12 29] dude = 1 2 3 5 6 7 11 12 29 >> inv(dude) ans = -1.4062 0.3437 0.0625 1.0625 0.0625 -0.1250 0.0937 -0.1562 0.0625 >> dude(:,2) = [99 100 101]' dude = 1 99 3 5 100 7 11 101 29 >> dude(1:2,:) ans = 1 99 3 5 100 7 >> % most importantly for this assignment, MATLAB will also draw triangles for you! >> the image below was created via these commands: >> axis([-10 10 -10 10]) >> axis square >> % the first argument to patch consists of x coordinates, the second consists of y >> coordinates, and the third consists of an RGB triple >> patch([3 4 6],[-4 -3 -6],[1 0 0]) >> patch([1 5 9],[10 13 14],[0 1 0]) >> patch([-3 -6 -9],[1 2 5],[0 0 1]) >> patch([-1 -3 -5],[-4 -6 -7],[0.25 0.5 0.3])

You can tell MATLAB to not draw edges on the patches via

set(0,’DefaultPatchEdgeColor’,’none’) – thanks to Michael Cook (a student

from a previous year) for the tip.

If you don’t want to use MATLAB, you might try Python, Ruby,

Visual Basic, TCL, or Perl

with one of their numeric/scientific/graphical extensions; Mathematica

or Maple might also be useful. You can even use Scheme or Lisp, if you

can find one that will draw triangles.

(If you insist,

you can use a compiled language

Java or C++ or something

if you can find an appropriate matrix-manipulation library and

are

willing to lose the

interactivity of use of an interpreted language. However, you will find

that the assignment

will take much longer than necessary if you take that route.)

The main reason we are asking you to use a flat shading model instead

of Gourard shading is

that MATLAB, as far as we can tell, will only do Gourard shading

in a “colormap” sort of mode

instead of a full RGB sort of mode.

Homogeneous coordinates in computer graphics are usually represented

as row vectors,

with operations conducted by doing `row * matrix`

type operations. However, some of the “vectorized”

commands in MATLAB, such as `cross`

and `dot`

,

work better with coordinates stores along the columns; hence, you may find

it useful

to use some transposition operations (indicated using a single quote) to flip

between row and column representations as needed. Your mileage may vary.

**Philosophy:**

The instructions to this assignment are

deliberately a little bit vague – you should feel free to experiment a

bit and come

up with your own choices of parameters and implementation techniques.

For instance, how exactly

should you parameterize orientations? It’s up to you!

Here, you’re not

stuck with whatever choices an API designer made.

**Deliverables:**

Package everything needed to run your script (3D data file, program, etc.),

as well as **three
example scenes** (in any common

image format you’d like) created with your program with different

parameters to demonstrate its capabillity, and upload them

to T-square as a zip file or gzipped tar file.

**Include “HW2” and as much as possible of your full name**

in the filename, e.g., HW2_Aaron_Lanterman.zip.

in the filename, e.g., HW2_Aaron_Lanterman.zip

(The upload procedure should

be reasonably self explanatory once you log in to T-square.)

Be sure to finish

sufficiently in advance of the deadline that you will be able to work around

any troubles T-square gives you to successfully submit before the deadline.

**If you have trouble getting T-square to work, please e-mail your**

compressed file to lanterma@ece.gatech.edu, with “MPG HW #2” and your

full name in the header line; please only use this e-mail submission as a

last resort if T-square isn’t working.

compressed file to lanterma@ece.gatech.edu, with “MPG HW #2” and your

full name in the header line; please only use this e-mail submission as a

last resort if T-square isn’t working.

The midnight due date is intended to discourage people from pulling

all-nighters, which are not healthy.

**Ground rules**: You are welcome to discuss high-level implementation

issues with your fellow students, but you should avoid actually looking

at one another student’s code as whole,

and under no circumstances should you be

copying any portion of another student’s code.

However, asking another student to focus

on a *few* lines of your code discuss why a you are getting a particular

kind of error is reasonable. Basically, these “ground rules” are

intended to prevent

a student from “freeloading” off another student, even accidentally, since

they won’t get the full yummy nutritional educational goodness out of the

assignment if they do.

**Assorted notes:**

- Don’t get the ideas of “spotlight” and “specular” confused. They give

similar kind of effects but are quite different things.<!–

- A few folks have tried writing programs that use CAD files with

polygons with variable numbers of sides within the same file.

That way lies madness. You can

do the assignment with a file with, say, quadralaterals iinstead of triangles

– everything will still work (after all, the Sega Saturn GPU rasterized

quadrilaterals and not triangles) – but you can’t easily write code that will

mix and match. You want a CAD file where all the polygons have the same

number of sides. Triangles are probably the easiest to code up.–> - A good way to think about the camera transformation is to work

“backwards” – you’re essentially translating your universe of

objects, including the

camera, so the camera sits at the origin, and then rotating your universe

of objects,

including the camera, around the origin,

so that the camera lines up along with your axes. Another way to think

about it is to imagine creating the transformation of your camera as if

it were an object, and then taking the inverse of the resulting matrix. If

what I wrote here makes no sense, ignore it; it’s the way I think about it,

but you’ve probably figured out my brain is a bit strange.