Question: What is wrong with this simple OpenGL/GLSL program? It is supposed to produce a quad with a red-green color gradient. But I just get a black window, and no error messages.
import numpy
from OpenGL.GL import *
from PySide.QtCore import *
from PySide.QtGui import *
from PySide.QtOpenGL import *
_vertexShaderSource = (
'attribute vec2 a_position;'
'attribute vec3 a_color;'
'varying vec3 v_color;'
''
'void main()'
'{'
' gl_Position = vec4(a_position, 0.0, 1.0);'
' v_color = a_color;'
'}'
)
_fragmentShaderSource = (
'varying vec3 v_color;'
''
'void main()'
'{'
' gl_FragColor = vec4(v_color, 1.0);'
'}'
)
_POSITION = 0
_COLOR = 1
class HelloWidget(QGLWidget):
def __init__(self):
QGLWidget.__init__(self)
def initializeGL(self):
self._shaderProgram = QGLShaderProgram(self.context())
self._shaderProgram.addShaderFromSourceCode(QGLShader.Vertex, _vertexShaderSource)
self._shaderProgram.addShaderFromSourceCode(QGLShader.Fragment, _fragmentShaderSource)
self._shaderProgram.link()
self._shaderProgram.bind()
glBindAttribLocation(self._shaderProgram.programId(), _POSITION, 'a_position')
glBindAttribLocation(self._shaderProgram.programId(), _COLOR, 'a_color')
def paintGL(self):
glViewport(0, 0, self.width(), self.height())
glClear(GL_COLOR_BUFFER_BIT)
position = numpy.ndarray([-0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5], numpy.float32)
glVertexAttribPointer(_POSITION, 2, GL_FLOAT, False, 0, position)
glEnableVertexAttribArray(_POSITION)
color = numpy.ndarray([1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0], numpy.float32)
glVertexAttribPointer(_COLOR, 3, GL_FLOAT, False, 0, color)
glEnableVertexAttribArray(_COLOR)
glDrawArrays(GL_QUADS, 0, 4)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
w = HelloWidget()
w.show()
app.exec_()
Answer: There are two bugs in the code.
The calls to glBindAttribLocation
must come before self._shaderProgram.link()
, as pointed out by Brett Hale.
numpy.ndarray
should be replaced by numpy.array
.
If you fix these two problems, then the code works as expected.
From the man page for glBindAttribLocation
:
Any attribute binding that occurs after the program object has been linked will not take effect until the next time the program object is linked.
Associate the attribute indices first, then link the program.
Alternatively, assign a value to _POSITION
, _COLOR
, etc., using glGetAttribLocation
.
As @KillianDS mentions, you can specify the index (location) in the shader, provided you have GL 3.3 or above. This is a source of frustration on OS X, which only guarantees GL 3.2.
It might also be worth pointing out that GL_QUADS
is not supported in the core profile, so it may be necessary to work around that, e.g., with 2 triangles.