user3181019
user3181019

Reputation: 15

OpenGL - Line disappear when move camera

I write a program to draw one line.

The line sometimes disappear when I move camera to positive z-axis (especially when z-axis greater than 10000).

There are some test result.

When z set 20541, the line can be seen.

When z set 20542, the line CAN'T be seen.

When z set 30320, the line can be seen.

When z set 30321, the line CAN'T be seen.

and so forth ...

The code is attached. What's wrong?

P.S. The code is written by OpenGL 1.0, but I can still get the same test result when written by OpenGL 3.0 + glm library.

#include <glut.h>

/*
System Info
-------------
OS: Win7 professional 64-bit SP1
CPU: Intel i3-4170 @ 3.70GHz
GPU: HD Graphics 4400
*/

void display(void) {
    // 20541 ok, 20542 not visible
    // 30320 ok, 30321 not visible
    const GLfloat z = 20541;

    const GLfloat far = 1000, near = 0.1;

    GLfloat vertices[4 * 3] = {
        -far, -far, z - far,
        far, far, z - far,
    };

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0, 0, z, 0, 0, z - 1, 0, 1, 0);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-0.1, 0.1, -0.1, 0.1, near, far);

    glColor3f(0, 1, 1); // blue

    glBegin(GL_LINES);
    glVertex3f(vertices[0], vertices[1], vertices[2]);
    glVertex3f(vertices[3], vertices[4], vertices[5]);
    glEnd();

    glFlush();
}

int main() {
    glutCreateWindow("");
    glutDisplayFunc(display);
    glutMainLoop();
    return 0;
}

Upvotes: 1

Views: 758

Answers (1)

BDL
BDL

Reputation: 22176

This issue seems to be a numerical instability of the floating point arithmetic. Since you are projecting points that are exactly on the far-plane, they get clipped when the floating-point result is a little bit larger than the expected result.

Let's assume a C++ implementation of what the gpu basically does:

glm::vec4 test_fp(float z)
{
    //Construct matrices
    auto ortho = glm::frustum(-0.1f, 0.1f, -0.1f, 0.1f, 0.1f, 1000.0f);
    auto lookat = glm::lookAt(glm::vec3(0, 0, z), glm::vec3(0, 0, z - 1.0f), glm::vec3(0, 1, 0));

    //We are only interested in the z-value
    glm::vec4 tvec(0, 0, z - 1000.0f, 1);

    //Calculate ndc vector
    auto result = ortho * lookat * tvec;

    //Homogenize
    result /= result.w;

    return result;
}

When now calling this function with the values you provided we get the following results:

auto a = test_fp(20541.0); //< [0, 0, 1.00000000, 1]
auto b = test_fp(20542.0); //< [0, 0, 1.00000191, 1]
auto c = test_fp(30320.0); //< [0, 0, 1.00000000, 1]
auto d = test_fp(30321.0); //< [0, 0, 1.00000191, 1]

As you can see, the results of b and d diverge from the mathematical correct result and are slightly above 1.0. Since values above 1.0 are behind the far-plane, they are clipped away and are not visible, which is exactly the behavior you have.

Upvotes: 1

Related Questions