Pixel perfect projection matrix


currently I have two different projection modes, orthogonal and perspectivic. The orthogonal matrix is pixel perfect, I.E if I have a Quad that has a dimension of 100x100 and it is not transformed, the rendered size of that quad will be 100x100 as well. Now I want that the perspective matrix is pixel perfect too (I need it for a 3D UI), how can I do this? Scaling seems not to be the right way :o

float ymax = _near * (float)Math.Tan(fovy * Pi180);
float ymin = -ymax;
float xmin = ymin * aspectRatio;
float xmax = ymax * aspectRatio;
Gl.Frustumf(xmin, xmax, ymin, ymax, near, far);

Gl.Orthof(Width / -2.0f, Width / 2.0f, Height / -2.0f, Height / 2.0f, near, far);

Please clarify what you mean by this.

Ok, I’ll try to explain:-) Here’s an image of the perspectivc projection I want:

Now the special thing I need. Imagine the green quad has the size 100 x 100. The red quad should represent the screen and splits the projection in two parts, the near and the far part. The target is the follwing: I want to define all models in pixel dimensions. If the model is exactly in the red plane, it should be rendered 1:1 to the screen. The projection I’m looking for is nothing else than a mix between a orthogonal and a perspective matrix. Its strange to explain, to you know what I mean?

I got it;-)

near = 1;
far = 1000;
focal = 500;

float ymax = Height/2.0f * near / focal;
float ymin = -ymax;
float xmin = ymin * aspectRatio;
float xmax = ymax * aspectRatio;
Gl.Frustumf(xmin, xmax, ymin, ymax, near, far);

An here’s what that matrix is doing:
its a normal perspective projection, but near,far and focal are measured in pixels. When the distance from the point to the camera is 500 (focal), then the point will be rendered 1:1 to the screen. A plane that is 100 x 100 and is 500 away from the camera, the plane will be rendered exactly 100 x 100 pixels.

Thanks for your help anyway;-)

Here’s the function I use to build that kind of matrix. width and height defines the 2D space available at z=0, must be the same as the size of the viewport. z_near defines the z position of the near plane, must be greater than 0. z_far defines the z position of the far plane, must be lesser than 0. z_eye defines the position of the viewer, must be greater that z_near. All the vertices placed at z=0 will now perfectly map with the pixel grid of your screen.

void MatrixPerspectivePixelPerfect(Matrix* m, float width, float height,
                       float z_eye, float z_near, float z_far) {
  const float kdn = z_eye - z_near;
  const float kdf = z_eye - z_far;
  const float ksz = - (kdf + kdn) / (kdf - kdn);
  const float ktz = - (2.0f * kdn * kdf) / (kdf - kdn);
  VectorSet(&m->v0, (2.0f * z_eye) / width, 0.0f, 0.0f, 0.0f);
  VectorSet(&m->v1, 0.0f, (2.0f * z_eye) / height, 0.0f, 0.0f);
  VectorSet(&m->v2, 0.0f, 0.0f, ktz - ksz * z_eye, -1.0f);
  VectorSet(&m->v3, 0.0f, 0.0f, ksz, z_eye);

Note that you’ll need to transpose the matrix before sending it to OpenGL.