2

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?
Glorfindel
  • 21,988
  • 13
  • 81
  • 109
okutane
  • 13,754
  • 10
  • 59
  • 67
  • You need to give more details on exactly what the problem is. it's difficult to understand. Maybe even a screen shot? – shoosh Feb 22 '09 at 14:54

2 Answers2

2

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.

Gareth Rees
  • 64,967
  • 9
  • 133
  • 163
  • That link didn't helped me. I added more code in my question. – okutane Feb 22 '09 at 17:24
  • It doesn't matter how I draw my polygons (GL_LINE or GL_FILL) the problem is still there. Is there any proofs that rendering with GL_LINE shouldn't use depth buffer? – okutane Feb 22 '09 at 18:03
  • Can you take a screenshot of the model drawn as I recommend above? – Gareth Rees Feb 22 '09 at 18:12
  • Uploaded new rendered model with flat filled faces. – okutane Feb 22 '09 at 18:26
  • You are using glOrtho which makes it a little hard to tell (see) which triangles is near/far. If you have a problem generating the meshes, triangles has to be generated in a certain order. See http://home.comcast.net/~fbui/glCullFace.html – epatel Feb 22 '09 at 18:31
  • I think it's clear that the culling is working correctly—we can see only front-facing triangles. It's the depth buffer that's not working. Are you sure you are calling glDepthFunc(GL_LEQUAL)? – Gareth Rees Feb 22 '09 at 18:39
  • The default for glDepthFunc is GL_LESS, which should be fine, so that's probably not the problem. – Gareth Rees Feb 22 '09 at 18:47
  • What does the scene look like if you try glFrustum instead of glOrtho? (make sure you use a positive near plane) – Gareth Rees Feb 22 '09 at 18:48
  • If I will use glFrustum(-maxDistance, maxDistance, -maxDistance, maxDistance, 0.1, 10) then the rendering area will be empty. – okutane Feb 23 '09 at 01:33
  • I've found how to workaround this. But how can I set my camera properly? I need to ensure that I'm looking at the center of my model from some constant distance. What's wrong with my PolarView function? – okutane Feb 23 '09 at 03:26
0

"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);
}  
okutane
  • 13,754
  • 10
  • 59
  • 67