PDA

View Full Version : Attempting perfect edges in Ortho



CodesAndChaos
07-09-2009, 03:44 PM
First I'll describe what I'm trying to do, then what code I'm attempting to do this with, and finally what's not working (based on what I'm doing in code)

1) What I'm trying to do:
I'm trying to first render a closed line loop (later the same coordinates will be used for a texture map) in orthographic mode (using glOrtho) so that I can save raster images of diamond tiles. These renderings will be saved as bitmaps and later used in an isometric game (actually dimetric since the angle is to be at 26.565 and not 30 degrees because I want rise/run == 1/2). Essentially what I'm trying to do is create a simple 3D tile renderer for isometric games.

2) The code (my code that is not working):

// using JOGL - init
gl.glViewport(0, 0, width, height); // 100 x 100 for now
gl.glMatrixMode(gl.GL_PROJECTION);
gl.glLoadIdentity();
gl.glOrtho(-2, 2, -2, 2, -2, 2);
gl.glMatrixMode(gl.GL_MODELVIEW);

...

// drawing section
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
// not sure why the following gives perfect w == 1/2*h
// since it should be 26.565, rotated about x
gl.glRotated( 29.699999999999996, 1.0, 0.0, 0.0);
gl.glRotated(-45.0, 0.0, 1.0, 0.0); // rotate about y
// optional for panning (diamond shape appears to move up/down
gl.glTranslated(-pan, pan, -pan);
gl.glBegin(gl.GL_LINE_LOOP);
gl.glVertex3d(0.0, 0.0, 0.0);
gl.glVertex3d(1.0, 0.0, 0.0);
gl.glVertex3d(1.0, 0.0, 1.0);
gl.glVertex3d(0.0, 0.0, 1.0);
gl.glEnd();
gl.glFlush();

...

// zoom is rounded to avoid binary representational issues
// this is in the event handling section
pan -= .1;
pan = (int)(pan * 100 + 0.5) / 100.0;

3) What's not working:
Before performing any translations, the diamond shape is perfect in that it's rise/run is 1/2. The diamond shape can be used and perfectly tiled. If however I translate, the perfectly rendered diamond is no longer perfect. The following picture shows the perfect render and the same geometry after two translations.

http://arron.ferguson.googlepages.com/ortho-rendering-problem.png/ortho-rendering-problem-full;init:.png

It's kind of hard to see but if you zoom to the images (zoom without antialiasing in your favorite image software) you'll see that the pixels are not lining up to a rise/run of 1/2 after a translation (the first one is fine but it's without any sort of panning).

I'm confused because that sort of distortion shouldn't be happening in orthogonal view (according to my limited world of understanding in OpenGL). If you have any suggestions as to how I can correct this so that no matter if I zoom in/out or if I translate (pan) left/right/up/down the pixels show the same rise/run, I would be eternally grateful!

ZbuffeR
07-10-2009, 05:42 AM
In fact this makes sense.
The 2D vertex coordinates (after ortho projection) have floating point precision.
Let's say for a line, first and second vertex are like this :
vertex A : x= 10.2 pixel coordinate rounded to 10
vertex B : x= 15.3 pixel coordinate rounded to 15

when translating a bit, 0.25 units to the right :
vertex A : x= 10.45 pixel coordinate rounded to 10
vertex B : x= 15.55 pixel coordinate rounded to 16

Here appear a 1-off error.

To avoid this, I would suggest to feed exact integer coordinates to opengl on an identity matrix adapted to the number of pixels on screen, skipping GL ortho transformation.
Otherwise you will have to struggle against GL transformation.

CodesAndChaos
07-10-2009, 06:29 PM
ZbuffeR,

Thanks for your response. Unfortunately you're talking with a n00bie when it comes to OpenGL. If you have time, could you elaborate on what you said about "feed exact integer coordinates to opengl on an identity matrix adapted to the number of pixels on screen"? I'm not sure what this means.

ZbuffeR
07-11-2009, 01:28 AM
use this projection :

glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluOrtho2D (0, windowWidth, 0, windowHeight);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();

then draw your scene using only glVertex2d commands.
Do not use rotations.
Be sure to use only integer values for x,y in glTranslated(x, y, 0);
That way you should avoid such "rolling edge" artifacts.

If this works, Maybe you can put back your rotations convenient for isometric view.

But be warned that getting perfect rasteritation when mixing points, lines, and triangles, is very hard and sometimes impossible.
You may try the slight offset recommended by the GL FAQ states :
"If exact pixelization is required, you might want to put a small translation in the ModelView matrix, as shown below:

glMatrixMode (GL_MODELVIEW); glLoadIdentity (); glTranslatef (0.375, 0.375, 0.);
"

scratt
07-12-2009, 12:02 AM
You may try the slight offset recommended by the GL FAQ states :
"If exact pixelization is required, you might want to put a small translation in the ModelView matrix, as shown below:

glMatrixMode (GL_MODELVIEW); glLoadIdentity (); glTranslatef (0.375, 0.375, 0.);
"


I was working on something which required exact alignment this weekend and happened on this thread while looking for info I may have missed.

I've been scaling my integer vertices and then using a corresponding 1.0/scale value for matrix scaling to avoid jitter.

But I was still having some small alignment problems.

This last note, which I had not noticed on the GL FAQs, with a little jiggling of numbers completed the final touch to get everything aligned perfectly.

Thanks, ZBufferR.

Without the matrix scaling though it does not work for me..
So it may be worth trying this also if you still have problems with alignment.

For example:
Multiply all your vectors by 16.
Apply the translation to the identity matrix and then scale the matrix by 1.0/16.0f.

Obviously which ever number you use for the vector scaling must be used as the value to divide 1.0 by when you scale the matrix.

CodesAndChaos
07-12-2009, 02:58 PM
ZbuffeR,

Thanks for your time. I'm going to try this.