I would have thought that dealing with textures in OpenGL would be simple, and that stacks of documentation would be available on the web to tell me how I should do it. Ok, so taking it to the next stage of doing something with that texture using GLSL might be a bit more involved, but it should be basically plain sailing. I assumed that using python would make no difference at all to what was actually involved.
I don’t know if its my incompetence or just the flaky pyside bindings for the Qt GLSL stuff, but it seemed to be much more difficult than it ought to have been. A small test example I hacked up builds on the previous post. The intention was to draw a 2D image over the top of the 3D Qt logo. Other than that, the code is identical.
There is stacks of documentation out there, including lots on the pyside website. Unfortunately, it seems the documentation often doesn’t actually represent reality. The doc page for QtOpenGL.QGLShaderProgram has a chunk of python that is not even valid (closer inspection reveals its a partial transliteration from the C++ docs), and I had no end of fun calling various functions from PyOpenGL that were documented but didn’t actually do as expected.
Part of the frustration with the OpenGL (and possibly a legacy of its state machine nature) is a deeply annoying failure mode in which nothing appears on the screen, but no errors occur. As often as not when you think you’ve followed some tutorial or documentation to the letter!
In the end, I adopted a hybrid approach of using parts of the Qt library, including QGLShaderProgram along with management of the texture using direct OpenGL calls. As a learned friend of mine declared,“writing OpenGL is about hacking until it works”. It now works (and isn’t wholly unclean).
As with the previous post, there was the necessity to combine my OpenGL scene with a QML overlay, which came with similar problems of context management as discussed. In particular, it is necessary to update the texture parameters on every update to the scene (as opposed to at initialisation as with more usual implementations). The modifications to the drawBackground() method of OpenGLScene amount to the inclusion of initialisation code (which is run once), which sets up the shaders (loading and linking etc), and then the following which is run on every redraw:
self.program.bind() GL.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR) GL.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR) GL.glTexEnvf(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_REPLACE) GL.glEnableClientState(GL.GL_VERTEX_ARRAY) GL.glVertexPointer(3, GL.GL_FLOAT, 0, triangle_vertices) GL.glDrawArrays(GL.GL_TRIANGLES, 0, len(triangle_vertices)/3) GL.glDisableClientState(GL.GL_VERTEX_ARRAY) self.program.release()
Note that this code is run outside of the viewport modifications that are performed for the rendering of the Qt logo. The consequence of this is that the image scales with the window. It would be trivial to change but it didn’t seem necessary for this example.
The shaders themselves are at the top of the source code. Full functioning code can be found here.
One problem I had that’s worth noting was when I’d failed to make my texture a power of 2 (although it is documented, its not obviously necessary).
Finally, if anyone can work out how to pass attribute arrays to a GLSL program using python, please let me know!