I'm using OpenTK and I would like to be able to render polygons and textures pixel perfect when their Z is a certain number, anywhere else in the projection doesn't matter (this is for a UI). Is there a way to set up a projection matrix that does this?
-
2possible duplicate of [Opengl pixel perfect 2D drawing](http://stackoverflow.com/questions/10040961/opengl-pixel-perfect-2d-drawing) – Nicol Bolas May 12 '13 at 19:52
-
@NicolBolas I already tried that link and it didn't answer my question. I'm asking for a way to do it, not why it isn't working. – user2225102 May 12 '13 at 19:56
1 Answers
First off, forget about that "special" Z value. When you want to draw a UI you switch to a orthographic projection, so that you can use Z for layering your graphics elements.
So the basic problem boils down to finding a orthographic projection that identity maps view space to viewport space. So let's see what OpenGL specifies about that:
If a vertex in clip coordinates is given by
xc yc zc wc
then the vertex’s normalized device coordinates are
xd xc/wc yd = yc/wc zd zc/wc
13.6.1 Controlling the Viewport
The viewport transformation is determined by the selected viewport’s width and height in pixels, px and py, respectively, and its center (ox,oy) (also in pixels).
The vertex’s window coordinates are given by
xw px·xd/2 + ox yw = py·yd/2 + oy zw (f−n)zd/2 + (n+f)/2
(…) separately for each primitive. The factor and offset applied to zdfor each viewport encoded by n and f are set using glDepthRange… (…)
So there you have it: To become pixel perfect you must find a projection that's exactly the inverse of the composition of vertex clip coordinates to vertex normalized coordinates to vertex window coordinates.
Let w = 1 then you can substitute normalized for clip vertex coordinates and hence
xw px·xc/2 + ox
yw = py·yc/2 + oy
zw (f−n)zc/2 + (n+f)/2
Since we're not interested in the z coordinate we can rewrite this slightly
xw px·xc/2 + ox px/2 0 ox xc
yw = py·yc/2 + oy = 0 py/2 oy yc
…… … … … … ……
1 1 0 0 1 1
i.e. we have changed this into a homogenous matrix transformation
v_w = V · v_c
where v_c is the vertex position after projection from eye space to clip space and where V is the viewport transformation matrix
px/2 0 ox
V = 0 py/2 oy
… … …
0 0 1
So we can rewrite this again as
v_w = V · P · v_e
We're getting close. We want that
v_w = v_e
so V·P
must be identity
I = V · P = V · V^-1
Hence we know that the projection matrix P must be the inverse of the viewport matrix
px/2 0 ox
P = inv V = inv 0 py/2 oy
… … …
0 0 1
2/px 0 -ox
= 0 2/py -oy
… … …
0 0 1
For the sake of non singularity we choose the Z row as (0,0,1,0) for vertex eye space Z in the range [0, 1]. So this is the projection matrix to use for pixel perfect mapping from eye space to glViewport(ox, oy, px, py)

- 159,371
- 13
- 185
- 298