March 4th 2015, Software Rendering Pipeline

March 3rd 2015 Track Rendering Engine | | March 4th 2015 Homogeneous Clip Coordinates

For calculating the perspective projection of the 3D point vectors we define the matrices $M_V$ and $M_P$ as follows:

$ M_V = M_R M_T $ with

  • $ M_R = \left( \begin{array}{c c c c} r_x & u_x & -d_x & 0 \\ r_y & u_y & -d_y & 0 \\ r_z & u_z & -d_z & 0 \\ 0 & 0 & 0 & 1 \end{array} \right) $
    • $\vec{r}$ being the x-axis of the camera coordinate system (right vector)
    • $\vec{u}$ being the y-axis of the camera coordinate system (up vector)
    • $\vec{d}$ being the z-axis of the camera coordinate system (direction vector)
    • by convention, the camera is looking in the direction of the negative z-axis
  • $ M_T = \left( \begin{array}{c c c c} 1 & 0 & 0 & -e_x \\ 0 & 1 & 0 & -e_y \\ 0 & 0 & 1 & -e_z \\ 0 & 0 & 0 & 1 \end{array} \right) $
    • $\vec{e}$ being the position of the camera in world coordinates (eye point)
  • $ M_P = \left( \begin{array}{c c c c} c/a & 0 & 0 & 0 \\ 0 & c & 0 & 0 \\ 0 & 0 & -\frac{n+f}{f-n} & -2\frac{fn}{f-n} \\ 0 & 0 & -1 & 0 \end{array} \right) $
    • $c = \frac{1}{tan(fovy/2)}$ (fovy cathetus)
    • $fovy$ = field of view in y-direction (vertical viewing angle of the camera)
    • $a = \frac{w}{h}$ (window aspect)
    • $w$ = window width
    • $h$ = window height
    • $n$ = distance of near plane
    • $f$ = distance of far plane

To implement the above calculations, we use the glslmath C++ library, which provides linear math operators for 4×4 matrices and 4-component vectors using homogeneous coordinates. It also provides convenience methods for the calculation of the above transformation and projection matrices:

As an example, we transform a single point $\vec{p}=(0,0,-10)^T$ into the camera coordinate system with the camera positioned at the eye point $\vec{e}=(0,10,10)^T$ looking at the point $\vec{l}=(0,0,0)^T$ with the up vector $\vec{u}=(0,1,0)^T$ and the perspective projection with a near plane distance of $n=1$, a far plane distance of $f=100$ and a vertical viewing angle of $fovy$=90 degrees. Additionally, we transform the point with an affine modelling transformation, which translates the point up 10 units with a translation vector of $\vec{t}=(0,10,0)^T$.

#include <glslmath.h>

vec4 p(0,0,-10);
vec3 t(0,10,0);

mat4 M = mat4::translate(t);

vec3 e(0,10,10);
vec3 l(0,0,0);
vec3 u(0,1,0);

mat4 V = mat4::lookat(e,l,u);

double fovy=90.0;
double aspect=1.0; // for a quadratic viewing window
double n=1.0;
double f=100.0;

mat4 P = mat4::perspective(fovy,aspect,n,f);

mat4 MVP = P*V*M;
p = MVP*p;

std::cout << "projected vertex: " << vec3(p) << std::endl;

The output of the projected vertex is given in normalized device coordinates in the range $ [-1,1]^3 $, so the coordinates need to be scaled up to integer window coordinates, if the point is to be painted as a pixel on the rendering window.

In this example the projected point is visible at position $(0,1)^T$ on the image plane, that is the top center of the window.

More precisely, the projected point is a 4-component homogeneous vector which is cast to a 3-component vector undergoing dehomogenization by dividing it by its w-component. Although being projected onto the 2D image plane, the resulting 3-component vector has a z-coordinate, which is interpreted as the depth of the point.

The z-coordinate is usually inspected by the Z-buffer algorithm for hidden surface removal. In this simplified rendering pipeline, we are simply going to neglect the z-values. They do not play a role, if we just render points and lines and no other graphic primitives like triangles.

Q But what if we turn our head so that the point becomes invisible?

We need to clip the a point at the viewing frustum (the visible volume, which is a pyramid frustum) in homogeneous clip coordinates!

March 3rd 2015 Track Rendering Engine | | March 4th 2015 Homogeneous Clip Coordinates