PDA

View Full Version : Pixel perfect projection matrix



Phippu
07-01-2010, 03:53 AM
Hi,

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);

Dark Photon
07-01-2010, 05:19 AM
Now I want that the perspective matrix is pixel perfect too...
Please clarify what you mean by this.

Phippu
07-01-2010, 05:52 AM
Ok, I'll try to explain:-) Here's an image of the perspectivc projection I want:

http://www.philippewechsler.ch/Images/stuff/perspective.jpg

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?

Phippu
07-01-2010, 08:24 AM
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;-)

loicm
07-01-2010, 03:57 PM
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.