为啥使用 GTKGLArea 时在 PyOpenGL 中未定义 glGenVertexArrays
Posted
技术标签:
【中文标题】为啥使用 GTKGLArea 时在 PyOpenGL 中未定义 glGenVertexArrays【英文标题】:Why is glGenVertexArrays undefined in PyOpenGL when using GTKGLArea为什么使用 GTKGLArea 时在 PyOpenGL 中未定义 glGenVertexArrays 【发布时间】:2017-02-12 08:47:46 【问题描述】:我有下面的测试代码,我试图让一个基本的 opengl Gtk3 GLArea 示例正常工作。
下面的错误目前是我的症结所在,从我所读到的内容来看,这可能意味着这些功能不适用于上下文,但阅读 GLArea 它似乎并没有让您选择上下文,听起来它应该默认为正确的一个。
问题可能出在 GLArea 或 PyOpenGL 上,不幸的是,我目前可以使用的所有示例都在 C 中,很高兴获得一个在 python 中工作的基本示例。
无论如何,我花了很多时间试图解决这个问题,所以如果有人能帮助克服至少这个错误,那就太好了。
Traceback (most recent call last):
File "gtkglarea.py", line 91, in on_configure_event
self.vertex_array_object = glGenVertexArrays(1)
File "/usr/lib/python3/dist-packages/OpenGL/platform/baseplatform.py", line 407, in call
self.name, self.name,
OpenGL.error.NullFunctionError: Attempt to call an undefined function glGenVertexArrays, check for bool(glGenVertexArrays) before calling
例如,它也是一个要点https://gist.github.com/olymk2/5b3e49ac83130e580bd9983f2e5d49c3
#!/usr/bin/python
import os
import sys
from OpenGL.GLU import *
from OpenGL import GLX
from OpenGL import GL as GL
from ctypes import *
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk
from OpenGL.arrays import vbo
from OpenGL.GL import shaders
from OpenGL.raw.GL.ARB.vertex_array_object import glGenVertexArrays, \
glBindVertexArray
from numpy import array
import numpy as np
VERTEX_SHADER = """
#version 330
in vec4 position;
void main()
gl_Position = position;
"""
FRAGMENT_SHADER = """
#version 330
out vec4 fragColor;
void main()
fragColor = vec4(1.0, 0.0, 0.0, 1.0);
"""
class application_gui:
"""Tutorial 01 Create and destroy a window"""
# glwrap = gtkglarea()
def __init__(self):
self.window = Gtk.Window()
self.canvas = Gtk.GLArea()
self.canvas.set_required_version(3, 3)
self.test_features()
self.vertices = [
0.6, 0.6, 0.0, 1.0,
-0.6, 0.6, 0.0, 1.0,
0.0, -0.6, 0.0, 1.0]
self.vertices = np.array(self.vertices, dtype=np.float32)
self.canvas.connect('realize', self.on_configure_event)
self.canvas.connect('render', self.on_draw)
self.canvas.set_double_buffered(False)
self.window.connect('delete_event', Gtk.main_quit)
self.window.connect('destroy', lambda quit: Gtk.main_quit())
self.window.add(self.canvas)
self.window.show_all()
self.on_configure_event(self.canvas)
def test_features(self):
print('Testing features')
print('glGenVertexArrays Available %s' % bool(glGenVertexArrays))
print('Alpha Available %s' % bool(self.canvas.get_has_alpha()))
print('Depth buffer Available %s' % bool(self.canvas.get_has_depth_buffer()))
def on_configure_event(self, widget):
print('realize event')
widget.make_current()
# widget.attach_buffers()
context = widget.get_context()
print('is legacy context %s' % Gdk.GLContext.is_legacy(context))
print('configure errors')
print(widget.get_error())
vs = shaders.compileShader(VERTEX_SHADER, GL.GL_VERTEX_SHADER)
fs = shaders.compileShader(FRAGMENT_SHADER, GL.GL_FRAGMENT_SHADER)
self.shader = shaders.compileProgram(vs, fs)
self.vertex_array_object = glGenVertexArrays(1)
GL.glBindVertexArray( self.vertex_array_object )
# Generate buffers to hold our vertices
self.vertex_buffer = GL.glGenBuffers(1)
GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.vertex_buffer)
# Get the position of the 'position' in parameter of our shader and bind it.
self.position = GL.glGetAttribLocation(self.shader, 'position')
GL.glEnableVertexAttribArray(self.position)
# Describe the position data layout in the buffer
GL.glVertexAttribPointer(self.position, 4, GL.GL_FLOAT, False, 0, ctypes.c_void_p(0))
# Send the data over to the buffer
GL.glBufferData(GL.GL_ARRAY_BUFFER, 48, self.vertices, GL.GL_STATIC_DRAW)
# Unbind the VAO first (Important)
GL.glBindVertexArray( 0 )
# Unbind other stuff
GL.glDisableVertexAttribArray(self.position)
GL.glBindBuffer(GL.GL_ARRAY_BUFFER, 0)
print('errors')
print(widget.get_error())
return True
def on_draw(self, widget, *args):
print('render event')
print(widget.get_error())
#Create the VBO
widget.attach_buffers()
GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
GL.glUseProgram(self.shader)
GL.glBindVertexArray( self.vertex_array_object )
GL.glDrawArrays(GL.GL_TRIANGLES, 0, 3)
GL.glBindVertexArray( 0 )
GL.glUseProgram(0)
glFlush()
return True
application = application_gui()
Gtk.main()
【问题讨论】:
您确定您的 GL 实现和请求的上下文确实支持这些功能吗? 很可能不是,这也是之前我会选择上下文的困惑的一部分,但现在 GLArea 发生了魔法,我看不到为小部件选择上下文的方法,以前我是使用 xsome xlib 代码帮助选择上下文。 developer.gnome.org/gtk3/unstable/GtkGLArea.html 【参考方案1】:对我来说,问题似乎与在 Wayland 下运行有关。看起来如果 PyOpenGL 在 Wayland 下运行并且有一个 X11 服务器正在运行,它将使用 GLX 而不是 Wayland 的 EGL 支持。 GtkGLArea 如何设置 GL 上下文意味着 GLX 可以工作,但没有任何 GL 扩展,包括 VAO。这似乎是 PyOpenGL 中的一个错误。
有两种方法可以解决这个问题:
设置 PYOPENGL_PLATFORM
以强制 PyOpenGL 使用 EGL 而不是 GLX。
例如在导入 OpenGL 之前:
if 'WAYLAND_DISPLAY' in os.environ and 'PYOPENGL_PLATFORM' not in os.environ:
os.environ['PYOPENGL_PLATFORM'] = 'egl'
取消设置 WAYLAND_DISPLAY
以强制 Gtk 使用 GLX 而不是 EGL。
例如在导入 Gtk 之前:
if 'WAYLAND_DISPLAY' in os.environ:
del os.environ['WAYLAND_DISPLAY']
【讨论】:
【参考方案2】:下面是完整的工作示例,在@derhass 的评论之后,我进行了一些搜索,发现 Gdk.Screen 为什么在我之前发现的示例中没有使用它,我不知道。
拼图缺少的部分是这 3 行
screen = Gdk.Screen.get_default()
visual = Gdk.Screen.get_rgba_visual(screen)
self.window = Gtk.Window()
Gtk.Widget.set_visual(self.window, visual)
完整的工作示例,应在如下所示的窗口中显示您的基本三角形。
#!/usr/bin/python
# noqa: E402
import gi
gi.require_version('Gtk', '3.0')
import numpy as np
from gi.repository import Gtk, Gdk
from OpenGL.GLU import *
from OpenGL import GL as GL
from OpenGL.GL import shaders
from OpenGL.raw.GL.ARB.vertex_array_object import glGenVertexArrays, \
glBindVertexArray
# from numpy import array
VERTEX_SHADER = """
#version 330
in vec4 position;
void main()
gl_Position = position;
"""
FRAGMENT_SHADER = """
#version 330
out vec4 fragColor;
void main()
fragColor = vec4(1.0, 0.0, 0.0, 1.0);
"""
class application_gui:
"""Tutorial 01 Create and destroy a window"""
# glwrap = gtkglarea()
def __init__(self):
screen = Gdk.Screen.get_default()
visual = Gdk.Screen.get_rgba_visual(screen)
print('is composite %s' % Gdk.Screen.is_composited(screen))
self.window = Gtk.Window()
Gtk.Widget.set_visual(self.window, visual)
self.canvas = Gtk.GLArea()
self.canvas.set_required_version(3, 3)
self.test_features()
self.vertices = [
0.6, 0.6, 0.0, 1.0,
-0.6, 0.6, 0.0, 1.0,
0.0, -0.6, 0.0, 1.0]
self.vertices = np.array(self.vertices, dtype=np.float32)
self.canvas.connect('realize', self.on_configure_event)
self.canvas.connect('render', self.on_draw)
self.canvas.set_double_buffered(False)
self.window.connect('delete_event', Gtk.main_quit)
self.window.connect('destroy', lambda quit: Gtk.main_quit())
self.window.add(self.canvas)
self.window.show_all()
def test_features(self):
print('Testing features')
print('glGenVertexArrays Available %s' % bool(glGenVertexArrays))
print('Alpha Available %s' % bool(self.canvas.get_has_alpha()))
print('Depth buffer Available %s' % bool(self.canvas.get_has_depth_buffer()))
def on_configure_event(self, widget):
print('realize event')
widget.make_current()
print(widget.get_error())
vs = shaders.compileShader(VERTEX_SHADER, GL.GL_VERTEX_SHADER)
fs = shaders.compileShader(FRAGMENT_SHADER, GL.GL_FRAGMENT_SHADER)
self.shader = shaders.compileProgram(vs, fs)
# Create a new Vertex Array Object
self.vertex_array_object = GL.glGenVertexArrays(1)
GL.glBindVertexArray(self.vertex_array_object )
# Generate a new array buffers for our vertices
self.vertex_buffer = GL.glGenBuffers(1)
GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.vertex_buffer)
# Get position variable form the shader and store
self.position = GL.glGetAttribLocation(self.shader, 'position')
GL.glEnableVertexAttribArray(self.position)
# describe the data layout
GL.glVertexAttribPointer(self.position, 4, GL.GL_FLOAT, False, 0, ctypes.c_void_p(0))
# Copy data to the buffer
GL.glBufferData(GL.GL_ARRAY_BUFFER, 48, self.vertices, GL.GL_STATIC_DRAW)
# Unbind buffers once done
GL.glBindVertexArray( 0 )
GL.glDisableVertexAttribArray(self.position)
GL.glBindBuffer(GL.GL_ARRAY_BUFFER, 0)
return True
def on_draw(self, widget, *args):
print('render event')
print(widget.get_error())
# clear screen and select shader for drawing
GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
GL.glUseProgram(self.shader)
# bind and draw vertices
GL.glBindVertexArray(self.vertex_array_object)
GL.glDrawArrays(GL.GL_TRIANGLES, 0, 3)
GL.glBindVertexArray(0)
GL.glUseProgram(0)
GL.glFlush()
return True
application = application_gui()
Gtk.main()
【讨论】:
【参考方案3】:在使用 PyOpenGL 和 glfw 时遇到此错误,修复为 glfw.make_context_current(window)
。
【讨论】:
以上是关于为啥使用 GTKGLArea 时在 PyOpenGL 中未定义 glGenVertexArrays的主要内容,如果未能解决你的问题,请参考以下文章
GtkGLArea:未找到 GL_ARB_create_context_profile 扩展
为啥在使用 Promise 时在类方法中未定义“this”? [复制]
为啥在获取系统时间时在这里使用`atomic_signal_fence`