【问题标题】:Use of the Gtk.GLArea in Pygobject GTK3Pygobject GTK3 中 Gtk.GLArea 的使用
【发布时间】:2017-11-30 04:28:08
【问题描述】:

使用 Gtk3 的 python 包装器的文档有些有限。我找到了几个常见的小部件示例。我正在尝试使用 Gtk.GLArea 小部件。 API 文档是针对 C 语言的,我没有太多运气来猜测使用这个小部件的等效 python 调用。在示例中,小部件是使用以下 C 代码创建的:

 // create a GtkGLArea instance
GtkWidget *gl_area = gtk_gl_area_new ();
g_signal_connect (gl_area, "render", G_CALLBACK (render), NULL);

那么渲染函数里面有OpenGL命令:

static gboolean
render (GtkGLArea *area, GdkGLContext *context)
{
  // inside this function it's safe to use GL; the given
  // #GdkGLContext has been made current to the drawable
  // surface used by the #GtkGLArea and the viewport has
  // already been set to be the size of the allocation

  // we can start by clearing the buffer
  glClearColor (0, 0, 0, 0);
  glClear (GL_COLOR_BUFFER_BIT);

  // draw your object
  draw_an_object ();

  // we completed our drawing; the draw commands will be
  // flushed at the end of the signal emission chain, and
  // the buffers will be drawn on the window
  return TRUE;
}

我的问题是你如何在 python 中做同样的事情?

这是我的尝试:

class RootWidget(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self, title='GL Example')
        self.set_default_size(800,500)
        gl = Gtk.GLArea()
        gl.connect("render", self.gl_render)
        self.add(gl)


    def gl_render(self, gl):
        print(gl)
        Gtk.glClearColor(0,0,0,1)
        Gtk.glClear(Gtk.GL_COLOR_BUFFER_BIT)
        return True

您会注意到我添加了“Gtk”。到 gl 命令。不确定这是否正确,但 python 不知道函数中的 glClearColor 是什么。我对 C 命名空间不是很熟悉,但我也不知道 C 函数如何理解 gl 命令是什么。该程序确实运行,我在控制台中收到以下错误:

不支持FB设置

(python.exe:120048): Gdk-WARNING **: 片段编译失败 着色器:

错误:0:5:'gl_FragColor':未声明的标识符

错误:0:5:'texture2D':找不到匹配的重载函数(使用 隐式转换)

对此的任何意见都会很有用。我希望能够使用 opengl 命令在固定的小部件区域进行绘制。

编辑: 这是我最近的尝试。在on_render() 函数中,我打印上下文,我确实看到上下文属性设置为<gtk.gdk.Win32GLContext object at 0x3f133f0>,并且调试确实表明这是当前上下文。问题是我仍然得到相同的着色器、Frag_Color 和纹理错误,而且我什至没有调用任何 gl 命令。

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from OpenGL.GL import *
from OpenGL.GLU import *


class MyGLArea(Gtk.GLArea):
    def __init__(self):
        Gtk.GLArea.__init__(self)
        self.connect("realize", self.on_realize)


    def on_realize(self, area):
        ctx = self.get_context()
        ctx.make_current()
        print("The context is {}".format(self.get_property("context")))
        err = self.get_error()
        if err:
            print(err)
        return



class RootWidget(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self, title='GL Example')
        self.set_default_size(800,500)
        gl_area = MyGLArea()
        self.add(gl_area)


win = RootWidget()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()

编辑 2: 好像我只是遇到了 GLArea 小部件的安装问题。看起来很奇怪,因为我使用了 30 多个不同的 Gtk 小部件而没有问题。我有错误只是添加小部件,甚至没有发送命令。我在 Ubuntu python 解释器中运行代码,它在创建小部件时没有任何错误。我对某些 GL 命令有一些问题,但可能来自我安装的 python 包装器。我仍在寻找与 pygame 或 glut 的 init 等效的小部件,并设置投影函数来设置视口。如果有人有想法,我很想听听。以下代码运行时没有错误:

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from OpenGL.GL import *
from OpenGL.GLU import *


class MyGLArea(Gtk.GLArea):
    def __init__(self):
        Gtk.GLArea.__init__(self)
        self.connect("realize", self.on_realize)
        self.connect("render", self.render)


    def on_realize(self, area):
        ctx = self.get_context()
        ctx.make_current()
        err = self.get_error()
        if err:
            print("The error is {}".format(err))

    def render(self, area, ctx):
        glClearColor(1,0,0,1)
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
        return True

class RootWidget(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self, title='GL Example')
        self.set_default_size(800,500)
        gl_area = MyGLArea()
        self.add(gl_area)

win = RootWidget()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main() 

【问题讨论】:

  • python 文档:lazka.github.io/pgi-docs/#Gtk-3.0/classes/GLArea.html。但我同意示例是用 C 语言编写的,这是一个问题。
  • glClearColor 不在 GTK 中,它在 opengl 库中:khronos.org/registry/OpenGL-Refpages/gl4/html/…。该库必须有一些 python 包装器,它似乎被命名为 PyOpenGL:pyopengl.sourceforge.net
  • 这里有一个 PyOpenGL 教程,可以帮助您入门:pythonprogramming.net/…
  • @liberforce 谢谢。这清除了 gl 命令的来源。我确实运行了 pygame 教程,它的工作方式与我想在 gtk 中使用它的方式完全相同,只是它不是一个单独的窗口,而是一个小部件。阅读 Gdk.GLContext 的 API 文档,一旦上下文变为“当前”,它将接受 gl 命令。我什至在发送之前收到 gl 错误。

标签: opengl gtk pygobject


【解决方案1】:

在 Windows 上使用 All-In-One 安装程序时,我注意到 GTK+ 的 OpenGL 扩展选项。现在它按预期工作。 这是一些工作代码:

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from OpenGL.GL import *
from OpenGL.GL import shaders
import numpy as np

FRAGMENT_SOURCE ='''
#version 330
in vec4 inputColor;
out vec4 outputColor;
void main(){
outputColor = vec4(1.0,0.0,0.0,1.0);//constant red. I know it's a poor shader
};'''

VERTEX_SOURCE = '''
#version 330
in vec4 position;
void main(){
gl_Position =  position;
}'''

class MyGLArea(Gtk.GLArea):
    def __init__(self):
        Gtk.GLArea.__init__(self)
        self.connect("realize", self.on_realize)
        self.connect("render", self.on_render)

    def on_realize(self, area):
        ctx = self.get_context()
        print("realized", ctx)

    def on_render(self, area, ctx):
        ctx.make_current()
        glClearColor(0, 0, 0, 1)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        VERTEX_SHADER_PROG = shaders.compileShader(VERTEX_SOURCE, GL_VERTEX_SHADER)
        FRAGMENT_SHADER_PROG = shaders.compileShader(FRAGMENT_SOURCE, GL_FRAGMENT_SHADER)
        self.shader_prog = shaders.compileProgram(VERTEX_SHADER_PROG, FRAGMENT_SHADER_PROG)
        self.create_object()

    def create_object(self):
        # Create a new VAO (Vertex Array Object) and bind it
        vertex_array_object = glGenVertexArrays(1)
        glBindVertexArray(vertex_array_object)
        # Generate buffers to hold our vertices
        vertex_buffer = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer)
        # Get the position of the 'position' in parameter of our shader and bind it.
        position = glGetAttribLocation(self.shader_prog, 'position')
        glEnableVertexAttribArray(position)
        # Describe the position data layout in the buffer
        glVertexAttribPointer(position, 3, GL_FLOAT, False, 0, ctypes.c_void_p(0))
        # Send the data over to the buffer
        vertices = np.array([-0.6, -0.6, 0.0,
                             0.0, 0.6, 0.0,
                             0.6, -0.6, 0.0,
                             0.7, -0.1, 0.0,
                             0.8, 0.1, 0.0,
                             0.9, -0.1, 0.0
                             ], dtype=np.float32)
        glBufferData(GL_ARRAY_BUFFER, 96, vertices, GL_STATIC_DRAW)
        # Unbind the VAO first (Important)
        glBindVertexArray(0)
        # Unbind other stuff
        glDisableVertexAttribArray(position)




        glBindBuffer(GL_ARRAY_BUFFER, 0)
        self.display(vertex_array_object)

    def display(self, vert):
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glUseProgram(self.shader_prog)
        glBindVertexArray(vert)
        glDrawArrays(GL_TRIANGLES, 0, 3)
        glDrawArrays(GL_TRIANGLES, 4, 3)
        glBindVertexArray(0)
        glUseProgram(0)

class RootWidget(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self, title='GL Example')
        self.set_default_size(800, 500)
        gl_area = MyGLArea()
        gl_area.set_has_depth_buffer(False)
        gl_area.set_has_stencil_buffer(False)
        self.add(gl_area)

win = RootWidget()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()

【讨论】:

    【解决方案2】:

    我不确定这是否适合你,但它确实适合我。

    Python 文件:

    #!/usr/bin/env python
    import gi
    gi.require_version('Gtk', '3.0')
    from gi.repository import Gtk, GdkPixbuf, Gdk
    from OpenGL.GL import glClearColor, glClear, glFlush, GL_COLOR_BUFFER_BIT
    import os, sys
    
    UI_FILE = "pygtk_gtkglarea.ui"
    
    class GUI:
        def __init__(self):
    
            self.builder = Gtk.Builder()
            self.builder.add_from_file(UI_FILE)
            self.builder.connect_signals(self)
    
            gl_area = Gtk.GLArea()
            gl_area.connect('render', self.area_render)
            gl_area.connect('realize', self.area_realize)
            #gl_area.connect('create-context', self.area_context)
            box = self.builder.get_object('box1')
            box.pack_end(gl_area, True, True, 0)
    
            window = self.builder.get_object('window')
            window.show_all()
    
        def area_realize (self, gl_area):       
            error = gl_area.get_error()
            if error != None:
                print("your graphics card is probably too old : ", error)
            else:
                print(gl_area, "realize... fine so far")
    
        def area_context(self, gl_area):
            # not needed except for special instances, read the docs
            c = gl_area.get_context()
            print(c , "context")
            return c
    
        def area_render(self, area, context):
            #print gl_area
            #print gl_context
            glClearColor (0.5, 0.5, 0.5, 1.0)
            glClear (GL_COLOR_BUFFER_BIT)
            glFlush()
            print("rendering... done")
            return True
    
        def on_window_destroy(self, window):
            Gtk.main_quit()
    
    def main():
        app = GUI()
        Gtk.main()
    
    if __name__ == "__main__":
        sys.exit(main())
    

    还有 pygtk_gtkglarea.ui 文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <!-- Generated with glade 3.18.3 -->
    <interface>
      <requires lib="gtk+" version="3.0"/>
      <object class="GtkWindow" id="window">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="title" translatable="yes">window</property>
        <property name="default_width">500</property>
        <property name="default_height">400</property>
        <signal name="destroy" handler="on_window_destroy" swapped="no"/>
        <child>
          <object class="GtkBox" id="box1">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="orientation">vertical</property>
            <child>
              <placeholder/>
            </child>
          </object>
        </child>
      </object>
    </interface>
    

    【讨论】:

    • @theGtknerd 您的代码确实对我有用(尽管我必须将 glFlush 添加到导入中)。一旦我向它添加绘图命令就是问题所在。我在 glClear() 之后添加 glColor3f(1.0,0.0,1.0) 并且它崩溃了。与任何 glBegin(GL_LINES) 或类似的相同。同样,这可能是我的 gl 库的问题。我假设我得到的 gl_FragColor 错误是由于它试图运行的片段着色器代码。我也尝试过编译和使用着色器,但没有运气。
    • @AdamSolchenberger 让我明天试试你的添加,我会更新。很抱歉那次导入。
    • @AdamSolchenberger 我对 glColor3f 也有同样的问题。可悲的是,我不擅长 OpenGL。我有我在帮助另一个项目时发布的代码 sn-p。
    猜你喜欢
    • 2011-08-24
    • 1970-01-01
    • 2012-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多