glOrtho weird behaviour?

Hello OpenGL developers!

I’ve made a simple test case and I don’t know what to think about behaviour of my program. I will try to describe it in few words. My program makes the following instructions:

  1. Creates an orthographic projection for my scene.
  2. Places OpenGL points (using GL.GL_POINTS and glVertex3d() function) in each corner of my ortho “box” (using the same coordinates as the glOrtho (left, right, bottom, top) parameters).
  3. Shows result frame to the user.

I’ve used three samples of parameters (xmin, xmax, ymin, ymax) for projection and points generation (in the source code two samples are placed in commented block):

  • first one with a small numbers,
  • second one is the first one + 5000000 and
  • third one is the first one + 10000000.

As I’ve understood from the OpenGL Red Book (Chapter 3: Viewing, Orthographic Projection), that three images generated with those three samples should look the same - as the image generated with first sample (four equal white squares in each corner). But it isn’t :-.
There is no model in my test case except 4 points to get the clearest and simplest code.
It looks like glOrtho function gives the wrong perspective matrix when it paramaters are big numbers and left-to-right and bottom-to-top distance are small. Maybe it’s coused by double precision error ???.
Please help me with this problem beacause I think I’ve just exploited all good ideas with this task ::slight_smile:

This test case has been done because of a big problem with map display precision that I must manage in my bigger map application.

So here is the source code of my test case:


import java.awt.*;
import java.awt.event.*;

import javax.media.opengl.*;
import com.sun.opengl.util.*;

public class OrthoTest implements GLEventListener {
    
/*    private double xmin = 0.75;
    private double xmax = 30.25;
    private double ymin = 0.75;
    private double ymax = 30.25;
*/ 
/*    private double xmin = 5000000.75;
    private double xmax = 5000030.25;
    private double ymin = 5000000.75;
    private double ymax = 5000030.25;
*/    
    private double xmin = 10000000.75;
    private double xmax = 10000030.25;
    private double ymin = 10000000.75;
    private double ymax = 10000030.25;
    
    public static void main(String[] args) {
        Frame frame = new Frame("Ortho test");
        GLCanvas canvas = new GLCanvas();
        
        canvas.addGLEventListener(new OrthoTest());
        frame.add(canvas);
        frame.setSize(700, 700);
        final Animator animator = new Animator(canvas);
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                // Run this on another thread than the AWT event queue to
                // make sure the call to Animator.stop() completes before
                // exiting
                new Thread(new Runnable() {
                    public void run() {
                        animator.stop();
                        System.exit(0);
                    }
                }).start();
            }
        });
        frame.setVisible(true);
        animator.start();
    }
    
    public void init(GLAutoDrawable drawable) {}
    
    public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {}
    
    public void display(GLAutoDrawable drawable) {
        
        GL gl = drawable.getGL();
        
        if ((drawable instanceof GLJPanel) &&
                !((GLJPanel) drawable).isOpaque() &&
                ((GLJPanel) drawable).shouldPreserveColorBufferIfTranslucent()) {
            gl.glClear(GL.GL_DEPTH_BUFFER_BIT);
        } else {
            gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
        }
        
        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glLoadIdentity();
        gl.glOrtho(
                xmin,       // left
                xmax,       // right
                ymin,       // bottom
                ymax,       // top
                -10.0f, 10.0f);
        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();
        
        gl.glPointSize( 20.0f);
        gl.glBegin(GL.GL_POINTS);
        gl.glColor3f(1.0f, 1.0f, 1.0f);
        gl.glVertex3d(xmin, ymin, 0.0f);    // left-bottom
        gl.glVertex3d(xmin, ymax, 0.0f);    // left-top
        gl.glVertex3d(xmax, ymin, 0.0f);    // right-bottom
        gl.glVertex3d(xmax, ymax, 0.0f);    // right-top
        gl.glEnd();
    }
    
    public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {}
    
}

I discovered that translating my points to the beginning of coordinate system and placing there my orthographic projection “box” gives the same result ???
Can somebody help me, please…

Here is the source code:

import java.awt.*;
import java.awt.event.*;

import javax.media.opengl.*;
import com.sun.opengl.util.*;

public class OrthoTest_2 implements GLEventListener {
    
/*    private double xmin = 0.75;
    private double xmax = 30.25;
    private double ymin = 0.75;
    private double ymax = 30.25;
*/ 
/*    private double xmin = 5000000.75;
    private double xmax = 5000030.25;
    private double ymin = 5000000.75;
    private double ymax = 5000030.25;
*/    
    private double xmin = 10000000.75;
    private double xmax = 10000030.25;
    private double ymin = 10000000.75;
    private double ymax = 10000030.25;
    
    public static void main(String[] args) {
        Frame frame = new Frame("Ortho test");
        GLCanvas canvas = new GLCanvas();
        
        canvas.addGLEventListener(new OrthoTest_2());
        frame.add(canvas);
        frame.setSize(700, 700);
        final Animator animator = new Animator(canvas);
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                // Run this on another thread than the AWT event queue to
                // make sure the call to Animator.stop() completes before
                // exiting
                new Thread(new Runnable() {
                    public void run() {
                        animator.stop();
                        System.exit(0);
                    }
                }).start();
            }
        });
        frame.setVisible(true);
        animator.start();
    }
    
    public void init(GLAutoDrawable drawable) {}
    
    public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {}
    
    public void display(GLAutoDrawable drawable) {
        
        GL gl = drawable.getGL();
        
        if ((drawable instanceof GLJPanel) &&
                !((GLJPanel) drawable).isOpaque() &&
                ((GLJPanel) drawable).shouldPreserveColorBufferIfTranslucent()) {
            gl.glClear(GL.GL_DEPTH_BUFFER_BIT);
        } else {
            gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
        }
        
        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glLoadIdentity();
        gl.glOrtho(
                0,              // left
                xmax - xmin,    // right
                0,              // bottom
                ymax - ymin,    // top
                -10.0f, 10.0f);
        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();
        
        gl.glPushMatrix();
        gl.glTranslated(-ymin, -xmin, 0);
        gl.glPointSize( 20.0f);
        gl.glBegin(GL.GL_POINTS);
        gl.glColor3f(1.0f, 1.0f, 1.0f);
        gl.glVertex3d(xmin, ymin, 0.0f);    // left-bottom
        gl.glVertex3d(xmin, ymax, 0.0f);    // left-top
        gl.glVertex3d(xmax, ymin, 0.0f);    // right-bottom
        gl.glVertex3d(xmax, ymax, 0.0f);    // right-top
        gl.glEnd();
        gl.glPopMatrix();
    }
    
    public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {}
    
}

The GPU handles all coords and matrices as floatingpoint (32bit) values, where you only have 6-7 significant decimals.

You’re simply losing too much precision.

Either that, or you’re making some other mistake… try to reduce the bigger factors to <10000 for example.

Thank you for reply Riven. 3D reality is mathematically perfect, but unfortunately computers have theirs limitations :-[
I’ve repaired my program translating all my maps in maths (not OpenGL) space and now it works great!

Thank you once again Riven.
Sometimes programming a lots of code You can forgot some general things like I do :stuck_out_tongue: