The way UV coordinates are used to address pixels in a texture is not always the same as the way NDC values are used to address pixels on the screen. I believe DirectX 11 finally made these two addressing modes consistent so the interval [-1, 1] addresses pixels on screen in the exact same way the interval [0, 1] addresses pixels in an identically sized texture. I'm not sure what iteration of OpenGL fixed this inconsistency if it happened at all.
In a sensible API (DX10 / DX11 / GL), texture coordinates and screen coordinates should work the same way, except that NDC is from [-1,1] and textures from [0,1]
uv = ndc * 0.5 + 0.5;
pixel_Index = clamp( round(uv * num_Pixels - 0.5), 0, num_Pixels-1 );
On D3D9, the definition of pixel coordinates is stupidly shifted so that the centre of the top-left pixel lines up perfectly with the top-left edge of the screen. i.e. all the pixels are shifted by half a pixel in that direction, so you need:
uv = ndc * 0.5 + 0.5 + 0.5/num_Pixels;
GL's only stupidity in this regard is that z also ranges from -1 to +1, instead of from 0 to 1, which has no impact in this situation
Also, is this even a feasible scenario? I'm coding the coordinate positioning of a bunch of objects and I want to add this option so I can, for example, do something like positioning a player's menu bar at the pixel 10 of the screen, and his inventory icon at the (width - 10).
Ignoring projection matrices, the screen is addressed in NDC (normalized device coordinates), which range from -1 to 1.
i.e. a vertex at x=-1 will be on the left hand edge of the screen, and a vertex at x=1 will be on the right hand edge of the screen.
Say the screen is 1280 pixels wide -- that's pixel #0 to pixel #1279.
The left edge of pixel #0 corresponds to an NDC value of -1. The right edge of pixel #1279 corresponds to an NDC value of -1 (this is also the left edge of imaginary pixel #1280).
If you want a shape to cover the pixels from #10 to #20, first calculate the size of a pixel. NDC is 2 units across, but our "pixel" coordinates are 1280 units across. Therefore one pixel is 2/1280 NDC units wide.
The left edge is -1, and we want to the coordinates to a point 10 pixels right of that, and then another 10 pixels right.
p1 = -1 + 2/1280 * 10
p2 = -1 + 2/1280 * 20
If you use an ortho matrix, it will just be doing this translation (by -1) and scaling (by 2/1280) for you