2017-02-12 56 views
1

我在下面的测试代码中试图获得一个基本的opengl Gtk3 GLArea示例。为什么在使用GTKGLArea时,PyGenVertexArrays在PyOpenGL中未定义

下面的错误是我目前的难点,从我已阅读这可能意味着功能是不可用的上下文,但阅读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() 
+0

你确定你的GL实现_and_实际要求的情况下支持这些功能? – derhass

+0

很可能不是,那是我以前选择上下文的困惑的一部分,但现在有GLArea正在进行的魔术,我没有看到为小部件选择上下文的方式,以前我使用xsome xlib代码来帮助选择上下文。 https://developer.gnome.org/gtk3/unstable/GtkGLArea。html – Oly

+0

就像我在Python路径中使用这个PYOPENGL_PLATFORM =“EGL”前缀在路上打了一个注解,解决了这个问题,如果它使用osmesa作为平台,我会遇到上述错误。 – Oly

回答

1

对于我来说,这个问题似乎与韦兰下运行。看起来,如果PyOpenGL在Wayland下运行,并且运行了X11服务器,它将使用GLX而不是Wayland的EGL支持。关于GtkGLArea如何设置GL上下文的一些事情意味着GLX的工作原理,但没有任何GL扩展,其中包括VAO。这看起来像是PyOpenGL中的一个错误。

有两种方法来解决此问题:

  1. 设置PYOPENGL_PLATFORM强制PyOpenGL使用EGL而不是GLX。

    E.g.导入的OpenGL前:

    if 'WAYLAND_DISPLAY' in os.environ and 'PYOPENGL_PLATFORM' not in os.environ: 
        os.environ['PYOPENGL_PLATFORM'] = 'egl' 
    
  2. 取消设置WAYLAND_DISPLAY强制GTK来使用,而不是GLX东瀛。

    E.g.之前进口的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) 

完整的工作样本,应该在它看起来像这样一个窗口,显示你的基本三角形。

enter image description here

#!/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() 
相关问题