okutane
okutane

Reputation: 14250

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:

Upvotes: 2

Views: 2633

Answers (2)

okutane
okutane

Reputation: 14250

"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);
}  

Upvotes: 0

Gareth Rees
Gareth Rees

Reputation: 65854

Have you read OpenGL FAQ 12?

The one thing that looks suspicious about your code is the negative near plane. Negative Z values are behind the camera, which is usually a mistake when rendering a 3D scene. However, that in itself shouldn't cause the problem you're seeing, and the range [-6,6] for Z should provide plenty of precision for this kind of scene.

Are you calling glEnable(GL_DEPTH_TEST)? Are you passing GL_DEPTH_BUFFER_BIT to glClear each frame?

Update: you're calling glPolygonMode(GL_FRONT, GL_LINE). This means that front-facing triangles are drawn in outline only, which means that if front-facing triangle A overlaps another front-facing triangle B, you can see through A to the edges of B. With a convex body this can't happen, so you don't notice the problem.

If you want triangles to occlude the triangles behind them, then you are going to need to fill them in using mode GL_FILL. To get a wireframe figure, you need to draw the model with white fill, then draw the model again with black outline, like this:

glDepthFunc(GL_LEQUAL);
glPolygonMode(GL_FRONT, GL_FILL);
/* draw the model in white */
glDepthFunc(GL_EQUAL);
glPolygonMode(GL_FRONT, GL_LINE);
/* draw the model again in black */

The idea is that on the second pass over the model, we only want to draw the outlines that are not obscured by some triangle drawn in the first pass that is closer to the camera (that is, with lower Z).

Another idea: I think your camera may be pointing the wrong way. This would explain why the scene is being drawn wrongly with the glOrtho perspective, and not at all with the glFrustum perspective. In the glOrtho case, the entire scene is being drawn behind the camera; that's why it's being drawn with the Z order the wrong way round. When you set the near plane to a positive number, the entire scene is culled.

Upvotes: 2

Related Questions