Search code examples
winapiopenglwgl

How to properly setup OpenGL scene for visualizing single objects


I need to write a simple visualizer for my mesh toolkit. The objects I'm working with is always located inside [-1,1]^3 box (inclusive), so I need to ensure that object will be entirely visible by user. I also want to have a possiblity to rotate a camera around object like user is "flying" around object.

That's how I'm doing this:

static void Reshape(int w, int h)
{
    glViewport(0,0,(GLsizei) w, (GLsizei) h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    float maxDistance = sqrt(2);
    if (w <= h)
    {
        glOrtho(-maxDistance, maxDistance, -maxDistance * (GLfloat)h / (GLfloat)w,
            maxDistance * (GLfloat)h / (GLfloat)w, -6.0, 6.0);
    }
    else
    {
        glOrtho(-maxDistance * (GLfloat)w / (GLfloat)h, maxDistance * (GLfloat)w / (GLfloat)h,
            -maxDistance, maxDistance, -6.0, 6.0);
    }
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

static void PolarView(GLdouble distance, GLdouble twist, GLdouble elevation)
{
    double centerx, centery, centerz;
    double eyex, eyey, eyez;

    eyex = distance * cos(-twist) * cos(elevation);
    eyey = distance * sin(-twist) * cos(elevation);
    eyez = distance * sin(elevation);
    centerx = centery = centerz = 0;

    gluLookAt(eyex, eyey, eyez, centerx, centery, centerz, 0, 0, 1);
}

The Reshape function is called during initial setup and after each resize of the visualizer control, the PolarView function is called on each redraw with some angles and distance greater than square root of 3 (is it really matters?). That code works fine with convex objects like cube or sphere, but it have some problems with torus object (Some of the faces are seen thru others), so I believe it's something about depth testing. What's wrong with my setup? Screenshot:
Bad torus
Bad torus filled
I've made some search on the internet and found that such problem can happen in case when there is something wrong with my near and far plane parameters. What is the correct values for these in my case? My drawing procedure looks like:

glEnable(GL_DEPTH_TEST);
glClearDepth(1);
glPolygonMode(GL_FRONT, GL_LINE); // Changing of GL_LINE to GL_FILL doesn't fixing my problem, it just changing the appearance of the model.
glClearColor(BackColor.R / 255.0f, BackColor.G / 255.0f, BackColor.B / 255.0f, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
PolarView(sqrt(3), _phi, _theta);
// .. only draws 

My PIXELFORMATDESCRIPTOR:

        PIXELFORMATDESCRIPTOR pfd =
    {
        sizeof(PIXELFORMATDESCRIPTOR),
        1,
        PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
        PFD_TYPE_RGBA,
        24,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        32, // Depth buffer size
        0,
        0,
        PFD_MAIN_PLANE,
        0,
        0,
        0,
        0
    };

I've found some ways to workaround this:

  • Swap values for my near and far planes
  • set glDepthFunc to GL_GREATER and glClearDepth to 0
    OK, my code will be working fine if there is even number of errors. But where is first error?

Solution

  • "8.070 How can I automatically calculate a view that displays my entire model? (I know the bounding sphere and up vector.)" entry at OpenGL FAQ 8 answers my question. However, my setup is slightly different, here is my rewritten PolarView and Reshape functions:

    static void Reshape(int w, int h)
    {
        float diameter = sqrt(3);
        glViewport(0, 0, (GLsizei)w, (GLsizei)h);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        GLdouble zNear = 1;
        GLdouble zFar = zNear + diameter * 2;
        GLdouble left = -diameter;
        GLdouble right = diameter;
        GLdouble top = -diameter;
        GLdouble bottom = diameter;
        double aspect = (double)w / (double)h;
        if (aspect < 1)
        {
            bottom /= aspect;
            top /= aspect;
        }
        else
        {
            left *= aspect;
            right *= aspect;
        }
        glOrtho(left, right, bottom, top, zNear, zFar);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
    }
    
    static void PolarView(GLdouble twist, GLdouble elevation)
    {
        float diameter = sqrt(3);
        double distance = diameter * 2;
        double centerx, centery, centerz;
        double eyex, eyey, eyez;
    
        eyex = distance * cos(twist) * cos(elevation);
        eyey = distance * sin(twist) * cos(elevation);
        eyez = distance * sin(elevation);
        centerx = centery = centerz = 0;
        gluLookAt(eyex, eyey, eyez, centerx, centery, centerz, 0, 0, 1);
    }