Please visit ecere.org for my current cross platform Object Oriented, GUI & hardware-accelerated 3D Graphics technology.
Ok so here it starts... with the coordinate system. You probably know that in 2-D, we usually use René Descartes's Cartesian System to identify a point on a flat surface. We use two coordinates, that we put in parentheses to refer to the point: (x, y) where x is the coordinate on the horizontal axe and y on the vertical one. In 3 dimensions, we add an axe called z, and usually we assume it represents the depth. So to represent a point in 3D, we use three numbers: (x, y, z). Different cartesian 3D systems can be used. But they are all either Left-Handed or Right-Handed. A system is Right-Handed when pointing your index in the positive Y direction and your thumb in the positive X direction, your fingers are curled toward the positive Z direction. On the other hand, (hehe) a system is Left-Handed when your fingers are curled toward the negative Z direction. Actually, you can rotate these systems in any directions and they will keep these caracteristics. In computer graphics, the typical system is the Left-Handed so we'll use it too. So for us:
What is a vector exactly? In a few words, it's a set of coordinates... But if you get into more specific details, a vector can be a lot more. Let's start with a 2D vector, of the form (x, y): so let's talk about the vector P (4,5). (Usually, we put some weird arrow with only one side on top of the P, so it looks more like a hook). We can say that the vector P represent the point (4,5), or more likely that it is an arrow pointing from the origin to the point (4,5), having a specific direction and length. By the way, when we're talking about the length of a vector (also called the module), we talk about the distance from the origin to the point, and it's noted | P |. We compute the length of a 2D vector with the formula:
| P | = sqrt( x^{2} + y^{2} )
Here's an interesting fact: In 1D (where a point is on a single axe), the square root of the square of a number corresponds to its absolute value, whence the | | symbol for the absolute value's notation.
Now let's jump to 3D vectors: our friend will be P(4, -5, 9). The length will be:
| P | = sqrt( x^{2} + y^{2} + z^{2} )
and it is represented by a point in Cartesian 3D space, or rather by an arrow pointing from the origin of the system to the point. We'll learn more about vectors when we'll talk about operations.
I'll try to make this clear and simple at first: a matrix is a
two-dimensional array of numbers Probably all matrices we'll use in this site we'll be 4
by 4. Why 4 by 4? Because we are in 3 dimension and because we need an additional
column and an additional row to make the calculations work. In 2D we would need 3x3
matrices. This means that in 3D, you have 4 numbers horizontally, and 4 vertically, 16 in
total. Look at a sample matrix:
1 | 0 | 0 | 0 |
0 | 1 | 0 | 0 |
0 | 0 | 1 | 0 |
0 | 0 | 0 | 1 |
It's called the identity matrix, because when another matrix is multipled by this one, it isn't changed in any way. Now, just for fun, here's another example of what a matrix can look like:
10 | -7 | 22 | 45 |
sin(a) | cos(a) | 34 | 32 |
-35 | 28 | 17 | 6 |
45 | -99 | 32 | 16 |
So you've found all you've read here pretty easy and are wondering when you will learn something? Or you're even asking yourself what is the link between all this information and 3D graphics? Here everything changes, you will now learn facts that are the foundation of 3D transformations and of a lot of other concepts. It's still mathematical stuff though... We'll talk about operations on Vectors and Matrices: the sum and different type of products. Let's start with the addition of two vectors:
( x_{1} , y_{1} , z_{1} ) + ( x_{2} , y_{2} , z_{2} ) = ( x_{1} + x_{2} , y_{1} + y_{2} , z_{1} + z_{2} )
Quite simple heh? Now the product of a scalar by a vector:
k · ( x, y, z ) = ( kx, ky, kz )
Now a trickier one, called the dot product, doesn't get a vector as a result: ( x_{1} , y_{1} , z_{1} ) · ( x_{2} , y_{2} , z_{2} ) = x_{1}x_{2} + y_{1}y_{2} + z_{1}z_{2} Actually, the dot product of two vectors divided by the product of their modules, corresponds to the cosine of the angle between the vectors. So:
cos (V ^ W) = V · W / ( | V |* | W | )
Note that the "^" doesn't mean exponent this time, but the angle between the
vectors! This application of the dot product can be used to compute the angle of a light
with a plane so it will be discussed in greater details in the section about Shading.
Now a very weird one, the cross product.
( x_{1} , y_{1} , z_{1} )
X ( x_{2} , y_{2} , z_{2} ) = ( y_{1}z_{2} - z_{1}y_{2}
, z_{1}x_{2} - x_{1}z_{2} , x_{1}y_{2} - y_{1}x_{2}
)
The cross product is very useful to compute the normal of a plane.
Ok, we've finished with the vectors. I'll begin with the sum of two
matrices. It's pretty straightforward and similar to the sum of two vectors, so I won't
write a big formula here. For every i which is a row in the matrices, and for every j
which is a column in the matrices, you simply add the term (i, j) of the second matrix to
the term (i, j) of the first one. I could write some big formula with weird looking big
sigma symbols but I don't want to... We'll rather move to the most important principle in
matrices, concerning 3D transformations: the product of two matrix. I will point right now
the fact that M x N * DOESN'T *
equal N x M. So here is the equation for multiplying two matrices, this time with the
sigmas. You probably won't understand anything if you don't already know the principle,
but it will get clear when you'll see the code in the tutorial about 3D transformations.
Here it is:
A 4x4 matrix multiplication formula
If A=(a_{ij})_{4x4} and B=(b_{ij})_{4x4},
then
A x B=
_{4} |
_{4} |
_{4} |
_{4} |
_{4} |
_{4} |
_{4} |
_{4} |
_{4} |
_{4} |
_{4} |
_{4} |
_{4} |
_{4} |
_{4} |
_{4} |
And if AxB=(c_{ik})_{4x4} then we can write this on one line:
c_{ik} = S_{4, j=1 }a_{ij}b_{jk}
Now you should be able to try multiplying some matrix by an identity matrix to understand how it works. Then after all these separated discussions about vectors and matrices, we's multiply them together! So here's the formula to multiply a 3D vector by a 4x4 matrix (you should already have guessed that the result will be another 3D vector), if B=(b_{ij})_{4x4}:
( a_{1}, a_{2}, a_{3} ) x B = (Sa_{i}b_{i1} + b_{4,1}, Sa_{i}b_{i2} + b_{4,2}, Sa_{i}b_{i3} + b_{4,3} )
with 3, i=1 as parameters for the sums.
That's it for the operations on vectors and matrices! It's getting harder, heh? From now on, the link between the code and the maths will be more visible, with transformations...
You've surely already seen formulas like:
t_{( tx, ty )}: ( x, y ) ==> ( x + tx, y + ty )
This was the equation of a translation in a 2D Cartesian system. Now let's check the scaling equation:
s_{( k )}: ( x, y ) ==> ( kx, ky )
Makes sense heh? A much harder one, the rotation, where trigonometry makes its entry in 3D graphics:
r( q ): ( x, y ) ==> ( x cos(q) - y sin(q), x sin(q) + y cos(q) )
These were for 2D, but in 3D they stay pretty much the same. You simply add the coordinate z and the parameter tz for the translation. For the scaling, you simply multiply z by k (or you can use three diffrent scalings for every coordinates, like in the scaling matrix below). For the rotation, you keep the same formula, let z stays the same, and it gives you the rotation around the z axis. Because two other rotations are added in 3D (around the x and y axis). I could write all this 3D transformation the same way I did in 2D, but instead we'll use a much cleaner way, (that will show you the point of all this chapter) vectors and matrices! So you have your vector ( x, y, z ) as above in 2D, and several matrices of trasformation, one for each type. Then we will multiply the matrices by the vector and the resulting vector will be pointing to the transformed point. (In the next chapter, we will multiply every matrices together, to get what we will called the global transformation matrices, then multiply it by the source vector to get the destination in only one operation!). So let's show you all these 3D transformation matrices:
1 | 0 | 0 | 0 |
0 | 1 | 0 | 0 |
0 | 0 | 1 | 0 |
tx | ty | tz | 1 |
sz | 0 | 0 | 0 |
0 | sy | 0 | 0 |
0 | 0 | sx | 0 |
0 | 0 | 0 | 1 |
1 | 0 | 0 | 0 |
0 | cos(q) | sin(q) | 0 |
0 | -sin(q) | cos(q) | 0 |
0 | 0 | 0 | 1 |
cos(q) | 0 | -sin(q) | 0 |
0 | 1 | 0 | 0 |
sin(q) | 0 | cos(q) | 0 |
0 | 0 | 0 | 1 |
cos(q) | sin(q) | 0 | 0 |
-sin(q) | cos(q) | 0 | 0 |
0 | 0 | 1 | 0 |
0 | 0 | 0 | 1 |
So this concludes the part about transformations. You can apply any transformation to a 3D point with these matrices. In the next chapter, we will implement the code for matrices, vectors and for transforming 3D points. But before moving to the coding part, I want to discuss a bit planes and normals...
A plane is a flat, infinite surface, oriented in a specific direction. You can define a plane with the famous equation:
Ax + By + Cz + D = 0
where A, B, C are what we called the normals of the plane, and D is the distance from the plane to the origin. So what is a normal? It's a vector perpendicular to a plane. We compute the normal of a plane by doing the cross products of the two edges of the plane. To define these edges, we need three points. If P_{1} is our fisrt point, P_{2} our second, and P_{3} our third, and if they are counter-clockwise, treating them as vectors we can write:
Edge_{1} = P_{1} - P_{2}
and
Edge_{2} = P_{3} - P_{2}
and then compute the normal:
Normal = Edge_{1} X Edge_{2}
What about the D component of the equation? We simply isolate D, plot the values of any of the three point in the equation, and we get it:
D = - (Ax + By + Cz)
or
D = - (A·P_{1}.x + B·P_{1}.y + C·P_{1}.z)
or even trickier:
D = - Normal · P_{1}
But to compute the A, B, C components (because sometimes, we need themselves, not the normals), you can simplify all these operations with these equations:
A = y_{1} ( z_{2} - z_{3}
) + y_{2} ( z_{3} - z_{1} ) + y_{3} ( z_{1} - z_{2}
)
B = z_{1} ( x_{2} - x_{3} ) + z_{2} ( x_{3} - x_{1}
) + z_{3} ( x_{1} - x_{2} )
C= x_{1} ( y_{2} - y_{3} ) + x_{2} ( y_{3} - y_{1}
) + x_{3} ( y_{1} - y_{2} )
D = - x_{1} ( y_{2}z_{3} - y_{3}z_{2} ) - x_{2}
( y_{3}z_{1} - y_{1}z_{3} ) - x_{3} ( y_{1}z_{2}
- y_{2}z_{1} )