Search code examples
openglcameraglut

gluPerspective messes up 3D objects


void drawTire(void)
{
    GLint num_of_tri = 32;
    GLfloat vertex[3]; 
    const GLfloat delta_angle = 2.0*PI/float(num_of_tri);

    //Draw Front tire
    glBegin(GL_TRIANGLE_FAN);
        glColor3f(0.5, 0.5, 0.5);

        vertex[0] = vertex[1] = vertex[2] = 0.0;
        glVertex3fv(vertex);

        for(int i = 0; i < num_of_tri ; i++)
        {
            vertex[0] = cos(delta_angle*i) * wheelRadius; //wheel Radius is 1.0
            vertex[1] = sin(delta_angle*i) * wheelRadius;
            vertex[2] = 0.0;
            glVertex3fv(vertex);
        }
        vertex[0] = 1.0 * wheelRadius;
        vertex[1] = 0.0 * wheelRadius;
        vertex[2] = 0.0;
        glVertex3fv(vertex);
    glEnd();

    //Draw Back Tire
    const GLfloat depth = -wheelRadius/1.5; 
    glBegin(GL_TRIANGLE_FAN);
        glColor3f(1.0, 0.0, 0.0);
        vertex[0] = vertex[1] = 0.0;
        vertex[2] = depth;
        glVertex3fv(vertex);

        for(int i = 0; i < num_of_tri ; i++)
        {
            vertex[0] = cos(delta_angle*i) * wheelRadius;
            vertex[1] = sin(delta_angle*i) * wheelRadius;
            vertex[2] = depth;
            glVertex3fv(vertex);
        }
        vertex[0] = 1.0 * wheelRadius;
        vertex[1] = 0.0 * wheelRadius;
        vertex[2] = depth;
        glVertex3fv(vertex);
    glEnd();

    //Connect Front&Back
    glBegin(GL_QUADS);
        glColor3f(0.0, 0.0, 0.0);
        for(int i = 0; i < num_of_tri; i++)
        {
            vertex[0] = cos(delta_angle*i) * wheelRadius;
            vertex[1] = sin(delta_angle*i) * wheelRadius;
            vertex[2] = 0;
            glVertex3fv(vertex);

            vertex[0] = cos(delta_angle*i) * wheelRadius;
            vertex[1] = sin(delta_angle*i) * wheelRadius;
            vertex[2] = depth;
            glVertex3fv(vertex);

            vertex[0] = cos(delta_angle*((i + 1)%num_of_tri)) * wheelRadius;
            vertex[1] = sin(delta_angle*((i + 1)%num_of_tri)) * wheelRadius;
            vertex[2] = depth;
            glVertex3fv(vertex);

            vertex[0] = cos(delta_angle*((i + 1)%num_of_tri)) * wheelRadius;
            vertex[1] = sin(delta_angle*((i + 1)%num_of_tri)) * wheelRadius;
            vertex[2] = 0;
            glVertex3fv(vertex);
        }
    glEnd();

    glFlush();
}

I'm using the above code to draw a (kind of) 3D car wheel. This code appears to work.
This is my init function:

void init(void)
{    
    glClearColor (1.0, 1.0, 1.0, 0.0);
    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
    gluPerspective(45.0f, (GLfloat)1366/(GLfloat)768, 0.1f, 100.0f);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0.0, 0.0, 5.0, 0, 0, 0, 0, 1, 0);
}

This is my display function:

void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
drawTire();
glFlush();
}

The result is messed up car wheel as can be seen here: http://postimg.org/image/fuf9o75ub/

The front of the tire (the side that the camera should be looking at) is gray. The camera somehow looks at the back of the tire, which is red.
Also, the tire side (the one the that touches the ground. I have no idea how to name it) is also shown, which is weird (the black color).

Why does gluPerspective messes up 3D object, and how can one fix this? (I have tried changing the fov... result were almost the same)


Solution

  • Right now, you aren't using depth testing. This means that the last primitive rendered is the one "on top", since without depth testing, OpenGL has no way of knowing the 'depth' of a pixel after it has been rendered.

    To solve this problem, OpenGL uses a depth buffer, which is a hidden screen-sized buffer that stores how far away each pixel is from the camera. With depth testing enabled, when OpenGL renders a fragment, it first checks the depth of the fragment and compares it to the value in the depth buffer. If the fragment's depth value is smaller than the stored value (note 1), then OpenGL concludes that the fragment is in front of an already rendered object and writes the fragment. Otherwise, its behind an object and ignores the fragment.

    To use depth testing, you first need to make sure you've allocated a depth buffer when you created your context. This depends on what windowing library you are using, but usually they give you a depth buffer by default.

    You then need call glEnable(GL_DEPTH_TEST) to begin using depth testing.

    Additionally, you need to clear the depth values in the depth buffer when you re-render your scene. Change glClear(GL_COLOR_BUFFER_BIT) to glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT).

    And that's all you need to use depth testing.


    (note 1): More specfically, it uses whatever function was set glDepthFunc, though 99% of the time this is GL_LESS or GL_LEQUAL.