When writing a very simple, introductory code using PyOpenGL and pygame, I stumbled across a logic error. The cube (rendered with triangle strips and glDrawArray
) would appear once, on the first frame, and then disappear for all frames after that.
MRE:
import pygame
pygame.init()
from OpenGL import GL
from OpenGL import GLU
def solidCube():
vertices = (-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,
-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)
GL.glColor3f(255, 255, 255)
GL.glEnableClientState(GL.GL_VERTEX_ARRAY)
data = (GL.GLfloat * len(vertices))(*vertices)
GL.glVertexPointer(3, GL.GL_FLOAT, 0, data)
GL.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 14)
GL.glDisableClientState(GL.GL_VERTEX_ARRAY)
display = (600, 500)
screen = pygame.display.set_mode(display, pygame.DOUBLEBUF|pygame.OPENGL)
GL.glMatrixMode(GL.GL_PROJECTION)
GL.glLoadIdentity()
GLU.gluPerspective(90, (display[0]/display[1]), 0.1, 100.0)
GLU.gluLookAt(0, 0, 0, -1.0, 0, 0, 0, 1, 0)
game = 1
clock = pygame.time.Clock()
while game:
for event in pygame.event.get():
if event.type == pygame.QUIT:
game = 0
GL.glMatrixMode(GL.GL_MODELVIEW)
GL.glLoadIdentity()
GL.glClearColor(0, 0, 0, 1)
GL.glClear(GL.GL_COLOR_BUFFER_BIT|GL.GL_DEPTH_BUFFER_BIT)
GL.glTranslatef(-10, 0, 0)
solidCube()
GL.glMatrixMode(GL.GL_PROJECTION)
GL.glLoadIdentity()
GLU.gluLookAt(0, 0, 0, -1.0, 0, 0, 0, 1, 0)
pygame.display.flip()
clock.tick(50)
pygame.quit()
This code raised no errors, but instead did not show the cube for more than one frame, instead flashing it once, then not showing it any more. Then I started debugging.
My gluLookAt
and gluPerspective
were static values, they did not change. Thus, it could not be that I was not seeing the cube (it rendered properly the first frame, these were the right values). My cube's position was also static, it was not moving anywhere, or out of my FOV. So, it came down to the cube not getting drawn. I removed the glClear
statement from the code, and the cube flickered in and out of existence. I had a similar issue in the past, it was that the object was only in one of the two video buffers, so pygame.display.flip()
would swap between the two really quickly, bringing it in and out of existence.
Because of this, I was able to source my problem: the cube was getting drawn once, then rendered (properly). After this, it would clear both buffers and the cube would not get redrawn, so I was left with a blank screen.
To summarize, my question is: Why is my triangle-strip cube not getting drawn more than once, and how can I fix this issue, and have it re-draw?
You just mixed up the matrices. The projection matrix should be set tot the current GL_PROJECTION
matrix and the mode view matrix to the current GL_MODELVIEW
.
GL.glMatrixMode(GL.GL_PROJECTION)
GL.glLoadIdentity()
GLU.gluPerspective(90, (display[0]/display[1]), 0.1, 100.0)
game = 1
clock = pygame.time.Clock()
while game:
for event in pygame.event.get():
if event.type == pygame.QUIT:
game = 0
GL.glMatrixMode(GL.GL_MODELVIEW)
GL.glLoadIdentity()
GLU.gluLookAt(0, 0, 0, -1.0, 0, 0, 0, 1, 0)
GL.glClearColor(0, 0, 0, 1)
GL.glClear(GL.GL_COLOR_BUFFER_BIT|GL.GL_DEPTH_BUFFER_BIT)
GL.glTranslatef(-10, 0, 0)
solidCube()
pygame.display.flip()
Note that OpenGL is a state engine. Once a state is set, it is retained until changed again, even beyond frames.
The matrix which is affected by the matrix operations is specified with glMatrixMode
. The matrix operations, like gluPerspective
, gluLookAt
, glRotate
, glScale
, glTranslatef
, not only set a matrix, they define a new matrix and multiply the current matrix by the new matrix. Therefore you can "reset" a current matrix with glLoadIdentity
. glLoadIdentity
assigns the Identity matrix to the current matrix.
Complete example:
import numpy as np
import pygame
pygame.init()
from OpenGL import GL
from OpenGL import GLU
def solidCube():
vertices = (-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,
-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)
GL.glColor3f(255, 255, 255)
GL.glEnableClientState(GL.GL_VERTEX_ARRAY)
data = (GL.GLfloat * len(vertices))(*vertices)
GL.glVertexPointer(3, GL.GL_FLOAT, 0, data)
GL.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 14)
GL.glDisableClientState(GL.GL_VERTEX_ARRAY)
display = (600, 500)
screen = pygame.display.set_mode(display, pygame.DOUBLEBUF|pygame.OPENGL)
GL.glMatrixMode(GL.GL_PROJECTION)
GL.glLoadIdentity()
GLU.gluPerspective(90, (display[0]/display[1]), 0.1, 100.0)
angle = 0
game = 1
clock = pygame.time.Clock()
while game:
for event in pygame.event.get():
if event.type == pygame.QUIT:
game = 0
GL.glMatrixMode(GL.GL_MODELVIEW)
GL.glLoadIdentity()
GLU.gluLookAt(0, 0, 0, -1.0, 0, 0, 0, 1, 0)
GL.glClearColor(0, 0, 0, 1)
GL.glClear(GL.GL_COLOR_BUFFER_BIT|GL.GL_DEPTH_BUFFER_BIT)
GL.glTranslatef(-5, 0, 0)
GL.glRotatef(angle, 0, 1, 0)
angle += 1
GL.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_LINE)
solidCube()
pygame.display.flip()
clock.tick(50)
pygame.quit()