Search code examples
pythonopenglpyopengl

PyOpengl: Changing gluPerspective variables makes cube flash


When using gluPerspective in glutReshapeFunc function, the square image flashes while resizing and is gone after a few moments.

from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *

width = 500
height = 500


def cube():
    glBegin(GL_QUADS)
    glColor3f(0, 1, 0)
    glVertex3f(10, 0, 0)
    glVertex3f(10, 10, 0)
    glVertex3f(10, 0, 0)
    glVertex3f(0, 0, 0)
    glVertex3f(10, 0, 0)
    glVertex3f(10, 0, 10)
    glVertex3f(0, 10, 0)
    glVertex3f(10, 10, 0)
    glVertex3f(0, 10, 0)
    glVertex3f(0, 0, 0)
    glVertex3f(0, 10, 0)
    glVertex3f(0, 10, 10)
    glVertex3f(0, 0, 10)
    glVertex3f(0, 0, 0)
    glVertex3f(0, 0, 10)
    glVertex3f(10, 0, 10)
    glVertex3f(0, 0, 10)
    glVertex3f(0, 10, 10)
    glVertex3f(10, 10, 10)
    glVertex3f(10, 10, 0)
    glVertex3f(10, 10, 10)
    glVertex3f(10, 0, 10)
    glVertex3f(10, 10, 10)
    glVertex3f(0, 10, 10)
    glEnd()


def showScreen():
    global width, height

    glClearColor(0, 0, 0, 1)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    cube()
    glutSwapBuffers()


def mouseTracker(mousex, mousey):
    print(f"Mouse pos: {mousex}, {mousey}")


def reshapeWindow(x, y):
    global width, height
    width = x
    height = y
    print(x, y)
    gluPerspective(45, (width / height), 0.0001, 1000)



glutInit()
glutInitDisplayMode(GLUT_RGBA)
glutInitWindowSize(500, 500)
wind = glutCreateWindow("OpenGL")
glutDisplayFunc(showScreen)
glutIdleFunc(showScreen)
glutMotionFunc(mouseTracker)
glutPassiveMotionFunc(mouseTracker)
glutReshapeFunc(reshapeWindow)
gluPerspective(45, (width / height), 0.0001, 1000)
glTranslatef(0, 0, -5)

while True:
    glutMainLoopEvent()
    glutPostRedisplay()

If I put the gluPerspective into the showScreen function like so:

def showScreen():
    global width, height

    glClearColor(0, 0, 0, 1)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    cube()
    gluPerspective(45, (width / height), 0.0001, 1000)
    glutSwapBuffers()

The square flashes without resizing but it is gone after a few moments. If I remove the gluPerspective entirely, the image turns into a triangle. Is there any way to change gluPerspective variables without making the image flash?


Solution

  • You have to call gluPerspective before drawing the cube. The matrix operations not only set the current matrix, but define a new matrix and multiply the current matrix by the new matrix. Therefore you must load the Identity matrix with glLoadIdentity before modifying the matrix. The legacy OpenGL provides different current matrices for the model view matrix and the projection matrix. Before changing a matrix, select the matrix mode with glMatrixMode:

    Change the projection matrix in the reshape callback:

    def reshapeWindow(x, y):
        global width, height
        width = x
        height = y
        print(x, y)
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        gluPerspective(45, (width / height), 0.0001, 1000)
        glMatrixMode(GL_MODELVIEW)
    

    Set the model view matrix before the application loop or in the application loop:

    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    glTranslatef(0, 0, -5)
    

    gluPerspective defines a Viewing frustum. The center of the view is (0, 0). Hence you need to change the vertex coordinates.

    I suggest enabling the Depth Test when drawing 3D meshes.

    Minimale example based on your code:

    from OpenGL.GL import *
    from OpenGL.GLU import *
    from OpenGL.GLUT import *
    import time
    
    width = 500
    height = 500
    
    vertices = [(-1,-1,-1), ( 1,-1,-1), ( 1, 1,-1), (-1, 1,-1), (-1,-1, 1), ( 1,-1, 1), ( 1, 1, 1), (-1, 1, 1)]
    faces = [(4,0,3,7), (1,0,4,5), (0,1,2,3), (1,5,6,2), (3,2,6,7), (5,4,7,6)]
    colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1), (1, 1, 0), (1, 0, 1), (0, 1, 1)]
    
    def cube():
        glRotatef(1, 3, 1, 1)
        glBegin(GL_QUADS)
        for i, face in enumerate(faces):
            glColor3fv(colors[i])
            for vertex in face:
                glVertex3fv(vertices[vertex])
        glEnd()
    
    def showScreen():
        glClearColor(0, 0, 0, 1)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        cube()
        glutSwapBuffers()
    
    def mouseTracker(mousex, mousey):
        print(f"Mouse pos: {mousex}, {mousey}")
    
    def reshapeWindow(x, y):
        global width, height
        width = x
        height = y
        print(x, y)
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        gluPerspective(45, (width / height), 0.0001, 1000)
        glMatrixMode(GL_MODELVIEW)
    
    glutInit()
    glutInitDisplayMode(GLUT_RGBA)
    glutInitWindowSize(500, 500)
    wind = glutCreateWindow("OpenGL")
    glutDisplayFunc(showScreen)
    glutIdleFunc(showScreen)
    glutMotionFunc(mouseTracker)
    glutPassiveMotionFunc(mouseTracker)
    glutReshapeFunc(reshapeWindow)
    
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    glTranslatef(0, 0, -5)
    
    glEnable(GL_DEPTH_TEST)
    
    while True:
        glutMainLoopEvent()
        glutPostRedisplay()
        time.sleep(0.01)