k*(X, Y, Z) = (kX, kY, kZ)If we define the origin as the location of the camera, we can use this formula and take 1/z as k. Now the z coordinate is a constant:
1/Z * (X, Y, Z) = (X/Z, Y/Z, 1).This kind of points lie on the plane z=1. If we want our plane to be closer / farther, we can change the formula a bit:
a/Z * (X, Y, Z) = (X*a/Z, Y*a/Z, a)(Using a actually affects the perspective.) Now the equation of the projection plane is z=a,
Note! If z reaches somehow the value zero, the program naturally crashes (division by zero). Be careful!
Example: Visualizing three dimensions with a pseudo code (plots a pixel to the center of the screen. When the z value changes, it vanishes from the screen):
Let's take an airplane as an example (yeah, straight from otmmatx.doc :) The original orientation of the plane is as follows: the nose points to the direction of the z-axis, the right wing to the direction of the x-axis, and the y-axis pointing to the 'up' direction of the plane. Rotate the plane about the y-axis so that the nose points to the direction of the negative x-axis. Now when you rotate it about z-axis, does it turn around its own z-axis or the space's z-axis? It should turn around its own axis (or how could you implement a flight simulator otherwise?), but with basic rotations this is not what happens. So matrices are used.
In 3D coding, we use 4x4 matrices in which the data is located as follows:
It would maybe be better to format the object matrix always so that the object lies (as in the plane example) on the xz plane, so it is naturally a unit matrix (see 1.2.1). Now the unit vectors of the object's axes are i, j, and k, the same as the vectors of the world axes.
(Nearly) all 3D operations in matrix technique are done using matrix math.
About the x-axis:
We can of course precalculate a bit (just basic matrix multiplying):
So we get the rotated object matrix O from the formula
U = n*n(t) + cos(a)*(I-n*n(t)) + sin(a)*N(x).
Note! Remember to normalize the object matrices after some frames! The formula requires so much float math the object matrices tend to 'bend' very quickly. Using doubles, I myself need to normalize them about every tenth frame.
Note! Remember to transform vertices with the O' matrix and normals with the O matrix (otherwise the light sources are rotated also when the camera is rotated).
There are good camera routines (including camera moving) in the source code, go check 'em out!
Ok. This has been The Big Question for many 3D coders. I was also interested in the topic so much, I derived a 'nice' complicated and hard-to-use way of doing the thing on a maths class in about three hours. Right after I had finished, the guy sitting next to me, Jussi Vainionpaa, asked innocently, "wouldn't this be a bit more useful way?" I went through the system he had derived in five minutes, and came to the decision that not only his way was much more elegant, but it also worked better X) So here's the technique developed by Jussi Vainionpaa. Based on straightforward vector algebra.
Deriving a rotation matrix for the camera from a single vector to whose
direction the camera is pointing (z = camera forward, y =
camera down, j = world down, (j dot z)*z = the
projection of j on z):
y = j - (j dot z)*z.(vector projection, see 1.1.6). The formula is very straightforward and can be derived straight from the situation in the picture. It even shrinks due to the speciality of j:
x = yxz.The x vector needen't to be normalized if y and z already were unit vectors. Now we place the vectors to the camera matrix as in the chapter 2.2 and the camera matrix is ready.
Note that if the camera z-axis is equal to the y-axis of the world (or its opposite or even roughly equal to it), you get (0,0,0) as the camera y-axis vector. The solution to this problem is to perform a compare and if needed, to use the world z- or x-axis instead. Thanks to Arho Huttunen who noticed this first.
Another point by the same dude: if you're reading your camera from a .3DS, you'll also need rotate the y vector you've got
bankdegrees in order to get the exact orientation (
bankis a constant which can be read from the 3DS file).
B-splines are actually not lines but curves (ok, clever). They are used
to find a nice way through or near a specified list of key points for
example to smoothen camera movement. A B-spline looks like this:
A B-spline is constructed using arcs. If we want to form a
B-spline using n arcs, we need n+3 key points, let them be
c(0),c(1),...,c(n+2). The k:th arc (k = 1,2,...,n) of the
B-spline is calculated from the formula
A piece of pseudo that I used to create the picture above:
Pseudo example (rotating a point around all the three axes with the matrix
technique):
Have you ever thought how in the world are implemented games where vector-based human-like objects move nicely (Tomb Raiders, Quakes, ...)? The thing is done with hierarchical transformations.
Let's take a human arm as an example. When you move your arm from the shoulder, the whole arm moves: wrist, palm, fingers, everything. If you move just your wrist, the arm is not moved above it but palm and fingers are. The different parts of an arm are thus hierarchically dependent on each other: the palm can command the fingers but not the wrist; it's located between them in the hierarchical order. With the same method we can create a linked list of all parts of the body. In hierarchical systems, an object is thus divided to parts, and different parts are dependent on other parts. But how to implement this?
Let's continue with the arm example. The wrist matrix is called R
(the Finnish acronym for a wrist), the palm matrix K and finger
matrices S1, S2, S3, S4, and S5. They're
located in the linked list as follows:
R = R*XYZr.The palm must be rotated not only with its own rotation matrix but also with the formula above,
S? = S?*XYZs?*K.Note! To use these formulas, the preceding matrix should be already transformed, so the calculating order is in the linked list from top to bottom.
We use vertex normals to calculate the amount of light hitting a surface. So, why bother rotating these all using the object matrix when we can achieve the same result by rotating the light(s) to the opposite direction? Think about it: you've got a cube (located in the origin) rotated 90 degrees about the y-axis, and a light source in the negative z-axis infinity pointing towards the positive z-axis. The most brightness is now got by the side that was originally facing the positive x-axis (but currently facing the negative z-axis). If we rotate the light -90 degrees, we get the light pointing towards the negative x-axis and the highest amount of light hits the same side as when rotating the vertex normals 90 degrees. So it seems to work. :)
Nice, but how to implement it? Pas de problem: find the inverse of the object matrix, transform the light by it and voila! Since object matrices are always orthogonal (see the matrix stuff in the 1 part of the doc), we can use the transpose as the inverse.
Hmm... Maybe a small picture clarifies the case a bit :)
Ok, that's it. Just GO USE 'EM! :)