missing points (unplotable?)

Hi,

I’m a newbie to OpenGL.

I was trying out drawing random points and was puzzled by the fact that some coordinate values are not drawn. Here’s the pic:

https://docs.google.com/file/d/0B01buLmY__mCejVCOXZZbDdrbFk/edit?usp=sharing

Notice that there are 3 coordinate values (same for both x and y axes) which does not contain any points. I thought maybe something is wrong with the random values. So I’ve added an array to check if all the possible values 0…599 are actually sent to OpenGL (see array X and printout after glFlush()). I’ve checked that all the coordinate values 0…599 (for the x axis) are indeed accounted for and sent to OpenGL. So it’s not the random point, but the rendering. Note also that these missing values are always the same every time there’s a re-display() and every time I run the program.

Can someone explain what’s happening? Thanks.


#include <iostream>
#include <ctime>
#include <cstdlib>
#include <GL/freeglut.h>

const int M = 600;
int X[M] = {0}; 

void init()
{
    glutInit(&argc, argv);    
    glutInitWindowPosition(0, 0);
    glutInitWindowSize(M, M);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
    glutCreateWindow("test");
}

void display()
{
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3d(0, 0, 0);
    glBegin(GL_POINTS);
    for (int i = 0; i < 1000000; i++)
    {
        int x = rand() % M;
        int y = rand() % M;
        X[x] = 1;
        glVertex2i(x, y);
    }   
    glEnd();
    glFlush();

    int count = 0;
    for (int i = 0; i < 400; i++)
    {
        if (X[i] == 0)
        {
            count++;
            std::cout << X[i] << ' ';
        }
        else
        {
            X[i] = 0;
        }
    }
    std::cout << "count: " << count << std::endl;
}

int main(int argc, char ** argv)
{
    srand((unsigned int) time(NULL));    
    init();
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0, M, 0, M);
    glClearColor(1.0f, 1.0f, 1.0f, 0.0f);    
    glutDisplayFunc(display);
    glutMainLoop();
    return 0;
}

Because you’re using integer coordinates, each point is being plotted exactly on the boundary between 4 pixels; exactly which pixel is almost random (i.e. the smallest rounding error will have an effect).

The existing gluOrtho2D call (along with the implicit glViewport call) means that (0,0) is the bottom-left corner of the window and the bottom-left corner of the bottom-left pixel, (1,1) is the top-right corner of the bottom-left pixel, and (0.5,0.5) is the centre of the bottom-left pixel.

If you want to set specific pixels, you need to offset each coordinate by half a pixel so that your points are being plotted exactly at the centre of a pixel. One way to do this is to change the gluOrtho2D call to:


    gluOrtho2D(-0.5, M-0.5, 0.5, M-0.5);

Another option is to leave the gluOrtho2D call alone but add


    glTranslatef(0.5f, 0.5f, 0.0f);

before it.

Beyond that, you should be using glutReshapeFunc to set a reshape handler, and calling glViewport and gluOrtho2D in the reshape handler. You shouldn’t rely upon the initial window size being exactly as requested, nor should you rely upon it staying at that size.

I manage to get a better distribution when I do this:

    glVertex2f(float(x) + 0.5, float(y) + 0.5);

following your comments. Thanks.

(Yes I know about reshape, viewport, …)