CS488 - Sample Assignments

September 25, 2014, at 12:46 AMerika

Computer Graphics - Sample Assignments

Samples of assignments 0 to 2 done in CS488 in Winter 2006. This was back in the day when OpenGL didn't use shaders, graphics processors were dual at best, the latest and greatest in game engine UIs was what you could make with Gtkmm, and texture sizes had to be powers of 2. Which I didn't discover until well after that assignment was due... Read more...

Check out the descriptions on:

Assignment 0 - Simple Paint Programs

This assignment was minorly extending a paint GUI, while getting used to the Gtkmm toolkit, and setting up the account for future assignments. I extended this by including a whole slew of fun colours. :)

The assignment was fairly straightforward. I'd actually already tried it on my own some terms back when it was in python. I got stuck on figuring out how to select a default check item, but finally figured it out.

The Applications menu contains 'Clear' (to clear the screen) and 'Quit'. To familiarize ourselves with accelerator keys, all functions have hotkeys ('C', and 'Q' respectively for the functions in the appliations menu). We were restricted to drawing lines, ovals, and rectangles in the application. Which one we're currently drawing with depends on the check items of the Tools menu, which lists these 3 options. Similarly, the Colour menu sets the current colour to be using. The help menu, right justified, demonstrated how to bring up small dialogs. There's a help dialog for the 3 different drawing tools. At the bottom of the screen, there's a button, so that people who are unfamiliar with GUI's (of which most co-ops are not) can better understand widgets. Drawing occurs through mouse button events.

Assignment 1 - Simple 3D Games

We were required to implement the GUI of Tetris, while at the same time getting used to OpenGL syntax, and basic interactive methods (eg. rotation, scaling, etc). I extended this by having bevelled blocks, and creating 3D text for score keeping.

We were given a basic blue screen, and a couple of polygon triangles floating in 3-space to identify where the corners of the tetrominoes game *cough* tetris game were expected to to be located. With a quick couple of for-loops, I drew some wire frame lines to find out where all the cubes should be.

In Fine 328, I discovered that I really like to play with lights, and see how the different light influences the scene. Likely, it allows me to more easily depict whether or not something looks right. ie. If I know the shading should be correct, and it looks wrong, then something in the scene must be wrong.

This becomes particularly apparent if you've got normals facing the wrong way, and half the image is incorrectly created. So, after some trial and error, and finally getting the hang of OpenGL's counter clockwise ordering of vertices on a face, I finally got all 6 sides to a box renderable. However with the light tossed in there, it immediately looked wrong. Turns out, one needs to tell OpenGL where the normals of a face are facing, else I guess it assumes all normals face the viewer.

It'd be about this time that I added in all the functional menus.

  • File: Basic actions
    • New Game - starts up a new game
    • Reset - resets the well orientation, and stops things from spinning
    • Quit Game - duh
  • Draw: Drawing settings
    • Wireframe - just the outline. Coloured as with face colouring
    • Face - faces to the blocks. Each piece has its own unique colouring.
    • Multicoloured - faces to the blocks. Each face on each block has its own unique colouring. (No accidentally randomizing to the same colour for me)
    • Bevel - added in. Adds a bit of dimension to the otherwise flat & boring blocks
  • Lighting: Turns lighting on/off
  • Buffering: Turns double buffering on/off
  • Game: Extra features
    • Pause - suspends game play
    • Speed Up/Slow Down - adjusts block speed
    • Auto Increase - automatically increases the speed after X rows are cleared
    • Keep score - shows the current score of the game
  • 'Help: Basic help & about items.

Of course, I didn't add the game play options until after everything else was done, and I was bored. :P

Once basic lighting and blocks were in, I thought it was time to be rotating the scene. All the rotations are controlled by the mouse (game play - moving the blocks withing the game well - is controlled by the arrow keys). We were required to have some sense of 'gravity' --> if the mouse is still moving on release, then the object should keep spinning/rotating, with no change in speed over time, until the mouse stops it, or the rotations are reset. This was slightly tricky, as I needed to keep track of whether the mouse was still moving on release. I think I performed a quick hack to determine if it had zero velocity on release (ie. tracking the previously mouse motions prior to the release). This seemed to work out alright.

With the ablility to rotate, it was time to connect up the front end to the back end game engine. With a timer grabbing incrementing the game state, and the key inputs giving signals about how to affect the piece, all we had to do was render which block was in what square of the grid. No, we didn't need to adjust the logic of the game, and I didn't as I felt it was fine (though on reflectoin, I may have created a better randomization mechanism, as it always started with the same ruddy pieces each time... boring after testing tetris countless times.

With the basic face colourings in, I added in multicolouring (annoying to figure out what goo combinations of colourings would be, to ensure they're all distinct, especially with the light affecting the colours such that with the light on, sometimes the colours didn't look unique. In other words, I tried to choose unique colourings for each face. Unfortunately, with the light on, they sometimes didn't look as distinct from one another as I'd hoped. After severe tweaking, I decided it was sufficient, and moved onto more fun things. (Note: later, when I was working on my extensions, I noticed the fellow beside me, henceforth known as 'graphics boy', and significantly later descovered to be called Jason, had the most incredible multi-coloured system. Lights were rotating around, and the blocks were shimmering and the each face was itself a blend of multiple colours. At the time, I had no idea how to do that! About one or two assignments in (joint with CS798 - particularly with the isohedral tilings), I figured out how he'd done it. Not so hard to specifiy a colour at each vertex really...)

Fun things being bevelled blocks (make the blocks look more block-like). Actually, bevelling reminded me that faces have unique normals (ie. the lighting looked wrong), and a quick hack allowed for easy calculations (the use of GL_NORMALIZE, and combining the basic left/right/up/down/front/back normals of the adjacent faces to the glNormal command). Further, and finally, I spent until the early hours of the morning of the due date creating the numbers 0 - 9, and letters C, L, O, R, S, E, V in order to do some basic score keeping. 3D letters were created, as I couldn't figure out how to easily load in letters, and eventually determined it was too early in the morning to think smartly, so brute force would be the method of choice. I also added in an alpha-coloured (yeah alpha transparency stuff - just as much fun as working with lights) "start line". Twas a fun assignment I thought, and good for getting used to OpenGL.

Assignment 2 - Rastering Algorithms

This assignment we weren't allowed to use OpenGL, but were required to implement the graphics rendering pipeline - converting 3d models into world coordinates, being viewed from the camera, and displayed on the 2d screen.

This assignment turned out to be so much more fun than the profs or TAs would've anticipated. It was math, and it was graphics, and it was done fairly quickly, and without hardly any troubles, and there was fun scenes to be had at the end of it. First, we started with a really boring black X in the middle of a gray screen. We were only given a drawLine(p1, p2) command, points p1 and p2 being the 2D start and end positions, and had to use it to create our 3D rotate-able cube.

If we treat our model and world coordinates in 3D space as being a vector of size 4 (the first three entries being the x, y, and z coordinate, and the final 4th coordinate indicating whether its a point or not, we can use some fun matrices to transform the point, or the vector defined by the origin and the given point. The matrices are applied to the vectors by basic matrix multiplication, and the resulting 4D vector is the new position of the old point. Some of the basic transformations are:


Delta x, y, z being the translation along the respective axes.


Scaling values sx, sy, sz being the amount scaled along the respective axes.

Rotation: (about each of the 3 axes)

The rotation about the X axis, Y axis and Z axis respectively. Omega represents the angle of rotation. Notice that the Y axis is unique in that the negative is on the lower sin, rather than the upper sin.

Note: the order of transformation matters. Grab a nearby object, and rotate it along the x axis, and then along the y axis. If you reset it back to the original position, and then rotate along the y and then the x, you'll get a different orientation. The order of scaling and translating also matters, although in this assignment, I believe we had to ensure scaling always occured at the last (so as to prevent undesired behaviour - for example, take a forward step. If you were to scale yourself to the size of a giant and take a step, the distance covered would be much greater, although you would be performing the same action. Scaling does matter in ordering).

The perspective matrix is interesting in that it stores the depth information, while allowing us to scale the 3D point down to a 2D point, with the correct field of view angle. f and n represent the near and far planes (along the z axis, or the axis looking out from the camera). Once multplication is complete, we can still order the point with respect to its depth value. It's not necessary in this assignment, but the data is there if one wanted to draw in order of depth.

My first couple of attempts didn't quite work. One of the interesting quotes I discovered in my CS488 class was "A graphics program always has an even number of sign errors", so after a bit of testing, I discovered my signs were wrong on my perspective matrix (the above is correct, but our notes kept on having +/- to add some confusion - and I think I forgot the cot). To perform a quick sanity check, I ensured that a basic orgthographic projection (smushing the 3D flat against the camera) worked, and "borrowed" an idea from a nearby graphics-lab neighbour: namely, colouring the XYZ gnomes (gnomons is the actual term, but I feel gnome is more colourful....) with a different colour for each axis. Turns out I was upside down... (and later, backwards...)

The next obvious step was to be able to translate, rotate and scale the box, and translate and rotate the camera all within world coordinates. Easy. Further, be able to adjust the near/far plane (both of which must be constrainted to not go behind the viewer. These act as clipping mechanisms for the various lines. It's neat to see the box "consumed" by the near/far plane.), and be able to clip to the viewport.

Now, there was quite the confusion over the viewport's actual role. The assignment claimed the mouse could define the start and end point of the viewport, and we would see the box. Now, the confusion lay in: a) was drawing the viewport equivalent to re-scaling/positioning a window in a basic OS? or b) was the scene fixed to the application window, and the viewport just the region visible within the viewport constraints. Apparently the other section was extremely clear on this, however, the newsgroup, the TAs, and the general graphics lab was quite confused as to which was actually correct. In the end, I figure, the TAs accepted both solutions, and those who chose (b) got it horrendously wrong on the midterm. Now, I was fine with doing either, and had actualy implemented (a) until I was told (via classmates & later by a confused TA), that (b) was the actual aim. So I claim I was ok. I still say both are neat options.

Perhaps this is a good time for assignment specs. The only use of the keyboard was the connection with the menu hotkeys. All input was provided through the mouse. Through the Application menu, one could reset the scene (resetting the position, orientation and size of the box, position and orientation of the camera, and location of the viewport), or quit. Through the Mode menu, one could elect to rotate or translate the box or the camera/view, or scale the box, or adjust the perspective values of the view (ie. field of view angle, near and far clipping planes), or choose to reconfigure the position of the viewport (ie. drag and click to select a new visible region). The current mode as well as the near and far clipping planes were indicated on lower the status bar.

This being boring, and a box being really really boring to work with, I decided to add some additional features. The default help/about items were added. Given the gnomes could be annoying after a while, I added the ability to disable the gnomes. Oh oh! and then I noticed that a quick & easy for-loop could add in extra colouring to the surrounding region. So, I decided to pretend that our scene was really a picture on a wall, or a window into a new world, and allowed the user to switch this feature on/off. (It was then pointed out by a nearby neighbour, jokingly, that we could've skipped clipping, and just drew gray lines over the outlying region :P). An interesting thing to note is that one couldn't simply use a basic for-loop iterating over each "pixel" in the 2D plane. This resulted in a striped appearance. A quick fix was to draw lines between pixels. (ie. The drawLine command was not true pixels on the screen, but were being approximately scaled by the set-up).

And so, to finish off the extension (not completed, once again, until the wee hours of the morning of the due date), I allowed mutlple objects to be added in. Not wanting to create some adhoc picking mechanism, the Select menu allows the user to select which objects they wish to have the transformation applied to. Further, objects no longer wanted may be deleted. The Application menu was further enhanced to allow for the scene to be reset to the original layout, to add in a new box, and to add in a new mesh. I created an adhoc way of importing extremely simple .obj files (parsing information, and sample .obj files borrowed from here), and then rotating, translating and scaling them, as with the boxes. For kicks, I made a quick final scene so as to show off the full potential of the extensions.

BlogIt Side bar

Recently Written

erika: end hiding comments and categories

erika: end hiding comments and categories

Group-Specific Sidebar

Blix theme adapted by David Gilbert, powered by BlogIt