Search code examples
c++opengl3dcube

3D Cube Drawing, Only One Side Is Always On Top


I was working with OpenGL C++ drawing shapes, specifically cubes. In my current project, I managed to draw a cube correctly, but only the side of the cube that gets drawn last doesn't go transparent when the camera is directly on it. The first two sides of the cube go completely transparent when viewed head-on. Is there a way to fix this? Here is the picture. As you can see, the first two sides don't get displayed. Here is my code:

Main.cpp:

#include "Render.h"
#include <stdlib.h>

int screenHeight = 500;
int screenWidth = 500;
int screenFPS = 60;

void MainLoop(int val);

int main(int argc, char* args[])
{
    glutInit(&argc, args);
    glutInitDisplayMode(GLUT_DOUBLE);
    glutInitWindowSize(screenWidth, screenHeight);
    glutInitWindowPosition(350, 80);
    glutCreateWindow("Cube");
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    //glOrtho(0.0f, screenWidth, screenHeight, 0.0f, 0.0f, 1.0f);
    gluPerspective(40, 1, 0.5, 20);
    glutDisplayFunc(Render);
    glViewport(0, 0, screenWidth, screenHeight);
    glutKeyboardFunc(HandleKeys);
    glutIdleFunc(Animation);
    glutTimerFunc(1000 / screenFPS, MainLoop, 0);
    glutMainLoop();
    return 0;
}

void MainLoop(int val)
{
    Render();
    glutTimerFunc( 1000 / screenFPS, MainLoop, val );
}

Render.cpp:

#include "Render.h"
#include <iostream>
#include <stdlib.h>
#include <windows.h>

GLfloat xRot, yRot, zRot;

void Render()
{
    std::cout << xRot << " " << yRot << " " << zRot << "\n";
    glMatrixMode(GL_MODELVIEW);
    glClear(GL_COLOR_BUFFER_BIT);
    glLoadIdentity();
    glTranslatef(0.0,0.0,-10.5);
    glRotatef(yRot, 1.0, 0.0, 0.0);
    glRotatef(yRot, 0.0, 1.0, 0.0);
    glRotatef(zRot, 0.0, 0.0, 1.0);
    glBegin(GL_QUADS);
       glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
        glVertex3f( 1.0f, 1.0f,-1.0f);
        glVertex3f(-1.0f, 1.0f,-1.0f);
        glVertex3f(-1.0f, 1.0f, 1.0f);
        glVertex3f( 1.0f, 1.0f, 1.0f);
       glColor4f(1.0f, 0.5f, 0.0f, 1.0f);
        glVertex3f( 1.0f,-1.0f, 1.0f);
        glVertex3f(-1.0f,-1.0f, 1.0f);
        glVertex3f(-1.0f,-1.0f,-1.0f);
        glVertex3f( 1.0f,-1.0f,-1.0f);
       glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
        glVertex3f( 1.0f, 1.0f, 1.0f);
        glVertex3f(-1.0f, 1.0f, 1.0f);
        glVertex3f(-1.0f,-1.0f, 1.0f);
        glVertex3f( 1.0f,-1.0f, 1.0f);
       glColor4f(1.0f, 1.0f, 0.0f, 1.0f);
        glVertex3f( 1.0f,-1.0f,-1.0f);
        glVertex3f(-1.0f,-1.0f,-1.0f);
        glVertex3f(-1.0f, 1.0f,-1.0f);
        glVertex3f( 1.0f, 1.0f,-1.0f);
       glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
        glVertex3f(-1.0f, 1.0f, 1.0f);
        glVertex3f(-1.0f, 1.0f,-1.0f);
        glVertex3f(-1.0f,-1.0f,-1.0f);
        glVertex3f(-1.0f,-1.0f, 1.0f);
       glColor4f(1.0f, 0.0f, 1.0f, 1.0f);
        glVertex3f( 1.0f, 1.0f,-1.0f);
        glVertex3f( 1.0f, 1.0f, 1.0f);
        glVertex3f( 1.0f,-1.0f, 1.0f);
        glVertex3f( 1.0f,-1.0f,-1.0f);
    glEnd();
    glutSwapBuffers();
}
void Animation()
{
    yRot += 0.03;
    xRot += 0.08;
    Render();
}
void HandleKeys(unsigned char key, int x, int y)
{
    if(key == 27)
        exit(0);
    else if(key == 'w')
        yRot += 0.55;
    else if(key == 'a')
        xRot -= 0.55;
    else if(key == 's')
        yRot -= 0.55;
    else if(key == 'd')
        xRot += 0.55;
}

Render.h

#include "GLLib.h"
extern int screenHeight;
extern int screenWidth;
extern int screenFPS;
void Render();
void Animation();
void HandleKeys(unsigned char key, int x, int y);

And finally my librarys, GLLib.h:

#ifndef GLLIB_H
#define GLLIB_H
#include <GL/freeglut.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#endif

Solution

  • Chances are that all sides are drawn just fine. The problem is that you don't have a depth buffer. Therefore, everything that is drawn replaces what was drawn previously, no matter if it's in front or behind the previously drawn geometry.

    To use a depth buffer, you have to request it during initialization:

    glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH);
    

    and enable depth testing before you start rendering:

    glEnable(GL_DEPTH_TEST);
    

    Then, at the start of rendering each frame, you need to clear the depth buffer in addition to the color buffer:

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    

    This will make sure that the front most faces are visible, and the faces behind them are hidden, independent of the drawing order.