I am trying to create PyQt5/ PyOpenGL code based on this example from the OpenGL Wiki.
The paintGL()
call does not render anything to the screen. The StackOverflow questions with similar titles that I read describe different issues from what I am facing:
Note: I cannot post more than 2 links at this time due to rep limitations. I have added all related StackOverflow links as comments to this question.
I also went through the Common OpenGL Mistakes page and it does not seem to help (quite possibly I did not understand the page well).
The glGetErrors
function reports GL.GL_NO_ERROR
at all the below stages:
- When creating the VAO binding
- On creating the VBO bindings,
- After calling
glBindVertexArray
andglEnableVertexAttribArray
The glGetShaderiv
and glGetProgramiv
return GL.GL_TRUE
, so there do not seem to be compiling and linking errors.
The GL context seems to have been correctly created. The self.context().isValid()
check returns True
.
I am using PyQt5.5, Python 3.4.0 with PyOpenGL 3.1. Also, GPU Caps Viewer reports that Open GL 4.5 is available on my machine.
Any help or pointers to get moving is much appreciated.
The code is below.
from PyQt5 import QtGui, QtCore
import sys, array
from OpenGL import GL
# Create the Vertex Shader script and the Fragment Shader script here.
DeltaVertexShader = '''
#version 420 core
layout (location = 0) in vec4 vertexPositions;
layout (location = 1) in vec4 vertexColours;
smooth out vec4 fragmentColours;
void main()
{
gl_Position = vertexPositions;
fragmentColours = vertexColours;
}
'''
DeltaFragmentShader = '''
#version 420 core
smooth in vec4 fragmentColours;
out vec4 finalColours;
void main()
{
finalColours = fragmentColours;
}
'''
class PulleysWithWeights3D( QtGui.QOpenGLWindow ):
def __init__(self):
super().__init__()
# These are the 4D coordinates of a triangle that needs to be drawn.
_vertexPos = [ 0.075, 0.075, 0.075, 1.0, \
0.275, 0.275, 0.275, 1.0, \
0.550, 0.550, 0.550, 1.0 ]
# These are the RGBA colours for each vertex.
_vertexCols = [ 0.875, 0.525, 0.075, 0.500, \
0.875, 0.525, 0.075, 0.500, \
0.875, 0.525, 0.075, 0.500 ]
self._deltaPositions = array.array( 'f', _vertexPos )
self._deltaColours = array.array( 'f', _vertexCols )
self._appSurfaceFormat = QtGui.QSurfaceFormat()
self._appSurfaceFormat.setProfile( QtGui.QSurfaceFormat.CoreProfile )
self._appSurfaceFormat.setMajorVersion( 4 )
self._appSurfaceFormat.setMinorVersion( 2 )
self._appSurfaceFormat.setRenderableType( QtGui.QSurfaceFormat.OpenGL )
self._appSurfaceFormat.setSamples( 16 )
self._appSurfaceFormat.setSwapBehavior( QtGui.QSurfaceFormat.DoubleBuffer )
self.setSurfaceType( QtGui.QSurface.OpenGLSurface )
self.setFormat( self._appSurfaceFormat )
self.setIcon( QtGui.QIcon('OpenGL.png') )
self.setTitle( 'Pulleys3D' )
self.setMinimumSize( QtCore.QSize( 1280, 640 ) )
self.show()
def initializeGL(self):
GL.glClearColor( 0.0, 0.0, 0.00, 1.0 ) # RGBA
GL.glClearDepthf(1.0)
GL.glClearStencil(0)
GL.glClear( GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT | GL.GL_STENCIL_BUFFER_BIT )
# Initialize a VAO.
self._vaoColouredDelta = GL.glGenVertexArrays(1)
GL.glBindVertexArray( self._vaoColouredDelta )
# Initialize the VBOs.
self._vboPositions = GL.glGenBuffers(1) # Create the position buffer.
self._vboShades = GL.glGenBuffers(1) # Create the colours buffer.
# Bind the positions VBO to the GL_ARRAY_BUFFER target.
GL.glBindBuffer( GL.GL_ARRAY_BUFFER, self._vboPositions )
# Initialize the positions buffer with the positions array data.
GL.glBufferData( GL.GL_ARRAY_BUFFER, self._deltaPositions.buffer_info()[1] * self._deltaPositions.itemsize, \
self._deltaPositions.tobytes(), GL.GL_STATIC_DRAW )
GL.glEnableVertexAttribArray(0) # Enable attribute array 0, i.e., the positions array.
GL.glVertexAttribPointer( 0, 4, GL.GL_FLOAT, GL.GL_FALSE, 0, None )
GL.glBindBuffer( GL.GL_ARRAY_BUFFER, 0 )
GL.glBindBuffer( GL.GL_ARRAY_BUFFER, self._vboShades )
GL.glBufferData( GL.GL_ARRAY_BUFFER, self._deltaColours.buffer_info()[1] * self._deltaColours.itemsize, \
self._deltaColours.tobytes(), GL.GL_STATIC_DRAW )
GL.glEnableVertexAttribArray(1) # Enable attribute array 1, i.e., the colours array.
GL.glVertexAttribPointer( 1, 4, GL.GL_FLOAT, GL.GL_FALSE, 0, None )
GL.glBindBuffer( GL.GL_ARRAY_BUFFER, 0 )
GL.glBindVertexArray(0) # Unbind the VAO.
# Initialize the vertex shader and fragment shader program objects.
_vertexShaderObj = GL.glCreateShader( GL.GL_VERTEX_SHADER )
_fragmentShaderObj = GL.glCreateShader( GL.GL_FRAGMENT_SHADER )
GL.glShaderSource( _vertexShaderObj, DeltaVertexShader )
GL.glShaderSource( _fragmentShaderObj, DeltaFragmentShader )
GL.glCompileShader( _vertexShaderObj )
GL.glCompileShader( _fragmentShaderObj )
if GL.glGetShaderiv( _vertexShaderObj, GL.GL_COMPILE_STATUS ) != GL.GL_TRUE:
# There was a compilation error. Print it.
print( 'Vertex Shader Compilation failed! Details follow.' )
print( 'Compilation errors are: %s ' %( str( GL.glGetShaderInfoLog( _vertexShaderObj ) ) ) )
# Delete this shader.
GL.glDeleteShader( _vertexShaderObj )
return # Don't continue execution.
elif GL.glGetShaderiv( _fragmentShaderObj, GL.GL_COMPILE_STATUS ) != GL.GL_TRUE:
print( 'Fragment Shader Compilation failed! Details follow.' )
print( 'Compilation errors are: %s ' %( str( GL.glGetShaderInfoLog( _fragmentShaderObj ) ) ) )
# Delete this shader.
GL.glDeleteShader( _fragmentShaderObj )
return # Don't continue execution.
self._renderProgram = GL.glCreateProgram()
GL.glAttachShader( self._renderProgram, _vertexShaderObj )
GL.glAttachShader( self._renderProgram, _fragmentShaderObj )
GL.glLinkProgram( self._renderProgram )
if GL.glGetProgramiv( self._renderProgram, GL.GL_LINK_STATUS ) != GL.GL_TRUE:
print( 'Shader linking failed! Details follow.' )
print( 'Linking errors are: %s ' %( str( GL.glGetProgramInfoLog( self._renderProgram ) ) ) )
GL.glDetachShader( self._renderProgram, _vertexShaderObj )
GL.glDetachShader( self._renderProgram, _fragmentShaderObj )
GL.glDeleteShader( _vertexShaderObj )
GL.glDeleteShader( _fragmentShaderObj )
# Delete the program.
GL.glDeleteProgram( self._renderProgram )
return # Don't continue execution.
# Always detach shaders after a successful link.
GL.glDetachShader( self._renderProgram, _vertexShaderObj )
GL.glDetachShader( self._renderProgram, _fragmentShaderObj )
def resizeGL(self, wd, ht ):
# Resize the viewport by calling glViewport with the new height and width.
GL.glViewport( 0, 0, wd, ht )
def paintGL(self):
GL.glClearColor( 0.0, 0.0, 0.00, 1.0 ) # RGBA
GL.glClearDepthf(1.0)
GL.glClearStencil(0)
GL.glClear( GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT | GL.GL_STENCIL_BUFFER_BIT )
# Initialize the shader program to paint.
GL.glUseProgram( self._renderProgram )
GL.glBindVertexArray( self._vaoColouredDelta )
# Draw the array.
GL.glDrawArrays( GL.GL_TRIANGLES, 0, 3 )
# Swap the front and back buffers so the newly drawn content is visible.
self.context().swapBuffers( self )
# Unbind the vertex array and the program.
GL.glBindVertexArray(0)
GL.glUseProgram(0)
if __name__ == '__main__':
_pww3dApp = QtGui.QGuiApplication( sys.argv )
_pww3d = PulleysWithWeights3D()
sys.exit( _pww3dApp.exec_() )