Search code examples
pythonopenglpyopengl

pyOpenGL Far Faces Render over Close Ones


So I have a problem I have been chasing for a couple days now and I can't find anything to help. I just started to try and learn pyOpenGL and have quickly run into this issue. I hope I have included enough info, thanks for any and all help.

The Issue:

When I draw a cube it seems that some of the faces in the back are rendering over the faces in the front. This doesn't make sense to me as the back faces should be further away and would appear behind the front faces. I have a short video of the issue below. I should mention that this problem appeared to occur in the tutorial that I was following but wasn't mentioned or fixed. As I said I am a beginner at this and any help would be appreciated.

Problem Video: https://media.giphy.com/media/OT6SrDbj5NopQpD8Pt/giphy.gif (Cube is rotating left to right)

Setup:

I am running this on Ubuntu Linux using python 2.7.15 and pyOpenGL 3.1.0 and pygame 1.9.4

Source Code:

import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *

colors=(
    (255, 0, 0),     #Red
    (0, 255, 0),     #Green
    (0, 0, 255),     #Blue
)

verts = (
    (1.0, -1.0, -1.0),
    (1.0, -1.0, 1.0), 
    (-1.0, -1.0, 1.0),
    (-1.0, -1.0, -1.0),
    (1.0, 1.0, -1.0),
    (1.0, 1.0, 1.0),
    (-1.0, 1.0, 1.0),
    (-1.0, 1.0, -1.0)
)

surfaces = (
    (0, 1, 2, 3), 
    (4, 7, 6, 5), 
    (0, 4, 5, 1), 
    (1, 5, 6, 2), 
    (2, 6, 7, 3), 
    (4, 0, 3, 7)
)

def cube_obj(faces, vertices):
    glBegin(GL_QUADS)

    x = 0
    for face in faces:
        glColor3fv(colors[x])
        x += 1
        if x > 2:
            x = 0
        for vertex in face:
            glVertex3fv(vertices[vertex])

    glEnd()


def main():
    pygame.init()
    display = (800, 600)
    pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
    gluPerspective(75, (display[0]/display[1]), 0.1, 50.0)
    glTranslatef(-0.0, 0.0, -10.0)
    glClearColor(1, 1, 1, 1)

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
        cube_obj(surfaces, verts)
        glRotatef(.5, 0, 1, 0) 
        pygame.display.flip()
        pygame.time.wait(10)

main()

Solution

  • You've to enable the Depth Test. The depth plane enables an test before a fragment is drawn. If the fragment doesn't pass the test ti is discarded. The default depth function (glDepthFunc) is GL_LESS. This causes that a fragment is discarded if a fragment was draw on the same place before, which has a depth which is greater or equal the depth of the new fragment. The depth is stored in the depth buffer. To make the depth test work, you've to do 2 things:

    Enable it and set the proper depth function, at the initialization of the OpenGL states:

    glDepthFunc(GL_LESS)     # this is default
    glEnable(GL_DEPTH_TEST)  
    

    And beside the color plane, the depth plane has to be cleared too, in each frame, by (glClear) (This part you've done already):

    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)