Overriding Rasterization and Pixel Perfect Zoom

I am making a 2D game similar to Age Of Empires.it is very irritating to see that OpenGL does not often draw boundary Pixels to prevent overdraw of pixels for primitives touching each other.Especially when drawing single lines or textured quads, often the boundary pixels are not drawn.

I do not want to compensate by adding or subtracting 0.5 or setting 0.375 etc in the view as is the commonly used approach in overcoming this.

IS there any simple way to override this in opengl ? Like say setting a simple state variable ? or some property of lines or polygons ?

Also while zooming i do want the blurred zooming that occurs when i try to scale in opengl.I want to zoom in as MSPAINT does when we ask it draw at say 800%.Each pixel is made bigger AND THERE IS NO BLURRING. Can i achieve the same effect in openGL ?

Do i need to post this in the Advanced FOrum?

thanks in advance for any help from anybody

I don’t understand the first question. Could you please try to explain it in some other way?

If you render your frame to a texture first and the render a quad filling the entire screen with the texture mapped on to it using GL_NEAREST as interpolation for magnification you should get the kind of zooming that MSPAINT has.

it is very irritating to see that OpenGL does not often draw boundary Pixels
That’s actually your error. When you draw line from A to B multiple times it will go through exactly the same pixels. That’s what OpenGL specs require. If you happen to draw this line from B to A then it can go through other pixels.
If it’s a polygon edge, then left edge of one polygon drawn from A to B will go through the same pixels that right edge of other polygon drawn from B to A.
Keep that in mind and fix your code.

As for zooming - you were unclear at this point. It could be that you refer to texture filtering - simply use GL_NEAREST filter. See glTexParameter function specs for more details.

Also while zooming i do want the blurred zooming that occurs when i try to scale in opengl.
For textures this is simple: Just use GL_NEAREST filtering with your textures.

For geometry edges that won’t work, but since you mentioned blurring on zoom, I guess your problem is just textures.

it is very irritating to see that OpenGL does not often draw boundary Pixels to prevent overdraw of pixels for primitives touching each other

I do not want to compensate by adding or subtracting 0.5 or setting 0.375 etc
I think you misunderstood how OpenGL rasterization works.

The coordinates in OpenGL are not pixels like in a 2D API. OpenGL is a vector based API, and integer coordinates are always between pixels.

To make the example easier, let’s say you defined an orthographic projection that does a 1:1 mapping between coordinates and pixels, and your window is 20x20 pixels.

The GL coordinates in this scenario range from (0,0) (=lower left corner of lower left pixel) to (20,20) (=upper right corner of upper right pixel). This is very different from 2D APIs, where the coordinates would range from (0,0) to (19,19) (each one meaning the whole pixel, not a point inside it).

Now assume you draw an axis aligned quad (10,10)-(15,15). That is, the quad is from the lower left corner of the pixel (10,10) to the lower left corner of the pixel (15,15). It is exactly 5 pixels across each dimension (=15-10). It covers the pixels 10, 11, 12, 13 and 14 (in both dimensions).

Look at this image to see what I mean:

Once you are aware of the differences to a pixel based API, it’s really easy. Actually it’s a lot easier than the coordinate systems of most 2D APIs, it’s just a little confusing to people coming from the raster world who are not familiar with vector graphics.

If it’s a polygon edge, then left edge of one polygon drawn from A to B will go through the same pixels that right edge of other polygon drawn from B to A.
Not neccesarily. If you take my example, and draw another quad from let’s say (10,15) to (15,20), the two quads would not share a single pixel, even though they share two vertices.

The ambiguities you speak of only happen when there are pixels that are partially inside a primitive. When the edge goes through a pixel, you can’t generally predict if the pixel is drawn or not, but you can depend on it being consistent in a single implementation.

But as long as you make sure the edges don’t cross pixels, you can make pixel-perfect drawing with OpenGL.

Well, the line does go through the same pixels, but it doesn’t mean that both polygons will cover these pixels - one will cover pixels on the left side of the line and the other on the right side of the line.
In ideal world it would look like this:

Edge between polygons will always go through the same pixels therefore splitting them into two groups: green polygon’s pixels and blue polygon’s pixels. If pixel’s center (red dots) is on the right side of line, it will belong to blue polygon, otherwise it will belong to green polygon.

In real life this line is calculated with limited precision:

If you draw polygons with proper vertex order (both clock wise or counter clock wise) this line will go through the same pixels and you’ll get perfect rendering.

If you don’t keep polygon winding the same the line will be drawn differently for each polygon, and this is what you get:

The bottom line is, that rendering is done with limited precision and therefore can contain minor errors, but if you render the same thing twice it will contain exactly the same errors and will perfectly match previous rendering.

As for user interface rendering, Overmind’s image exaplains it perfectly - you don’t need any offset to get perfectly matched polygons.

you don’t need any offset to get perfectly matched polygons.

True when you rasterize only filled primitives.
But if you mix points, lines, and real triangles you will have problems, as these primitives are rasterized differently. In that case the 0.375 shift is useful.
http://www.opengl.org/resources/faq/technical/rasterization.htm#rast0120

Also, I suppose GL_POLYGON_SMOOTH should be turned disabled, or the edges may be blended with the background for AA, which could look like the edges not being rendered. Just a minor comment, assuming it is turned of here since it is disabled by default.

True when you rasterize only filled primitives.
True… true… :wink: