glDrawArrays returning invalid operation 1282 - pyOpenGL - python

I cannot figure this out for the life of me. I need a second pair of eyes ... or a better brain. I am trying to get this "Hello Triangle" python example working. I've been translating it from a c tutorial. However, I keep getting this error no matter what I do.
Traceback (most recent call last):
File ".../demo/tester.py", line 107, in <module>
if __name__ == '__main__': main()
File ".../demo/tester.py", line 87, in main
glDrawArrays(GL_TRIANGLES, 0, 3)
File ".../venv/lib/python3.6/site packages/OpenGL/platform/baseplatform.py", line 402, in __call__
return self( *args, **named )
File ".../venv/lib/python3.6/site-packages/OpenGL/error.py", line 232, in glCheckError
baseOperation = baseOperation,
OpenGL.error.GLError: GLError(
err = 1282,
description = b'invalid operation',
baseOperation = glDrawArrays,
cArguments = (GL_TRIANGLES, 0, 3)
My code is below. I am running on a Mac so you'll notice some things in there that might not be needed for PC. Everything works fine up until the glDrawArrays. I know that some of the functions between openGL for C vs python using pyOpenGL are a bit different. I've been cross referencing the documentation to make sure I am not trying write like a C programmer in Python.
try:
from AppKit import NSApp, NSApplication
except:
pass
import sys
import cyglfw3 as glfw
import numpy as np
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.arrays import vbo as glvbo
def main():
glfw.Init()
glfw.WindowHint(glfw.CONTEXT_VERSION_MAJOR, 3)
glfw.WindowHint(glfw.CONTEXT_VERSION_MINOR, 3)
glfw.WindowHint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
glfw.WindowHint(glfw.OPENGL_FORWARD_COMPAT, GL_TRUE)
window = glfw.CreateWindow(800, 600, 'LearnOpenGL', None)
if window is None:
glfw.Terminate()
exit()
glfw.MakeContextCurrent(window)
glfw.SetFramebufferSizeCallback(window, framebuffer_size_callback())
# Setting up a vertex buffer
verts = glvbo.VBO(
np.array([[0.0, 0.5, 0.0], [0.5, -0.5, 0.0], [-0.5, -0.5, 0.0]], 'f')
)
vbo = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, vbo)
glBufferData(GL_ARRAY_BUFFER, verts.size, verts, GL_STATIC_DRAW)
vao = glGenVertexArrays(1)
glBindVertexArray(vao)
glEnableVertexAttribArray(vao)
glBindBuffer(GL_ARRAY_BUFFER, vbo)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, None)
vertex_shader = """
#version 330 core
in vec3 vp;
void main() {
gl_Position = vec4(vp, 1.0);
}"""
fragment_shader = """
#version 330 core
out vec4 frag_color;
void main() {
frag_color = vec4(0.5, 0.0, 0.5, 1.0);
}"""
vs = glCreateShader(GL_VERTEX_SHADER)
glShaderSource(vs, vertex_shader)
glCompileShader(vs)
if glGetShaderiv(vs, GL_COMPILE_STATUS) != GL_TRUE:
raise Exception("vertex shader did not compile")
fs = glCreateShader(GL_FRAGMENT_SHADER)
glShaderSource(fs, fragment_shader)
glCompileShader(fs)
if glGetShaderiv(fs, GL_COMPILE_STATUS) != GL_TRUE:
raise Exception("fragment shader did not compile")
sp = glCreateProgram()
glAttachShader(sp, fs)
glAttachShader(sp, vs)
glLinkProgram(sp)
if glGetProgramiv(sp, GL_LINK_STATUS) != GL_TRUE:
raise Exception("program did not link")
while not glfw.WindowShouldClose(window):
processInput(window)
glClearColor(0.0, 0.0, 0.0, 1.0)
glClear(GL_COLOR_BUFFER_BIT)
glUseProgram(sp)
glBindVertexArray(vao)
glDrawArrays(GL_TRIANGLES, 0, 3) # This is where things happen
glfw.PollEvents()
glfw.SwapBuffers(window)
glfw.Terminate()
exit()
def framebuffer_size_callback():
glViewport(0, 0, 800, 600)
def processInput(window):
if glfw.GetKey(window, glfw.KEY_ESCAPE) == glfw.PRESS:
glfw.SetWindowShouldClose(window, True)
if __name__ == '__main__': main()
All I want to do at the end of the day, is draw a triangle :(

I determined there were 2 issues.
As BDL mentioned the glEnableVertexAttribArray was not setup appropriately. It needed an index and not a vertex array object.
The glBufferData size was incorrect as the size needed to be provided in bytes. A quick search online revealed that (numpy.size * numpy.itemsize) returns the size of the array.
With these 2 things done... I have a triangle.

Related

Why glVertexAttribPointer throws 1282 error while trying to draw one point on screen with pyOpenGL and glfw?

I have separated the program to three different files, but I don't understand why I get error on glVertexAttribPointer on line 70. I'm using Python 3.10.8
main.py
import glfw
import Shaders
from OpenGL.GL import *
from OpenGL.GLUT import *
from Math_3d import Vector2f
class Window:
def __init__(self, width: int, height: int, title: str):
if not glfw.init():
raise Exception("glfw can not be initialized")
glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3)
glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3)
glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
self._win = glfw.create_window(width, height, title, None, None)
if not self._win:
glfw.terminate()
raise Exception("glfw window can not be created")
glfw.set_window_pos(self._win, 400, 200)
glfw.make_context_current(self._win)
def createshaders(self):
# Request program and shader slots from the GPU
program = glCreateProgram()
vertex = glCreateShader(GL_VERTEX_SHADER)
fragment = glCreateShader(GL_FRAGMENT_SHADER)
# Set shader sources
glShaderSource(vertex, Shaders.vertex_code)
glShaderSource(fragment, Shaders.fragment_code)
# Compile shaders
glCompileShader(vertex)
glCompileShader(fragment)
if not glGetShaderiv(vertex, GL_COMPILE_STATUS):
report_shader = glGetShaderInfoLog(vertex)
print(report_shader)
raise RuntimeError("Vertex shader compilation error")
if not glGetShaderiv(fragment, GL_COMPILE_STATUS):
report_frag = glGetShaderInfoLog(fragment)
print(report_frag)
raise RuntimeError("Fragment shader compilation error")
# Link objects to program
glAttachShader(program, vertex)
glAttachShader(program, fragment)
glLinkProgram(program)
if not glGetProgramiv(program, GL_LINK_STATUS):
print(glGetProgramInfoLog(program))
raise RuntimeError('Linking error')
# Get rid of shaders
glDetachShader(program, vertex)
glDetachShader(program, fragment)
# Make default program to run
glUseProgram(program)
# Vertex Buffer Object
# Create point vertex data
v2f_1 = Vector2f(0.0, 0.0)
# Request a buffer slot from GPU
buffer = glGenBuffers(1)
# Make this buffer the default one
glBindBuffer(GL_ARRAY_BUFFER, buffer)
strides = v2f_1.data.strides[0]
loc = glGetAttribLocation(program, 'position')
glEnableVertexAttribArray(loc)
glVertexAttribPointer(loc, 2, GL_FLOAT, False, strides, None)
# glBufferData(GL_ARRAY_BUFFER, v2f_1, v2f_1, GL_DYNAMIC_DRAW)
def renderscene(self):
while not glfw.window_should_close(self._win):
glfw.poll_events()
glClear(GL_COLOR_BUFFER_BIT)
glDrawArrays(GL_POINTS, 0, 1)
glfw.swap_buffers(self._win)
glfw.terminate()
if __name__ == '__main__':
win = Window(1024, 768, "GLFW Window")
win.createshaders() # Create and initialize shaders and initialize Vertex Buffer Object
win.renderscene() # Swap buffer and render scene
Shaders.py
vertex_code = """
attribute vec2 position;
void main()
{
gl_Position = vec4(position, 0.0, 1.0);
}
"""
fragment_code = """
void main()
{
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
}
"""
Math_3d.py
import numpy as np
class Vector2f:
def __init__(self, x, y):
self.data = np.array([x, y], dtype=np.float32)
if __name__ == '__main__':
vec2 = Vector2f(0.0, 0.0)
print(vec2.data)
print(type(vec2.data.strides[0]))
print(vec2.data.strides[0])
I have tried to debug the line 70, but did not get any good result while using PyCharm.
Any recommendations on this? Closest answers would be according to 61491497 and 56957118 what I am aiming for.
You're using a Core profile OpenGL Context (glfw.OPENGL_CORE_PROFILE). Therefore you have to create a Vertex Array Obejct:
class Window:
# [...]
def createshaders(self):
# [...]
v2f_1 = Vector2f(0.0, 0.0)
# Request a buffer slot from GPU
buffer = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, buffer)
strides = v2f_1.data.strides[0]
glBufferData(GL_ARRAY_BUFFER, v2f_1.data, GL_DYNAMIC_DRAW)
vao = glGenVertexArrays(1)
glBindVertexArray(vao)
loc = glGetAttribLocation(program, 'position')
glEnableVertexAttribArray(loc)
glVertexAttribPointer(loc, 2, GL_FLOAT, False, strides, None)
Additionally, you need to change either the background color or the fragment color, because you won't be able to see a black point on a black background. e.g. red:
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);

glGetError not catching errors

I am trying to render images with OpenGL using a compute shader. I create a compute shader and program for it, then a vertex shader and fragment shader, as well as a program for them. I then create a texture and two triangles and render the texture on the triangles. So far, I have been unable to get the shaders to do anything properly, since glCompileShader seems to not catch when shaders compile incorrectly, so I can't tell what's wrong. I have added glGetError calls after each of my compiling and linking steps to see what the problem might be, but none of them throw errors; all that happens is glUseProgram raises an invalid operation error.
renderShaderSource:
#version 460 core
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(rgba32f, binding = 0) uniform image2D screen;
void main()
}
vertexShaderSource:
#version 460 core
layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 uvs;
out vec2 UVs;
void main()
{
gl_Position = vec4(pos.x, pos.y, pos.z, 1.0);
UVs = uvs;
}
fragmentShaderSource:
#version 460 core
out vec4 FragColor;
uniform sampler2D screen;
in vec2 UVs;
void main()
{
FragColor = texture(screen, UVs);
}
Python code (with excess comments and irrelevant code removed):
class GLWidget(QOpenGLWidget):
width = 100
height = 100
def initializeGL(self):
print('--initializeGL--')
print('GL version', glGetString(GL_VERSION))
# Render shader
renderShader = glCreateShader(GL_COMPUTE_SHADER)
glShaderSource(renderShader, renderShaderSource)
glCompileShader(renderShader)
status = glGetError()
if status != GL_NO_ERROR: raise RuntimeError('Error {} compiling renderShader'.format(status))
# Render program
renderProgram = glCreateProgram()
glAttachShader(renderProgram, renderShader)
glLinkProgram(renderProgram)
status = glGetError()
if status != GL_NO_ERROR: raise RuntimeError('Error {} linking renderProgram'.format(status))
# Vertex shader
vertexShader = glCreateShader(GL_VERTEX_SHADER)
glShaderSource(vertexShader, vertexShaderSource)
glCompileShader(vertexShader)
status = glGetError()
if status != GL_NO_ERROR: raise RuntimeError('Error {} compiling vertexShader'.format(status))
# Fragment shader
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER)
glShaderSource(fragmentShader, fragmentShaderSource)
glCompileShader(fragmentShader)
status = glGetError()
if status != GL_NO_ERROR: raise RuntimeError('Error {} compiling fragmentShader'.format(status))
# Display program
displayProgram = glCreateProgram()
glAttachShader(displayProgram, vertexShader)
glAttachShader(displayProgram, fragmentShader)
glLinkProgram(displayProgram)
status = glGetError()
if status != GL_NO_ERROR: raise RuntimeError('Error {} linking displayProgram'.format(status))
# Texture to render to
screenTex = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, screenTex)
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, self.width, self.height)
glBindImageTexture(0, screenTex, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F)
# Shape to render texture on
self.vertices = numpy.array([
-1.0, -1.0, 0.0, 0.0, 0.0,
-1.0, 1.0, 0.0, 0.0, 1.0,
1.0, 1.0, 0.0, 1.0, 1.0,
1.0, -1.0, 0.0, 1.0, 0.0
], dtype='float32')
# Buffers for rendering shape
vertexArray = glGenVertexArrays(1)
vertexBuffer = glGenBuffers(1)
glBindVertexArray(vertexArray)
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer)
glBufferData(GL_ARRAY_BUFFER, 4 * len(self.vertices), self.vertices, GL_STATIC_DRAW)
glVertexAttribPointer(0, 3, GL_FLOAT, False, 4 * 3, None)
glEnableVertexAttribArray(0)
# Unbind from the vertex buffer and vertex array
glBindBuffer(GL_ARRAY_BUFFER, 0)
glBindVertexArray(0)
self.renderProgram = renderProgram
self.displayProgram = displayProgram
self.vertexArray = vertexArray
self.vertexBuffer = vertexBuffer
def resizeGL(self, width, height):
print('--resizeGL--')
self.width = width
self.height = height
glViewport(0, 0, width, height)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(-1, 1, 1, -1, -1, 1)
def paintGL(self):
print('--paintGL--')
# Run render portion
glUseProgram(self.renderProgram)
glDispatchCompute(self.width, self.height, 1)
glMemoryBarrier(GL_ALL_BARRIER_BITS)
# Run display portion
glClearColor(0.0, 0.0, 0.0, 1.0)
glClear(GL_COLOR_BUFFER_BIT)
glUseProgram(self.displayProgram)
glBindVertexArray(self.vertexArray)
glDrawArrays(GL_TRIANGLES, 0, 6)
It's fairly clear that my compute shader (see renderShaderSource) is the problem in this scenario, I mean it's got mismatched { } things. But when I run the program, glUseProgram errors instead of glGetError:
--initUI--
--initializeGL--
GL version b'4.6 (Compatibility Profile) Mesa 21.2.6'
--resizeGL--
--paintGL--
Traceback (most recent call last):
File "gl.py", line 146, in paintGL
glUseProgram(self.renderProgram)
File "/home/aweso/.local/lib/python3.8/site-packages/OpenGL/platform/baseplatform.py", line 415, in __call__
return self( *args, **named )
File "/home/aweso/.local/lib/python3.8/site-packages/OpenGL/error.py", line 230, in glCheckError
raise self._errorClass(
OpenGL.error.GLError: GLError(
err = 1282,
description = b'invalid operation',
baseOperation = glUseProgram,
cArguments = (2,)
)
--paintGL--
Traceback (most recent call last):
File "gl.py", line 146, in paintGL
glUseProgram(self.renderProgram)
File "/home/aweso/.local/lib/python3.8/site-packages/OpenGL/error.py", line 230, in glCheckError
raise self._errorClass(
OpenGL.error.GLError: GLError(
err = 1282,
description = b'invalid operation',
baseOperation = glUseProgram,
cArguments = (2,)
)
Why did none of the glGetError calls catch that the compute shader failed to compile?
Python 3.8 on Ubuntu 20.04, Intel Core i3-1005G1 with integrated GPU. OpenGL 4.6 Mesa 21.2.6. OpenGL viewport is a PyQt6 QOpenGLWidget
Shader compile errors can't be get with glGetError. You have to call glGetShaderiv/glGetShaderInfoLog to get the compile errors. e.g.:
glCompileShader(renderShader)
if not glGetShaderiv(renderShader, GL_COMPILE_STATUS):
raise RuntimeError(glGetShaderInfoLog(renderShader).replace(b'\\n', b'\n'))
Program link errors can be get with glGetProgramiv/glGetProgramInfoLog. e.g.:
glLinkProgram(displayProgram)
if not glGetProgramiv(displayProgram, GL_LINK_STATUS):
raise RuntimeError(glGetProgramInfoLog(displayProgram).replace(b'\\n', b'\n'))
I also recommend Debug Output. e.g.:
#GLDEBUGPROC
def __CB_OpenGL_DebugMessage(source, type, id, severity, length, message, userParam):
msg = message[0:length]
print(msg.decode("utf-8"))
glDebugMessageCallback(__CB_OpenGL_DebugMessage, None)
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, None, GL_TRUE)
glEnable(GL_DEBUG_OUTPUT)
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS)

PySide2 OpenGL error when using custom QSurfaceFormat

I'm using QSurfaceFormat to explicitly define OpenGL Core profile and set minor/major versions. The thing is, assignment of a custom surface format gives me the following error:
Traceback (most recent call last):
File "/home/artem/PycharmProjects/PolyEdit3D/PolyEdit3D/Widgets/PlyViewport.py", line 22, in initializeGL
gl.glEnable(gl.GL_COLOR_BUFFER_BIT)
File "/home/artem/.local/lib/python3.7/site-packages/OpenGL/platform/baseplatform.py", line 415, in __call__
return self( *args, **named )
File "src/errorchecker.pyx", line 58, in OpenGL_accelerate.errorchecker._ErrorChecker.glCheckError
OpenGL.error.GLError: GLError(
err = 1280,
description = b'invalid enumerant',
baseOperation = glEnable,
cArguments = (GL_COLOR_BUFFER_BIT,)
)
Traceback (most recent call last):
File "/home/artem/PycharmProjects/PolyEdit3D/PolyEdit3D/Widgets/PlyViewport.py", line 69, in paintGL
gl.glDrawElements(gl.GL_TRIANGLES, 6, gl.GL_UNSIGNED_INT, ctypes.c_void_p(0))
File "src/latebind.pyx", line 39, in OpenGL_accelerate.latebind.LateBind.__call__
File "src/wrapper.pyx", line 318, in OpenGL_accelerate.wrapper.Wrapper.__call__
File "src/wrapper.pyx", line 311, in OpenGL_accelerate.wrapper.Wrapper.__call__
File "/home/artem/.local/lib/python3.7/site-packages/OpenGL/platform/baseplatform.py", line 415, in __call__
return self( *args, **named )
File "src/errorchecker.pyx", line 58, in OpenGL_accelerate.errorchecker._ErrorChecker.glCheckError
OpenGL.error.GLError: GLError(
err = 1282,
description = b'invalid operation',
baseOperation = glDrawElements,
pyArgs = (
GL_TRIANGLES,
6,
GL_UNSIGNED_INT,
c_void_p(None),
),
cArgs = (
GL_TRIANGLES,
6,
GL_UNSIGNED_INT,
c_void_p(None),
),
cArguments = (
GL_TRIANGLES,
6,
GL_UNSIGNED_INT,
c_void_p(None),
)
)
As you can see there's an error in gl.glEnable(gl.GL_COLOR_BUFFER_BIT) and other simple things. Without specifying QSurfaceFormat everything works like a charm.
Here's my surface format class:
class GLSurfaceFormat(QtGui.QSurfaceFormat):
def __init__(self):
super(GLSurfaceFormat, self).__init__()
self.__initSurface()
def __initSurface(self):
self.setRenderableType(QtGui.QSurfaceFormat.OpenGL)
self.setMinorVersion(3)
self.setMajorVersion(4)
self.setProfile(QtGui.QSurfaceFormat.CoreProfile)
self.setColorSpace(QtGui.QSurfaceFormat.sRGBColorSpace)
self.setSwapBehavior(QtGui.QSurfaceFormat.DoubleBuffer)
Here's how I assign it:
QApplication.setAttribute(Qt.AA_UseDesktopOpenGL)
QSurfaceFormat.setDefaultFormat(GLSurfaceFormat())
app = QApplication(sys.argv)
...
Could you tell me, is there any mistake in QSurfaceFormat usage or maybe there's something else?
!UPDATE!
Here's a quick example where you can reproduce the same behavior:
from PySide2 import QtCore, QtGui, QtWidgets
from OpenGL import GL as gl
from OpenGL.GL.shaders import compileProgram, compileShader
import numpy as np
import ctypes
import sys
import glm
class PlyViewportWidget(QtWidgets.QOpenGLWidget):
def __init__(self):
super(PlyViewportWidget, self).__init__(parent=None)
self.vao = None
self.vbo = None
self.ebo = None
self.shaderProg = None
self.isWireframe = False
def initializeGL(self):
gl.glEnable(gl.GL_COLOR_BUFFER_BIT)
gl.glClearColor(0.4, 0.4, 0.4, 1)
with open("fragment.glsl", 'r') as f:
fragment = compileShader(f.read(), gl.GL_FRAGMENT_SHADER)
with open("vertex.glsl", "r") as f:
vertex = compileShader(f.read(), gl.GL_VERTEX_SHADER)
self.shaderProg = compileProgram(vertex, fragment)
vertices = np.array(
[
0.5, 0.5, 0.0,
0.5, -0.5, 0.0,
-0.5, -0.5, 0.0,
-0.5, 0.5, 0.0
], dtype=ctypes.c_float
)
indices = np.array(
[
0, 1, 3,
1, 2, 3
], dtype=ctypes.c_uint
)
self.vbo = gl.glGenBuffers(1)
self.ebo = gl.glGenBuffers(1)
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.vbo)
gl.glBufferData(gl.GL_ARRAY_BUFFER, vertices.nbytes, vertices, gl.GL_STATIC_DRAW)
gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, self.ebo)
gl.glBufferData(gl.GL_ELEMENT_ARRAY_BUFFER, indices.nbytes, indices, gl.GL_STATIC_DRAW)
gl.glEnableVertexAttribArray(0)
gl.glVertexAttribPointer(0, 3, gl.GL_FLOAT, gl.GL_FALSE, 3 * ctypes.sizeof(ctypes.c_float), ctypes.c_void_p(0))
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0)
gl.glBindVertexArray(0)
gl.glUseProgram(self.shaderProg)
def paintGL(self):
gl.glClearColor(0.4, 0.4, 0.4, 1.0)
gl.glClear(gl.GL_COLOR_BUFFER_BIT)
trans = self.getTransformMatrix()
#u_transform = gl.glGetUniformLocation(self.shaderProg, "u_transform")
#gl.glUniformMatrix4fv(u_transform, 1, gl.GL_FALSE, u_transform)
gl.glBindVertexArray(self.vao)
gl.glDrawElements(gl.GL_TRIANGLES, 6, gl.GL_UNSIGNED_INT, ctypes.c_void_p(0))
def resizeGL(self, w:int, h:int):
gl.glViewport(0, 0, w, h)
def keyPressEvent(self, event:QtGui.QKeyEvent):
self.makeCurrent()
if event.key() == QtCore.Qt.Key_Z and not self.isWireframe:
gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_LINE)
self.isWireframe = True
self.update()
elif event.key() == QtCore.Qt.Key_Z and self.isWireframe:
gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL)
self.isWireframe = False
self.update()
event.accept()
def getTransformMatrix(self):
return glm.rotate(glm.mat4(1.0), glm.radians(90.0), glm.vec3(1.0, 0.0, 0.0))
class GLSurfaceFormat(QtGui.QSurfaceFormat):
def __init__(self):
super(GLSurfaceFormat, self).__init__()
self.__initSurface()
def __initSurface(self):
self.setRenderableType(QtGui.QSurfaceFormat.OpenGL)
self.setMinorVersion(3)
self.setMajorVersion(4)
self.setProfile(QtGui.QSurfaceFormat.CoreProfile)
self.setColorSpace(QtGui.QSurfaceFormat.sRGBColorSpace)
self.setSwapBehavior(QtGui.QSurfaceFormat.DoubleBuffer)
if __name__ == '__main__':
QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseDesktopOpenGL)
# Uncomment to get this damn error!!!
#QtGui.QSurfaceFormat.setDefaultFormat(GLSurfaceFormat())
app = QtWidgets.QApplication(sys.argv)
window = PlyViewportWidget()
window.show()
sys.exit(app.exec_())
vertex.glsl
#version 330 core
layout (location = 0) in vec3 aPos;
void main()
{
gl_Position = vec4(aPos, 1.0);
}
fragment.glsl
#version 330 core
out vec4 FragColor;
void main()
{
FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}
GL_COLOR_BUFFER_BIT is not a valid enumeration constant for glEnable, but it is a proper argument for glClear.
Invoke glClear, after the clear color is set by glClearColor:
class PlyViewportWidget(QtWidgets.QOpenGLWidget):
# [...]
def initializeGL(self):
#gl.glEnable(gl.GL_COLOR_BUFFER_BIT) <---- DELETE
gl.glClearColor(0.4, 0.4, 0.4, 1)
gl.glClear(gl.GL_COLOR_BUFFER_BIT) # <---- ADD
You missed to create the named Vertex Array Object:
class PlyViewportWidget(QtWidgets.QOpenGLWidget):
# [...]
def initializeGL(self):
# [...]
self.vao = gl.glGenVertexArrays(1) # <---
gl.glBindVertexArray(self.vao) # <---
self.vbo = gl.glGenBuffers(1)
self.ebo = gl.glGenBuffers(1)
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.vbo)
gl.glBufferData(gl.GL_ARRAY_BUFFER, vertices.nbytes, vertices, gl.GL_STATIC_DRAW)
gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, self.ebo)
gl.glBufferData(gl.GL_ELEMENT_ARRAY_BUFFER, indices.nbytes, indices, gl.GL_STATIC_DRAW)
gl.glEnableVertexAttribArray(0)
gl.glVertexAttribPointer(0, 3, gl.GL_FLOAT, gl.GL_FALSE, 3 * ctypes.sizeof(ctypes.c_float), ctypes.c_void_p(0))
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0)
gl.glBindVertexArray(0)

How to rotate the triangle with Modern OpenGL and Python

I have written a code to render a triangle using a shader program. I want to rotate the triangle. I'm using PyGLM to set a transformation matrix. Here I'm presenting the whole code. If I run this code a triangle is appearing in the window as expected, but there is no rotation. I think I've failed to pass the transformation matrix to the buffer.
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
from OpenGL.GL import shaders
import numpy as np
import glm
VERTEX_SHADER = """
#version 330
in vec4 position;
in vec3 color;
out vec3 newColor;
void main()
{
gl_Position = position;
newColor = color;
}
"""
FRAGMENT_SHADER = """
#version 330
in vec3 newColor;
out vec4 outColor;
void main()
{
outColor = vec4(newColor,1.0f);
}
"""
shaderProgram = None
def initliaze():
global VERTEXT_SHADER
global FRAGMEN_SHADER
global shaderProgram
vertexshader = shaders.compileShader(VERTEX_SHADER, GL_VERTEX_SHADER)
fragmentshader = shaders.compileShader(FRAGMENT_SHADER, GL_FRAGMENT_SHADER)
shaderProgram = shaders.compileProgram(vertexshader, fragmentshader)
triangles = [-0.5, -0.5, 0.0, 1.0,0.0,0.0,
0.5, -0.5, 0.0, 0.0,1.0,0.0,
0.0, 0.5, 0.0, 0,0,0.0,1.0]
triangles = np.array(triangles, dtype=np.float32)
VBO = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, VBO)
glBufferData(GL_ARRAY_BUFFER, triangles.nbytes, triangles, GL_DYNAMIC_DRAW)
position = glGetAttribLocation(shaderProgram, 'position')
glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, 24, ctypes.c_void_p(0))
glEnableVertexAttribArray(position)
color = glGetAttribLocation(shaderProgram, 'color')
glVertexAttribPointer(color, 3, GL_FLOAT, GL_FALSE, 24, ctypes.c_void_p(12))
glEnableVertexAttribArray(color)
def render():
global shaderProgram
global angle
#shader
glUseProgram(shaderProgram)
glClearColor(0, 0, 0, 1)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
#transform matrix
transform = glm.mat4(1)
transform = glm.translate(transform, glm.vec3(0.5,-0.5,0.0))
transform = glm.rotate(transform, glutGet(GLUT_ELAPSED_TIME),glm.vec3(0,0,1))
transformLoc = glGetUniformLocation(shaderProgram,"transform")
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm.value_ptr(transform))
#render program
glDrawArrays(GL_TRIANGLES, 0, 3)
glUseProgram(0)
glutSwapBuffers()
def main():
glutInit([])
glutInitWindowSize(640, 480)
glutCreateWindow("pyopengl with glut 2")
initliaze()
glutDisplayFunc(render)
glutMainLoop()
if __name__ == '__main__':
main()
In VERTEX_SHADER you didn't mentioned transform variable. So your triangle position remain fixed after you run the program. Change your VERTEX_SHADER as following.
VERTEX_SHADER = """
#version 330
in vec4 position;
in vec3 color;
out vec3 newColor;
uniform mat4 transform;
void main()
{
gl_Position = transform*position;
newColor = color;
}
"""
In your code you are accessing the location of location of a uniform variable transform by following line.
transformLoc = glGetUniformLocation(shaderProgram,"transform")
You should add glutPostRedisplay() function after the glutSwapBuffers() function to visualize the continuous change.
Looks like you will want to create your own library from GLM. What you're doing in the code above no longer works. As another user stated, this is a good template to build functionality from. I'd suggest downloading GLM, taking it apart, and reverse engineering what you need into Python.

Looking for a simple OpenGL (3.2+) Python example that uses GLFW [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking us to recommend or find a tool, library or favorite off-site resource are off-topic for Stack Overflow as they tend to attract opinionated answers and spam. Instead, describe the problem and what has been done so far to solve it.
Closed 9 years ago.
Improve this question
I am looking for a simple modern OpenGL (3.2+)example in Python.
I tried with GLUT and freeGLUT, but I am not able to get a 3.2 context on OS X (Mavericks). (This seems to be a known issue with GLUT/freeGLUT).
GLFW seems to be a modern lightweight alternative to GLUT, but it doesn't seem to have an official Python binding, and I could not find a simple example that uses 3.2 core profile features of OpenGL with GLFW and Python.
(I struggled with this problem, and so it could be useful for others, I am answering below as per SO guidelines.)
The code below uses PyOpenGL, PIL (for textures), numpy, GLFW and the corresponding Python binding cyglfw3.
Here is a screenshot of the output:
The main code is appended below. It uses some utility methods from a file called glutils.py (for loading texture, compiling shaders, etc.) which you can find here:
https://github.com/electronut/pp/tree/master/simplegl
Code listing follows:
import OpenGL
from OpenGL.GL import *
from OpenGL.GLUT import *
import numpy, math, sys, os
import glutils
import cyglfw3 as glfw
strVS = """
#version 330 core
layout(location = 0) in vec3 aVert;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
uniform vec4 uColor;
uniform float uTheta;
out vec4 vCol;
out vec2 vTexCoord;
void main() {
// rotational transform
mat4 rot = mat4(
vec4( cos(uTheta), sin(uTheta), 0.0, 0.0),
vec4(-sin(uTheta), cos(uTheta), 0.0, 0.0),
vec4(0.0, 0.0, 1.0, 0.0),
vec4(0.0, 0.0, 0.0, 1.0)
);
// transform vertex
gl_Position = uPMatrix * uMVMatrix * rot * vec4(aVert, 1.0);
// set color
vCol = vec4(uColor.rgb, 1.0);
// set texture coord
vTexCoord = aVert.xy + vec2(0.5, 0.5);
}
"""
strFS = """
#version 330 core
in vec4 vCol;
in vec2 vTexCoord;
uniform sampler2D tex2D;
uniform bool showCircle;
out vec4 fragColor;
void main() {
if (showCircle) {
// discard fragment outside circle
if (distance(vTexCoord, vec2(0.5, 0.5)) > 0.5) {
discard;
}
else {
fragColor = texture(tex2D, vTexCoord);
}
}
else {
fragColor = texture(tex2D, vTexCoord);
}
}
"""
class Scene:
""" OpenGL 3D scene class"""
# initialization
def __init__(self):
# create shader
self.program = glutils.loadShaders(strVS, strFS)
glUseProgram(self.program)
self.pMatrixUniform = glGetUniformLocation(self.program,
'uPMatrix')
self.mvMatrixUniform = glGetUniformLocation(self.program,
"uMVMatrix")
self.colorU = glGetUniformLocation(self.program, "uColor")
# color
self.col0 = [1.0, 0.0, 0.0, 1.0]
# texture
self.tex2D = glGetUniformLocation(self.program, "tex2D")
# define quad vertices
quadV = [
-0.5, -0.5, 0.0,
0.5, -0.5, 0.0,
-0.5, 0.5, 0.0,
0.5, 0.5, 0.0
]
# set up vertex array object (VAO)
self.vao = glGenVertexArrays(1)
glBindVertexArray(self.vao)
# vertices
self.vertexBuffer = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, self.vertexBuffer)
vertexData = numpy.array(quadV, numpy.float32)
glBufferData(GL_ARRAY_BUFFER, 4*len(vertexData), vertexData,
GL_STATIC_DRAW)
# enable vertex array
glEnableVertexAttribArray(0)
# set buffer data
glBindBuffer(GL_ARRAY_BUFFER, self.vertexBuffer)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, None)
# unbind VAO
glBindVertexArray(0)
# time
self.t = 0
# texture
self.texId = glutils.loadTexture('test.png')
# show circle?
self.showCircle = False
# step
def step(self):
# increment angle
self.t = (self.t + 1) % 360
# set shader angle in radians
glUniform1f(glGetUniformLocation(self.program, 'uTheta'),
math.radians(self.t))
# render
def render(self, pMatrix, mvMatrix):
# use shader
glUseProgram(self.program)
# set proj matrix
glUniformMatrix4fv(self.pMatrixUniform, 1, GL_FALSE, pMatrix)
# set modelview matrix
glUniformMatrix4fv(self.mvMatrixUniform, 1, GL_FALSE, mvMatrix)
# show circle?
glUniform1i(glGetUniformLocation(self.program, 'showCircle'),
self.showCircle)
# enable texture
glActiveTexture(GL_TEXTURE0)
glBindTexture(GL_TEXTURE_2D, self.texId)
glUniform1i(self.tex2D, 0)
# bind VAO
glBindVertexArray(self.vao)
# draw
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)
# unbind VAO
glBindVertexArray(0)
class RenderWindow:
"""GLFW Rendering window class"""
def __init__(self):
# save current working directory
cwd = os.getcwd()
# initialize glfw - this changes cwd
glfw.Init()
# restore cwd
os.chdir(cwd)
# version hints
glfw.WindowHint(glfw.CONTEXT_VERSION_MAJOR, 3)
glfw.WindowHint(glfw.CONTEXT_VERSION_MINOR, 3)
glfw.WindowHint(glfw.OPENGL_FORWARD_COMPAT, GL_TRUE)
glfw.WindowHint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
# make a window
self.width, self.height = 640, 480
self.aspect = self.width/float(self.height)
self.win = glfw.CreateWindow(self.width, self.height, "test")
# make context current
glfw.MakeContextCurrent(self.win)
# initialize GL
glViewport(0, 0, self.width, self.height)
glEnable(GL_DEPTH_TEST)
glClearColor(0.5, 0.5, 0.5,1.0)
# set window callbacks
glfw.SetMouseButtonCallback(self.win, self.onMouseButton)
glfw.SetKeyCallback(self.win, self.onKeyboard)
glfw.SetWindowSizeCallback(self.win, self.onSize)
# create 3D
self.scene = Scene()
# exit flag
self.exitNow = False
def onMouseButton(self, win, button, action, mods):
#print 'mouse button: ', win, button, action, mods
pass
def onKeyboard(self, win, key, scancode, action, mods):
#print 'keyboard: ', win, key, scancode, action, mods
if action == glfw.PRESS:
# ESC to quit
if key == glfw.KEY_ESCAPE:
self.exitNow = True
else:
# toggle cut
self.scene.showCircle = not self.scene.showCircle
def onSize(self, win, width, height):
#print 'onsize: ', win, width, height
self.width = width
self.height = height
self.aspect = width/float(height)
glViewport(0, 0, self.width, self.height)
def run(self):
# initializer timer
glfw.SetTime(0.0)
t = 0.0
while not glfw.WindowShouldClose(self.win) and not self.exitNow:
# update every x seconds
currT = glfw.GetTime()
if currT - t > 0.1:
# update time
t = currT
# clear
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
# build projection matrix
pMatrix = glutils.perspective(45.0, self.aspect, 0.1, 100.0)
mvMatrix = glutils.lookAt([0.0, 0.0, -2.0], [0.0, 0.0, 0.0],
[0.0, 1.0, 0.0])
# render
self.scene.render(pMatrix, mvMatrix)
# step
self.scene.step()
glfw.SwapBuffers(self.win)
# Poll for and process events
glfw.PollEvents()
# end
glfw.Terminate()
# main() function
def main():
print 'starting simpleglfw...'
rw = RenderWindow()
rw.run()
# call main
if __name__ == '__main__':
main()

Categories