Reputation: 1163
Is it possible to set up an OpenGL scene to allow for pixel-perfect rendering and pixel blitting? I noticed that setting up a scene by doing:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, width, height, 0.0, 0.0, 1.0);
And then drawing a pixel using:
glBegin(GL_POINTS);
glVertex2i(0, 0);
glEnd();
Does not consistently draw it on the top-left pixel on every hardware configuration (sometimes it's one pixel to the left, or one below the top-left corner). I realize this is likely due to different implementations of OpenGL by the graphics drivers, but is there a way to make it so that the top-left pixel is (0,0) and the bottom right is (width-1, height-1) consistently? It seems strange that this is something that isn't standardized...
I've seen some 'hacks' that use a translation of (0.375, 0.375) or (0.5, 0.5), but that also seems to solve it for some configurations and not for others.
Upvotes: 4
Views: 4096
Reputation: 5763
edit: dang, it is a translation. Updated.
You've got to consider also that pixels have size too. This is what the "translation hacks" are getting at. If the leftmost pixel should have a center coordinate 0.0
, then its left boundary is at -0.5
-- and that's where the clipping plane should be. Similarly, if the rightmost pixel should have a center coordinate width - 1
, then its right boundary is at (width - 1) + 0.5
-- and that's where that clipping plane should be.
So try:
glOrtho(-0.5, (width - 1) + 0.5, (height - 1) + 0.5, -0.5, 0.0, 1.0);
So that's where the translation come from.
Upvotes: 7
Reputation: 16582
On first inspection that seems like it should work, and that if implementations are offsetting by a pixel, I suspect they may be out of spec. However it could also be a result of having the view transformed upside down, and some inaccuracy creeping in and causing a rounding issue. I'm not convinced that's the case, but if I wanted to do pixel-perfect rendering I wouldn't start by introducing an unnecessary transform.
Most likely I'd avoid the fixed-function pipeline entirely anyway, and simply ensure that I'm calculating the right coords in the vertex shader, using my own transforms. So that's my first suggestion - the modern programmable pipeline puts you in a lot more control of what's going on.
Failing that, at least try rendering things the right way up and see if that makes the various platforms you're targetting a bit more consistent.
Alternatively, and I consider this a bit of a hack but sometimes these things are necessary - you could check for it, and offset your coordinates accordingly using a transform (i.e. draw a pixel and read it back to see if it ended up in the right place, and if not, where it did go). Of course you might just be compounding the problem.
I wouldn't fiddle too much with sub-pixel offsets here, more likely you'll just introduce more cases where pixels are no longer mapped 1:1 as you want.
Upvotes: 1