As a kid, did you ever take something apart just to see how it worked? I still remember taking apart my old Apple ][ just to see if I could get it back together. The integrated circuits sat on sockets, so you could easily pry them off with a small screw driver. It was an interesting exercise in seeing how computer hardware functions.
It's been several decades since I last dismantled an Apple ][, but I still find myself taking things apart just to satisfy my curiosity. I don't take apart computers that much anymore. I mean, where's the fun in taking apart a laptop? Eeek!
My interest has shifted to old game software autopsies. Old popular video game source code can be found everywhere on the net. Not only that, but game console development environments are becoming available to the hobbyist. Development environments exist on Linux for the GameCube (see also Linux on the GameCube, the Sony PlayStation 2, and the old Sega Dreamcast console). These game console platforms have some interesting homebrewed 3D demos for them on the internet. These incredible hobbyist efforts sparked my interest in reverse engineering 3D graphics for the game console environment. In some cases, excluding the PlayStation 2, the Linux environments don't support the OpenGL API. Which means coding 3D from scratch is necessary.
Related Reading Game Design Complete 
Do you need any of these development environments to experiment with game console 3D programming? Certainly not. I am surrounded by computers at work and at home; Macintosh, PC, Sun, and SGI. Despite the differences in hardware and software on all of these systems, they all have a nice little scripting language, Tcl, which is more than capable of stepping up to the task. Using Tcl, you can literally prototype algorithms in the interpreter much in the same way you would prototype an electronics circuit on an experimenter's breadboard. In our case, we're going to assemble a game console to experiment with using Tcl. Pretty cool, huh?
Sometimes the internet can be overwhelming in information. My initial Googling for 3D game and programming graphics yielded a lot of pages that were, in a nutshell, a rehash of college students' lectures in linear algebra and vectors, typically followed with an objectoriented coding example of a spinning cube with light sources. Have fun dissecting that code!
Relying on my ancient knowledge of 3D computer graphics, which is in an eroding data buffer in my mind, I recollected the basics of the 3D graphics pipeline. Why is this information important? Understanding the linear algebra involved is one thing; the order of implementation of the matrices is the other half of the equation. Most website tutorials make you dig this out of the complex source code that accompanies the lengthy discourse on linear algebra. As the physicist Richard Feynman used to say, Q.E.D., right? In my earlier years of college I would have prided myself in deriving the solution. Fast forward 20 years later, and my attitude has shifted to "just show me the solution." Let's take a look at a solution to a simple 3D graphics pipeline.
The object we're going to render exists in a fictitious 3D world. Objects in our world are mapped to x, y, and z coordinates. For simplicity, we're going to render a polygon to our Tcl game console. The three vertices of the polygon are defined in world coordinates as follows:
set vertex_list { \
{0.57735026919 0.57735026919 0.57735026919} \
{0.57735026919 0.57735026919 0.57735026919} \
{0.57735026919 0.57735026919 0.57735026919} }
Our polygon is a triangle, which is one face of a tetrahedron, a threesided pyramid. We're only going to render one face, as shown in Figure 1, to keep it simple.
Figure 1. Wish output display of polygon

This is the stuff lengthy, boring, game tutorial web pages are made of. I'll spare you and just point out where we're going to perform the linear algebra transformations to display the polygon on our Tcl game console.
Figure 2. Arbitrary rotation matrix
Figure 2. shows us our arbitrary rotation matrix. If you just want to rotate your polygon around the x axis, you adjust the alpha angle value, in radians. If you want to perform a rotation about the x, y, and z axes, then you must input the alpha, theta, and phi angle values in radians. The arbitrary rotation matrix is a linear algebra concatenation of all three transformation matrices into one universal matrix.
proc create_rotation_matrix_R { alpha theta
phi } {
# calculate the trig identities
set sin_alpha [expr {sin($alpha)}]
set cos_alpha [expr {cos($alpha)}]
set sin_theta [expr {sin($theta)}]
set cos_theta [expr {cos($theta)}]
set sin_phi [expr {sin($phi)}]
set cos_phi [expr {cos($phi)}]
# Eq 3.2 Rx, RealTime Rendering, Moller & Haines
set Rx { \
{1 0 0 0} \
{0 0 0 0} \
{0 0 0 0} \
{0 0 0 1}\
}
# set the Rx matrix components
lset Rx 1 1 $cos_alpha
lset Rx 1 2 $sin_alpha
lset Rx 2 1 [expr {1*$sin_alpha}]
lset Rx 2 2 $cos_alpha
# Eq 3.3 Rx, RealTime Rendering, Moller & Haines
set Ry { \
{0 0 0 0} \
{0 1 0 0} \
{0 0 0 0} \
{0 0 0 1} \
}
lset Ry 0 0 $cos_theta
lset Ry 0 2 [expr {1*$sin_theta}]
lset Ry 2 0 $sin_theta
lset Ry 2 2 $cos_theta
# Eq 3.4 Rx, RealTime Rendering, Moller & Haines
set Rz { \
{0 0 0 0} \
{0 0 0 0} \
{0 0 1 0} \
{0 0 0 1} \
}
lset Rz 0 0 $cos_phi
lset Rz 0 1 $sin_phi
lset Rz 1 0 [expr {1*$sin_phi}]
lset Rz 1 1 $cos_phi
return [matrix_multiply [matrix_multiply $Rx $Ry] $Rz]
}
You'll notice in the comments I mention the RealTime Rendering text, by Moller and Haines. This was my source of information for the linear algebra equations. As a side note, this is a great book; the second edition is available for over $60. I picked up my first edition off of eBay for $0.99.
The arbitrary rotation matrix procedure, create_rotation_matrix_R,
calls
the procedure matrix_multiply
. This is a straightforward matrix multiply that is
covered in all highschool algebra 2 and college linear algebra text books.

The last component of our simple 3D pipeline is the 2D projection to our game
console viewport. The procedure create_rotation_matrix_R
returns a matrix, R,
that represents the current transformed orientation of our polygon in world
coordinates. Now we must pass in the vertices of the polygon and calculate the
new x', y', and z' values.
The x', y', and z' values represent the vertex points in the orientation in which we would like to draw them on the game console. Now we need to project the 3D world coordinates onto the 2D game console viewport. Interestingly enough, most game tutorial sites spend a lot of character bytes on explaining the arbitrary matrix rotation described above, and mention nothing about the projection matrix.
For our projection transformation, we're going to pass in the matrix R
we
created with the arbitrary rotation procedure. In the back of your mind just
remember this: R
=P
. This is what the projection procedure looks
like:
proc gc_projection { x y z d P } {
global gc_width
global gc_height
set xprime \
[expr {[lindex $P 0 0]*$x+\
[lindex $P 1 0]*$y+[lindex $P 2
0]*$z}]
set yprime \
[expr {[lindex $P 0 1]*$x+\
[lindex $P 1 1]*$y+[lindex $P 2
1]*$z}]
set zprime\
[expr \
{([lindex $P 0 2]*$x+\
[lindex $P 1 2]*$y+[lindex $P 2 2]*$z
+ 10)}]
set aspect_ratio [expr $gc_width / $gc_height]
set xp [expr ($gc_width / 2) + ($xprime * $d / $zprime)]
set yp [expr ($gc_height /2 ) + \
($aspect_ratio * $yprime * $d / $zprime)]
return [list $xp $yp]
}
The aspect ratio is the ratio of the game console's width in pixels, divided by the game console's height in pixels. The projection and aspect ratio equations are covered in the book 3D Math Primer for Graphics and Game Development, by Fletcher Dunn.
The following lines of code convert the polygon from world coordinates to game console (viewport) coordinates.
set R [create_rotation_matrix_R $theta_Rx $theta_Ry
$theta_Rz]
set d 2000
set display_list {}
foreach vertex $vertex_list {
set x [lindex $vertex 0]
set y [lindex $vertex 1]
set z [lindex $vertex 2]
set screen_data [gc_projection $x $y $z $d $R]
puts "screen data($screen_data)"
lappend display_list $screen_data
}
This code creates a display list of 2D game console coordinates that represents the polygon points, projected to 2D, that we want to render. That's it! Pretty simple pipeline for learning 3D.
We are now able to prototype gamegraphics algorithms on any computer system that runs Tcl. Tcl is a great tool for playing with graphics algorithms. You can test an idea on the fly, or examine and debug values in the interpreter. Once you get a handle on the algorithm, you can go code it in C or C++. At work, I can use my Sun workstation, and when I get home, I usually do my work exclusively on my PowerBook. For compatibility, I will SSH into my SGI from my PowerBook. The code works on all the above platforms.
The pipeline should be simple enough to expand upon. Add a 3D object, such as a cube, using polygons, or finish the code to display a threesided pyramid. Rotate the objects and add a light source. And by all meanshave fun!
Michael J. Norton is a software engineer at Cisco Systems.
Return to the Mac DevCenter
Copyright © 2009 O'Reilly Media, Inc.