Question

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.

  1. The calls to glBindAttribLocation must come before self._shaderProgram.link(), as pointed out by Brett Hale.

  2. numpy.ndarray should be replaced by numpy.array.

If you fix these two problems, then the code works as expected.

Was it helpful?

Solution

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.

OTHER TIPS

I'd rather have posted a comment, but it got long. Hopefully this helps you:

Since your using the attribute keyword (a compatibility keyword) in your vertex shader, could you clarify what version of OpenGL and GLSL you are using? I don't see anything referring to the version in your code; did I miss it? It may help a bit to understand what the issue is.

The layout formatting would certainly simplify things if you have it available. Also, your shader(s) requires it's #version to be specified (at least in the latest spec, though I think it holds for all versions). Not necessary for 1.10 (though still supported), which the OP is using/intends to use.

I'm not familiar with Qt under Python but I'm pretty sure that you need to set your shader program as active using glUseProgram.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top