disckitty.ca/gallery/code/cs488

CS488 - Assignment 2


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:

Translation:

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

Scaling:

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.

Last Updated: January 14, 2008 - 12:46 AM (pro) (wood) (c) disckitty.ca