Home | Lehre | Videos | Texte | Vorträge | Software | Person | Impressum, Datenschutzerklärung | Blog
Computing Linear Perspective Projection
Coordinate system of Direct3D: x points to the right, y points upward, z
points into the screen; the origin is at the center of the screen. This
is a left-handed system.
Situation to derive the projection equations: viewer at origin, image
plane perpendicular to z axis at distance d.
To which point on the image plane is the point (x,y,z) projected?
Intercept theorem [Strahlensatz]: It is projected to (xd/z, yd/z,d).
Hence, perspective projection needs a division by z. This cannot
be implemented using matrices as usual (i.e. as a linear mapping or an
affine mapping)
Homogeneous Coordinates
Using vectors and matrices nearly as usual would be nice. Mathematicians
found a clever workaround to implement perspective projection using matrices
and vectors: homogeneous coordinates.
-
Add a fourth dimension w to (x, y, z). If (x, y, z) represents a position,
convert it to (x, y, z, 1). If (x, y, z) represents a (genuine)
vector (i.e., direction and length), convert it to (x, y, z, 0).
-
Subject those 4D vectors to 4x4 matrices. The result will be some (x',
y', z', w').
-
To convert a position (x', y', z', w') to regular 3D coordinates, divide
by w', what yields (x'/w', y'/w', z'/w').
A large set of transformations can be implemented in this way: rotation,
scaling, perspective projection, translation (!). For instance, a translation
can be achieved through the matrix
(1 0 0 a)
(0 1 0 b)
(0 0 1 c)
(0 0 0 1).
Note that a (genuine) vector will not be affected by this matrix because
its fourth component is zero.
Transformation Matrices
Some technical preparations (to be explained later):
// create the z buffer
presentParams.AutoDepthStencilFormat = DepthFormat.D24X8;
presentParams.EnableAutoDepthStencil = true;
// generate a mesh (introduce Mesh theTeapot as a member variable and include a reference to Direct3DX)
theTeapot = new Mesh.Teapot(device)
// clear frame and depth buffer
device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.Blue, 1.0f, 0);
// show the mesh
device.RenderState.Lighting = false;
theTeapot.DrawSubset(0);
Typically, we use several coordinate frames [Koordinatensysteme] to
describe a 3D world. Direct3D offers four of them:
-
Object space: adjusted to the current 3D object
-
World space: adjusted to the whole world
-
Camera space: The camera sits at the origin. We look along its z axis
-
Normalized screen space: points to the right, y points upward, z points
inside the screen; the origin is at the center of the screen; see above.
We do not specify these frames directly, but rather specify matrices to
let Direct3D do the conversion:
-
World matrix: object space -> world space
-
View matrix: world space -> camera space
-
Projection matrix: camera space -> normalized screen space
There are some pre-built matrices to do the job:
device.Transform.World = Matrix.RotationZ(0.6f)*Matrix.Translation(0.0f, 0.0f,
1.5f);
device.Transform.View = Matrix.LookAtLH(new Vector3(0.0f, 0.0f,
-3.0f), new Vector3(), new Vector3(0.0f, 1.0f, 0.0f));
device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI/3.0f,
ClientSize.Width/(float)ClientSize.Height, 0.1f, 50.0f);
We can multiply matrices using *, which is appropriately overloaded
in Managed DirectX. (In contrast to C++ and C#, current Java does not allow
to overload operators such as + and *.) The order [Reihenfolge] is important most of
the times: For matrices, A*B and B*A are different in general. As opposed
to usual mathematics, DirectX employs row vectors, not column vectors.
Thus, products are formed with the vector on the left hand side: v*A*B*C.
This means that in the matrix product A*B*C first A is applied, then B,
then C.
The basic functionality of OpenGL concerning matrices is very similar to that of Direct3D. Here are the main differences:
-
The World and the View matrix are combined into the MODELVIEW
matrix in OpenGL.
-
z points out of the screen, thus forming a right-handed system.
-
Vectors are treated as columns, so that we form products like A*B*C*v.
Thus, in a matrix product A*B*C the matrix C is applied first, what is
somewhat counterintuitive.