1 2 3 4 5 6 7
Setting up your Compiler Our Generic Windows Skeleton A Simple Cube Matrices Wazoo of Borg FullScreen Ahead Mr. Crusher On screen. Magnify.

 

 

 

Tutorial #4: Matrices
Erik Yuzwa


Ahoy mateys! I remembered that I promised back in Tutorial #1, to explain what the deal is with Matrices and how Direct3D uses them...

Our FIRST thing that we have to explain pronto, is the concept of the Left-Handed Coordinate System and the Right-Handed Coordinate System. This is one basic difference between OpenGL and Direct3D. In both coordinate systems, the X and Y axis are as normal. The Y positive axis going upwards and the X positive axis going to the right. However, the two systems differ in their Z-axis implementation. A Left-Handed System, which Direct3D uses, is one where the Z-axis is positive INTO the screen. Take your Left Hand, face the palm upwards with your fingers pointing in the direction of the positive x-axis (to the right), and curl your fingers in the direction of the Y-positive axis (up). Now if you stick your thumb STRAIGHT (like you were giving a sideways "thumbs-up" sign), your thumb is now pointing in the direction of the positive Z-axis.
OpenGL, on the other hand, uses a Right-Handed system, where the positive Z-axis is coming OUT of the screen. Again, to remember this, take your right hand, point your palm upwards and your fingers pointing in the direction of the positive x-axis (to the right). Now curl your fingers up to the direction of the positive y-axis (up), and point your thumb out. It is now pointing in the direction of the positive Z-axis (out)..

Now before we render our primitives from what we code to the screen, our vertex information goes through what's called the Geometry Pipeline. Basically, the Geometry Pipeline is a conversion process our vertices go through from what's called Model Coordinate to rasterization..
Okay perhaps for ease of explanation, we can follow our cube example from the previous tutorial to demonstrate what's going on in the Pipeline...

Step 1: Model Coordinates This is our vertex starting point. This is where our model (in our case, our Cube) is modelled in a local coordinate system. This means that if our cube was the ONLY object in our scene, then this is our vertex information. No real matrix transformation happens here we just have to realize that our coordinates are in a Model Coordinate system.

Cube: { 0.0f, 0.0f, 0.0f, D3DCOLOR_RGBA(255, 0, 0, 255), }, //vertex 0
      { 0.0f, 1.0f, 0.0f, D3DCOLOR_RGBA(255, 255, 0, 255), }, //vertex 1
      { 1.0f, 0.0f, 0.0f, D3DCOLOR_RGBA(255, 0, 0, 255), }, //vertex 2
      { 1.0f, 1.0f, 0.0f, D3DCOLOR_RGBA(0, 0, 255, 255), }, //vertex 3
      { 1.0f, 0.0f, 1.0f, D3DCOLOR_RGBA(255, 255, 255, 255), }, //vertex 4
      { 1.0f, 1.0f, 1.0f, D3DCOLOR_RGBA(255, 0, 0, 255), }, //vertex 5
      { 0.0f, 0.0f, 1.0f, D3DCOLOR_RGBA(0, 0, 0, 255), }, //vertex 6
      { 0.0f, 1.0f, 1.0f, D3DCOLOR_RGBA(255, 0, 0, 255), } //vertex 7

Step 2: World Transformation Okay, this is where our magic begins. The World Transformation is responsible for converting our model's vertices from it's Model Coordinates, into the scene that ALL of our primitives are rendered in (ie. our World)..this is where Matrices really start to come into play as we are playing around with various operations more suited for Matrix representation.
In a bare-bones nutshell, matrices are grids of numbers that represent a system of mathematical equations.. (remember all that 2x+3y+4z=0 stuff back in Algebra class??? Didn't think you'd ever use it in real life?? Surprise!)
There are many fine sites on matrices all over the internet, so I won't reinvent the wheel too much. We just have to know basic multiplication and addition and we're rockin'.

Matrix Multiplication Matrices are represented in an MxN form where M is the number of rows and N is the number of columns. So a 2x3 matrix has 2 rows and 3 columns. Now, matrices can ONLY be multiplied together should the number of columns of A equals the number of rows of B. (ie. A = 2x3 matrix and B = 3x4 matrix. Notice that the columns of A (3) is equal to the rows of B (3) so we are able to multiply A with B..)

Note: ALL of our matrices in Direct3D and OpenGL are 4x4, so we can multiply any matrix in either graphical system..

We'll do a simple multiplication here just to give you an idea:
| 1 2 |         | 5 6 |
| 3 4 |    X    | 7 8 |
Matrix A        Matrix B

Okay so A is a 2x2 matrix and so is B, therefore we are able to multiply them together. The general order of multiplication of matrices is to multiply the each item in the row of A with each item in the column of B. We will use the standard representation as follows: A(1,1) is the same thing as the value of the element at Row 1 Column 1 in Matrix A.
| 1 2 |       |5 6|  = |(1*5)+(2*7)  (1*6)+(2*8)|         |19 22|
| 3 4 |   X   |7 8|    |(3*5)+(4*7)  (3*6)+(4*8)|     =   |33 42|

Simple right? The bigger matrices follow the same rules, so it looks ugly but it is in fact very simple

To modify any vertex, we can do 3 things: translate it, scale it, or rotate it.
Translate: This is just translating our vertex to another point in our coordinate system. the translation matrix looks as follows:
|1 0 0 0 |
|0 1 0 0 |
|0 0 1 0 |
|x y z 1 |

We'll go through some examples in minute, after I explain the other two matrix types..
Scaling: Even easier than Translation is Scaling. This allows us to scale our vertex in magnitude by any value we wish. For example, to increase or decrease the size of a polygon, we can use a scaling matrix
| x 0 0 0 |
| 0 y 0 0 |
| 0 0 z 0 |
| 0 0 0 1 |

The last type of matrix operation we can perform is of course Rotation. This allows us to rotate our vertex/primitive by a certain amount of radians on whichever axis we want.
This is a rotation matrix around the x-axis looks like:
| 1   0     0   0 |
| 0 cosW  sinW  0 |
| 0 -sinW cosW  0 |

where W is our angle in radians

Once we start playing around with matrices, however, you'll soon discover that there's one matrix operation that you would really like to be able to use. That is, the rotation of a point around an arbitrary axis. I used to know how to do it long ago, but my neural pathways sometimes aren't as strong as they used to be..<grin>..but, Vincent Delannoy was kind enough to send me a matrix he's used many times:
| (1-cos(angle))x^2+cos(angle)  (1-cos(angle))xy-(sin(angle))z  (1-cos(angle))xz+(sin(angle))y  0|
| (1-cos(angle))xy+(sin(angle))z  (1-cos(angle))y^2+cos(angle)  (1-cos(angle))yz-(sin(angle))x  0|
| (1-cos(angle))xz-(sin(angle))y  (1-cos(angle))yz+sin(angle)x  (1-cos(angle))z^2+(cos(angle))  0|
| 0                                         0                               0                   1|

where :
  - angle is the angle of rotation in radians
  - (x, y, z) is a unit vector on the axis of rotation


Okay I KNOW that this is a very quick and not too detailed look into matrices, I'm just trying to include a very small primer in order to understand what Direct3D is doing. If you'd like more information on matrices, either contact me and I'll add some more depth to this tutorial, or peruse a Linear Algebra book which has all your matrix answers (without glossy photos of Keanuu Reeves)

SO back to World Transformation, as stated above, this is the process by which Direct3D converts our model coordinates into World Coordinates. Continuing our Cube example, this is where we position our Cube in the scene.

Step 3: View Transformation:
Okay, now that we know our model's vertices in our Model Coordinates, and now that we've placed our Model in our scene via the World Transformation, it's time to decide WHERE we're viewing our World from. This is where the View Transformation comes into play. We ultimately decide where we want to place our camera/viewpoint of the scene.
So for our Cube, we decided to move our viewpoint 5 units behind the center of the world coordinate system, up three units, and we're "looking" at the center point of the scene (0,0,0).

Step 4: Projection Transformation:
Okay we know our primitives Model Coordinates, we've placed it in a scene, and we've plunked a camera or viewpoint into our scene. Now in this stage of the Direct3D Geometry pipeline, we must render our view to give us some sort of feel of depth. Ie. primitives in the background appear smaller and are overlapped by primitives in the foreground which appear larger. Pretend YOU are viewing the scene personally. This is what the Projection Transformation offers us..a way to render the scene with some depth.
Continuing with our Cube example, we defined a perspective field of view to stretch from 1.0 all the way back to 100.0 (meaning our depth is 100 units).
Step 5: Clipping:
I've included this for completeness, but clipping of our scene is mostly handled by Direct3D. I say mostly, as you CAN (I believe) write your own clipping routines, but for now, Direct3D is capable of handling this. During this last stage of the Geometry Pipeline, primitives which are obscured from view of the camera are removed from the scene, thereby decreasing the amount of time it takes to render our scene. This is where all the hidden surface removal algorithms come into play.

And that's really about it....
That was a wild and crazy tour through the Geometry Pipeline of Direct3D8, and I've tried to include a small matrix primer...HOPEFULLY these explanations make it easier to understand... I've found that with this pipeline, it took me a while to figure out what was going on, but then suddenly the proverbial "light bulb" came on in my head and it all made sense...funny how that happens right?? Well hopefully the way I understand it and explain enables others to experience the same enlightenment that I went through..

Again, any feedback on this page would be taken into consideration...

Thanks for joining us, and don't hesitate to move onto Tutorial #3...hehe

Return To Index

 


 

[top]

 
 
© 2003, Silver.
Wind, two Tears, and a Funeral...