Search code examples
pythonopenglpygameglutpyopengl

PyOpenGL, Hidden-line removal and glut


I am using an approach for hidden line removal in a PyOpenGL program where I draw a figure twice, once as a wireframe and then again as filled polygons. It is working fine for my own figures but not for the basic glutSolidCube/glutWireCube so I am curious if there is a flaw in my code that the use of glut figures is exposing. Maybe there is just something squirrelly in the glut figures but I am guessing those are pretty well used and debugged...

here is my draw code (working app follows), followed by screen shot of result:

def render_scene():
    glEnableClientState(GL_VERTEX_ARRAY)
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    glLineWidth(2)

    glMatrixMode(GL_MODELVIEW)
    glPushMatrix()
    
    glRotate(rot[0], 1, 0, 0)
    glRotate(rot[1], 0, 1, 0)
    #
    # =============
    # pass 1: lines
    # =============
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)    
    glColor(0, 0, 0)
    # my cube
    glVertexPointer(3, GL_FLOAT, 0, cube_vertices)
    glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, cube_indices)
    # glut cube
    glPushMatrix()
    glTranslate(-1.1, 0, 0)
    glutWireCube(1)
    glPopMatrix()
    #
    # ================
    # pass 2: filled polygons
    # ================
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)
    glEnable(GL_POLYGON_OFFSET_FILL)
    glPolygonOffset(2, 2)
    glColor(1, 1, 1)
    # my cube
    glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, cube_indices)
    # glut cube
    glPushMatrix()
    glTranslate(-1.1, 0, 0)
    glutSolidCube(1)
    glPopMatrix()
   
    glPopMatrix()
    pg.display.flip()
    return

Thanks in advance!

running code:

import pygame as pg
from pygame.locals import *
from numpy import array, float32, uint32
from OpenGL.GLUT import *
from OpenGL.GL import *
from OpenGL.GLU import *

FPS = 60
WIDTH = 800
HEIGHT = 600
clock = pg.time.Clock()
rot = [10, 10]

cube_vertices = array([
    -0.5, -0.5, -0.5,
    0.5, -0.5, -0.5,
    0.5, 0.5, -0.5,
    -0.5, 0.5, -0.5,
    -0.5, -0.5, 0.5,
    0.5, -0.5, 0.5,
    0.5, 0.5, 0.5,
    -0.5, 0.5, 0.5], dtype=float32)   

cube_indices = array([
    0, 1, 2, 3,   # front 
    4, 5, 1, 0,   # top
    3, 2, 6, 7,   # bottom
    5, 4, 7, 6,   # back
    1, 5, 6, 2,   # right
    4, 0, 3, 7], dtype=uint32)    


def setup_rc():
    
    glEnable(GL_DEPTH_TEST)
    glEnable(GL_CULL_FACE)
    glCullFace(GL_FRONT)
    glClearColor(1, 1, 1, 0)  
    
    pg.event.post(pg.event.Event(VIDEORESIZE, {'size':(WIDTH, HEIGHT)}))

    return


def on_video_resize(event):
    w = event.size[0]
    h = event.size[1]
    if h == 0: h = 1
    aspect_ratio = w/h

    glViewport (0, 0, w, h)
    glMatrixMode (GL_PROJECTION)
    glLoadIdentity()
    if w <= h:
        glOrtho (-1.5, 1.5, -1.5*h/w, 1.5*h/w, -10.0, 10.0)
    else:
        glOrtho (-1.5*w/h, 1.5*w/h, -1.5, 1.5, -10.0, 10.0)
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()

    return True

def render_scene():
    glEnableClientState(GL_VERTEX_ARRAY)
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    glLineWidth(2)

    glMatrixMode(GL_MODELVIEW)
    glPushMatrix()
    
    glRotate(rot[0], 1, 0, 0)
    glRotate(rot[1], 0, 1, 0)
    #
    # =============
    # pass 1: lines
    # =============
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)    
    glColor(0, 0, 0)
    # my cube
    glVertexPointer(3, GL_FLOAT, 0, cube_vertices)
    glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, cube_indices)
    # glut cube
    glPushMatrix()
    glTranslate(-1.1, 0, 0)
    glutWireCube(1)
    glPopMatrix()
    #
    # ================
    # pass 2: filled polygons
    # ================
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)
    glEnable(GL_POLYGON_OFFSET_FILL)
    glPolygonOffset(2, 2)
    glColor(1, 1, 1)
    # my cube
    glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, cube_indices)
    # glut cube
    glPushMatrix()
    glTranslate(-1.1, 0, 0)
    glutSolidCube(1)
    glPopMatrix()
   
    glPopMatrix()
    pg.display.flip()
    return

def update():
    clock.tick(FPS)
    return

def on_keydown(event):
    key = event.key
    if key == K_LEFT:
        rot[1] -= 2
    elif key == K_RIGHT:
        rot[1] += 2
    if key == K_UP:
        rot[0] -= 2
    elif key == K_DOWN:
        rot[0] += 2
    elif key == K_ESCAPE:    
        pg.event.post(pg.event.Event(QUIT))
    return True

def main():
    pg.init()
    pg.display.set_mode((WIDTH, HEIGHT), DOUBLEBUF|OPENGL|RESIZABLE)
    pg.key.set_repeat(200, 100)
    pg.display.set_caption("Use arrow keys to rotate scene")
    glutInit()

    setup_rc()
    
    add_event_handler(VIDEORESIZE, on_video_resize)
    add_event_handler(KEYDOWN, on_keydown)
    
    while do_events():
        render_scene()
        update()

    pg.quit()
    return 

# =======================================
# my simplified pygame event handling, 
# normally in a separate module but wanted
# to make this code standalone
# =======================================
#
event_map = {pg.QUIT : (lambda e: False)}

def add_event_handler(key, func):  
    event_map[key] = func
    return

def try_to_apply(e):
    try:
        return event_map[e.type](e)
    except KeyError:
        return True

def do_events():
    return all(try_to_apply(e) for e in pg.event.get())

# ========================================

main()

Screen shot (glut-based figure on left, my figure on right): enter image description here


Solution

  • The problem is that you are mixing face culling and polygon offsets. The winding order of glutSolidCube/glutWireCube seems to be the opposite of the winding order of your own meshes. Disable face culling. Also note that glutSolidCube/glutWireCube may change the client states, so you should always specify the vertex pointer with glVertexPointer before drawing a geometry:

    def setup_rc():    
        glEnable(GL_DEPTH_TEST)
        #glEnable(GL_CULL_FACE)
        #glCullFace(GL_FRONT)
        glClearColor(1, 1, 1, 0)  
    
    def render_scene():
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glLineWidth(2)
    
        glMatrixMode(GL_MODELVIEW)
        glPushMatrix()
        
        glRotate(rot[0], 1, 0, 0)
        glRotate(rot[1], 0, 1, 0)
        #
        # =============
        # pass 1: lines
        # =============
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)  
        glDisable(GL_POLYGON_OFFSET_FILL)  
        glColor(0, 0, 0)
        # my cube
        glEnableClientState(GL_VERTEX_ARRAY)
        glVertexPointer(3, GL_FLOAT, 0, cube_vertices)
        glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, cube_indices)
        # glut cube
        glPushMatrix()
        glTranslate(-1.1, 0, 0)
        glutWireCube(1)
        glPopMatrix()
        #
        # ================
        # pass 2: filled polygons
        # ================
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)
        glEnable(GL_POLYGON_OFFSET_FILL)
        glPolygonOffset(2, 2)
        glColor(1, 1, 0)
        # my cube
        glEnableClientState(GL_VERTEX_ARRAY)
        glVertexPointer(3, GL_FLOAT, 0, cube_vertices)
        glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, cube_indices)
        # glut cube
        glPushMatrix()
        glTranslate(-1.1, 0, 0)
        glutSolidCube(1)
        glPopMatrix()
       
        glPopMatrix()
        glFlush()