Points are transformed using
or one of the other transformation functions, the
world_coordinates are not modified directly. Instead,
another data member of
class Point is used to store the
information about the transformation, namely
class Transform. A
Transform object has a single
data element of type
Matrix and a number of member functions. A
4 X 4
typedef real Matrix.
Such a matrix suffices for performing all
of the transformations (affine and perspective) possible in
Any combination of transformations can be represented by a single
transformation matrix. This means that consecutive transformations
Point can be "saved up" and applied to its coordinates
all at once when needed, rather than updating them for each
Transforms work by performing matrix multiplication of
Matrix with the homogeneous
If a set of homogeneous coordinates
\alpha = (x, y, z, w)
then the set of homogeneous coordinates \beta resulting from multiplying \alpha and M is calculated as follows:
Matrix M= a e i m b f j n c g k o d h l p
\beta = \alpha\times M = ((xa + yb + zc + wd), (xe + yf + zg + wh), (xi + yj + zk + wl), (xm + yn + zo + wp))Please note that each coordinate of \beta can be influenced by all of the coordinates of \alpha.
Operations on matrices are very important in computer graphics applications and are described in many books about computer graphics and geometry. For 3DLDF, I've mostly used Huw Jones' Computer Graphics through Key Mathematics and David Salomon's Computer Graphics and Geometric Modeling.
It is often useful to declare and use
Transform objects in 3DLDF,
just as it is for
transforms in Metafont. Transformations can be
Transforms and then be used to transform
by means of
1. Transform t; 2. t.shift(0, 1); 3. Point p(1, 0, 0); 4. p *= t; 5. p.show("p:"); -| p: (1, 1, 0)
Transform is declared (line 1), it is
initialized to an identity matrix. All identity matrices are
square, all of the elements of the main diagonal (upper left to lower
right) are 1, and all of the other elements are 0.
4 X 4
identity matrix, as used in 3DLDF, looks like this:
1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1If a matrix A is multiplied with an identity matrix I, the result is identical to A, i.e., A * I = A. This is the salient property of an identity matrix.
The same affine transformations are applied in the same way to
Transforms as they are to
Points, i.e., the functions
correspond to the
versions of these functions, and they take the same arguments:
Point p; Transform t; p.shift(3, 4, 5); t.shift(3, 4, 5); => p.transform == t p.show_transform("p:"); -| p: Transform: 0 0.707 0.707 0 -0.866 0.354 -0.354 0 -0.5 -0.612 0.612 0 0 0 0 1 t.show("t:"); -| t: 0 0.707 0.707 0 -0.866 0.354 -0.354 0 -0.5 -0.612 0.612 0 0 0 0 1
It is unfortunate that the terms ``array'', ``matrix'', and ``vector'' have different meanings in C++ and in normal mathematical usage. However, in practice, these discrepancies turn out not to cause many problems. Stroustrup, The C++ Programming Language, section 22.4, p. 662.
In fact, none of the operations for transformations require all of the elements of a 4 X 4 matrix. In many 3D graphics programs, the matrix operations are modified to use smaller transformation matrices, which reduces the storage requirements of the program. This is a bit tricky, because the affine transformations and the perspective transformation use different elements of the matrix. I consider that the risk of something going wrong, possibly producing hard-to-find bugs, outweighs any benefits from saving memory (which is usually no longer at a premium, anyway). In addition, there may be some interesting non-affine transformations that would be worth implementing. Therefore, I've decided to use full 4 X 4 matrices in 3DLDF.