Issue
I am running through a cumulation of OpenGL shader tutorials and mixing and matching stuff, trying to get a custom shader implemented. I have the following Python code and traceback:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QOpenGLWidget
from PyQt5.QtCore import Qt
from OpenGL.GL import (
glLoadIdentity, glTranslatef, glRotatef,
glClear, glBegin, glEnd,
glColor3fv, glVertex3fv,
GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT,
GL_QUADS, GL_LINES,
shaders, GL_VERTEX_SHADER, GL_FRAGMENT_SHADER
)
from OpenGL.GLU import gluPerspective
class mainWindow(QMainWindow): #Main class.
def keyPressEvent(self, event): #This is the keypress detector.
try:
key = event.key()
except:
key = -1
#print(key)
if key == 16777216:
exit()
vertices = [
(-1, 1, 0),
(1, 1, 0),
(1, -1, 0),
(-1, -1, 0)
]
wires = [
(0, 1),
(1, 2),
(2, 3),
(0, 3)
]
facets = [
(0, 1, 2, 3)
]
zoomLevel = -5
rotateDegreeH = 0
rotateDegreeV = -45
vertShaderCode = """#version 120
void main() {
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}"""
fragShaderCode = """#version 120
void main() {
gl_FragColor = vec4( 0, 1, 0, 1 );
}"""
def __init__(self):
super(mainWindow, self).__init__()
self.sizeX = 700 #Variables used for the setting of the size of everything
self.sizeY = 600
self.setGeometry(0, 0, self.sizeX + 50, self.sizeY) #Set the window size
#make shaders
VERTEX_SHADER = shaders.compileShader(self.vertShaderCode, GL_VERTEX_SHADER)
FRAGMENT_SHADER = shaders.compileShader(self.fragShaderCode, GL_FRAGMENT_SHADER)
self.shader = shaders.compileProgram(VERTEX_SHADER,FRAGMENT_SHADER)
self.openGLWidget = QOpenGLWidget(self) #Create the GLWidget
self.openGLWidget.setGeometry(0, 0, self.sizeX, self.sizeY)
self.openGLWidget.initializeGL()
self.openGLWidget.resizeGL(self.sizeX, self.sizeY) #Resize GL's knowledge of the window to match the physical size?
self.openGLWidget.paintGL = self.paintGL #override the default function with my own?
def nav(self, hVal = 0, vVal = 0, zVal = 0):
self.zoomLevel += zVal
self.rotateDegreeH += hVal
self.rotateDegreeV += vVal
self.openGLWidget.update()
def paintGL(self):
#This function uses shape objects, such as cube() or mesh(). Shape objects require the following:
#a list named 'vertices' - This list is a list of points, from which edges and faces are drawn.
#a list named 'wires' - This list is a list of tuples which refer to vertices, dictating where to draw wires.
#a list named 'facets' - This list is a list of tuples which refer to vertices, ditating where to draw facets.
#a bool named 'render' - This bool is used to dictate whether or not to draw the shape.
#a bool named 'drawWires' - This bool is used to dictate whether wires should be drawn.
#a bool named 'drawFaces' - This bool is used to dictate whether facets should be drawn.
shaders.glUseProgram(self.shader)
glLoadIdentity()
gluPerspective(45, self.sizeX / self.sizeY, 0.1, 110.0) #set perspective?
glTranslatef(0, 0, self.zoomLevel) #I used -10 instead of -2 in the PyGame version.
glRotatef(self.rotateDegreeV, 1, 0, 0) #I used 2 instead of 1 in the PyGame version.
glRotatef(self.rotateDegreeH, 0, 0, 1)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
glBegin(GL_LINES)
for w in self.wires:
for v in w:
glVertex3fv(self.vertices[v])
glEnd()
glBegin(GL_QUADS)
for f in self.facets:
for v in f:
glVertex3fv(self.vertices[v])
glEnd()
app = QApplication([])
window = mainWindow()
window.show()
sys.exit(app.exec_())
C:\Users\ccronk22\Documents\Python\glShaders>pygl002.py
Traceback (most recent call last):
File "C:\Users\ccronk22\AppData\Local\Programs\Python\Python38\lib\site-packages\OpenGL\latebind.py", line 43, in __call__
return self._finalCall( *args, **named )
TypeError: 'NoneType' object is not callable
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\ccronk22\Documents\Python\glShaders\pyGL002.py", line 109, in <module>
window = mainWindow()
File "C:\Users\ccronk22\Documents\Python\glShaders\pyGL002.py", line 59, in __init__
VERTEX_SHADER = shaders.compileShader(self.vertShaderCode, GL_VERTEX_SHADER)
File "C:\Users\ccronk22\AppData\Local\Programs\Python\Python38\lib\site-packages\OpenGL\GL\shaders.py", line 228, in compileShader
shader = glCreateShader(shaderType)
File "C:\Users\ccronk22\AppData\Local\Programs\Python\Python38\lib\site-packages\OpenGL\latebind.py", line 46, in __call__
self._finalCall = self.finalise()
File "C:\Users\ccronk22\AppData\Local\Programs\Python\Python38\lib\site-packages\OpenGL\extensions.py", line 242, in finalise
raise error.NullFunctionError(
OpenGL.error.NullFunctionError: Attempt to call an undefined alternate function (glCreateShader, glCreateShaderObjectARB), check for bool(glCreateShader) before calling
C:\Users\ccronk22\Documents\Python\glShaders>
The above code works well if you comment out the compileShader, compileProgram, and useProgram lines. It produces a white square, viewed from an above angle:
def __init__(self):
super(mainWindow, self).__init__()
self.sizeX = 700 #Variables used for the setting of the size of everything
self.sizeY = 600
self.setGeometry(0, 0, self.sizeX + 50, self.sizeY) #Set the window size
#make shaders
#VERTEX_SHADER = shaders.compileShader(self.vertShaderCode, GL_VERTEX_SHADER)
#FRAGMENT_SHADER = shaders.compileShader(self.fragShaderCode, GL_FRAGMENT_SHADER)
#self.shader = shaders.compileProgram(VERTEX_SHADER,FRAGMENT_SHADER)
[…]
def paintGL(self):
#This function uses shape objects, such as cube() or mesh(). Shape objects require the following:
#a list named 'vertices' - This list is a list of points, from which edges and faces are drawn.
#a list named 'wires' - This list is a list of tuples which refer to vertices, dictating where to draw wires.
#a list named 'facets' - This list is a list of tuples which refer to vertices, ditating where to draw facets.
#a bool named 'render' - This bool is used to dictate whether or not to draw the shape.
#a bool named 'drawWires' - This bool is used to dictate whether wires should be drawn.
#a bool named 'drawFaces' - This bool is used to dictate whether facets should be drawn.
#shaders.glUseProgram(self.shader)
Some additional information:
I am attempting to make the code from http://pyopengl.sourceforge.net/context/tutorials/shader_1.html work in the PyQt5 context, with only the OpenGL and PyQt5 APIs. The tutorial was written in Python2. I am using Python3.
So, what am I doing wrong with my shader compilation? Is it in the Python or GLSL?
Solution
To compile and link the shader you need a valid and current OpenGL Context. Note the OpenGL context have to be current when any OpenGL instruction is invoked.
QOpenGLWidget
provides the virtual methods
def initializeGL () def paintGL () def resizeGL (w, h)
where the OpenGL context is active. This methods are callbacks and invoked by Qts event handling. Don't call them in your code.
Create the shader in the initializeGL
callback:
class mainWindow(QMainWindow):
def __init__(self):
super(mainWindow, self).__init__()
self.sizeX = 700 #Variables used for the setting of the size of everything
self.sizeY = 600
self.setGeometry(0, 0, self.sizeX + 50, self.sizeY) #Set the window size
self.openGLWidget = QOpenGLWidget(self) #Create the GLWidget
self.openGLWidget.setGeometry(0, 0, self.sizeX, self.sizeY)
self.openGLWidget.resizeGL(self.sizeX, self.sizeY) #Resize GL's knowledge of the window to match the physical size?
self.openGLWidget.initializeGL = self.initializeGL
self.openGLWidget.paintGL = self.paintGL #override the default function with my own?
self.shader = None
def nav(self, hVal = 0, vVal = 0, zVal = 0):
self.zoomLevel += zVal
self.rotateDegreeH += hVal
self.rotateDegreeV += vVal
self.openGLWidget.update()
def initializeGL(self):
#make shaders
VERTEX_SHADER = shaders.compileShader(self.vertShaderCode, GL_VERTEX_SHADER)
FRAGMENT_SHADER = shaders.compileShader(self.fragShaderCode, GL_FRAGMENT_SHADER)
self.shader = shaders.compileProgram(VERTEX_SHADER,FRAGMENT_SHADER)
def paintGL(self):
glUseProgram(self.shader)
# [...]
(The import of glUseProgram
is missing in your code)
Answered By - Rabbid76
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.