|
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] |
|
|