GTK3 GLArea与GLFW的帧缓冲区问题(渲染到纹理):相同的OpenGL程序在GLFW中可用,但在GTK3的GLArea中不起作用

问题描述 投票:0回答:1

关于我的项目:我正在Linux上使用OpenGL3.2,并且已经使用带有GLArea小部件的GTK3构建了一个基本应用程序。该程序是使用PyCharm IDE用Python编写的。项目解释器设置为Python 3.8,我已经加载了以下软件包:枕头7.1.2,PyGObject 3.36.1,PyOpenGL 3.1.5,numpy 1.18,pyrr 0.10.3和glfw 1.11.2(请参见底部的图像)

我的问题:

我有一个程序可以使用GLFW正常运行,但不能使用GTK3的GLArea正常运行。我试图使用自定义帧缓冲区对象渲染到纹理基于GTK3的程序无法成功渲染到自定义帧缓冲区。但是,基于GLFW的程序可以很好地渲染。 OpenGL代码没有区别。我只更改窗口代码。我需要启用GTK3才能使用自定义帧缓冲区吗? GTK3(here)的文档仅指示需要设置特殊标志才能启用深度缓冲区和模板缓冲区(我已经启用了这两个),但与自定义纹理缓冲区无关。

非常感谢任何见解。

这里是有问题的GTK3 GLArea程序:

import sys
import gi, pyrr
import numpy

gi.require_version('Gtk', '3.0')
from pyrr import matrix44, Vector3
from gi.repository import Gtk
from OpenGL.GL import *
from OpenGL.GL.shaders import compileProgram
from PIL import Image


class GLCanvas(Gtk.GLArea):
    def __init__(self):
        Gtk.GLArea.__init__(self)
        self.set_required_version(3, 2)             # Sets the version of OpenGL required by this OpenGL program
        self.connect("realize", self.on_initialize) # This signal is used to initialize the OpenGL state
        self.connect("render", self.on_render)      # This signal is emitted for each frame that is rendered
        self.add_tick_callback(self.tick)           # This is a frame time clock that is called each time a frame is rendered
        self.set_start_time = False                 # Boolean to track whether the clock has been initialized
        self.set_has_depth_buffer(True)
        self.set_has_stencil_buffer(True)

    def tick(self, widget, frame_clock):
        self.current_frame_time = frame_clock.get_frame_time()  # Gets the current timestamp in microseconds
        if self.set_start_time == False:                        # Initializes the timer at the start of the program
            self.starting_time = self.current_frame_time        # Stores the timestamp set when the program was initalized
            self.set_start_time = True                          # Prevents the initialization routine from running again in this instance
        self.application_clock = (self.current_frame_time - self.starting_time)/1000000    # Calculate the total number of seconds that the program has been running
        return True                                                     # Returns true to indicate that tick callback should contine to be called

    def on_initialize(self, gl_area):
        # Prints information about our OpenGL Context
        opengl_context = self.get_context()             # Retrieves the Gdk.GLContext used by gl_area
        opengl_context.make_current()                   # Makes the Gdk.GLContext current to the drawing surfaced used by Gtk.GLArea
        major, minor = opengl_context.get_version()     # Gets the version of OpenGL currently used by the opengl_context
        print("\033[93m OpenGL context created successfully.\n -- Using OpenGL Version \033[94m" + str(major) + "." + str(minor) + "\033[0m")

        # Checks to see if there were errors creating the context
        if gl_area.get_error() != None:
            print(gl_area.get_error())

        # Get information about current GTK GLArea canvas
        window = gl_area.get_allocation()

        w_width, w_height = window.width, window.height
        self.aspect_ratio = w_width / w_height

        self.cube_positions = [(1.0, 1.0, 0.0), (0.0, 0.0, 0.0), (2.0, 0.0, 0.0)]
        self.plane_position = matrix44.create_from_translation(Vector3([-3.0, 1.0, 0.0]))

        cube = [-0.5, -0.5, 0.5, 0.0, 0.0,
                0.5, -0.5, 0.5, 1.0, 0.0,
                0.5, 0.5, 0.5, 1.0, 1.0,
                -0.5, 0.5, 0.5, 0.0, 1.0,

                -0.5, -0.5, -0.5, 0.0, 0.0,
                0.5, -0.5, -0.5, 1.0, 0.0,
                0.5, 0.5, -0.5, 1.0, 1.0,
                -0.5, 0.5, -0.5, 0.0, 1.0,

                0.5, -0.5, -0.5, 0.0, 0.0,
                0.5, 0.5, -0.5, 1.0, 0.0,
                0.5, 0.5, 0.5, 1.0, 1.0,
                0.5, -0.5, 0.5, 0.0, 1.0,

                -0.5, 0.5, -0.5, 0.0, 0.0,
                -0.5, -0.5, -0.5, 1.0, 0.0,
                -0.5, -0.5, 0.5, 1.0, 1.0,
                -0.5, 0.5, 0.5, 0.0, 1.0,

                -0.5, -0.5, -0.5, 0.0, 0.0,
                0.5, -0.5, -0.5, 1.0, 0.0,
                0.5, -0.5, 0.5, 1.0, 1.0,
                -0.5, -0.5, 0.5, 0.0, 1.0,

                0.5, 0.5, -0.5, 0.0, 0.0,
                -0.5, 0.5, -0.5, 1.0, 0.0,
                -0.5, 0.5, 0.5, 1.0, 1.0,
                0.5, 0.5, 0.5, 0.0, 1.0]

        cube = numpy.array(cube, dtype=numpy.float32)

        self.cube_indices = [0, 1, 2, 2, 3, 0,
                        4, 5, 6, 6, 7, 4,
                        8, 9, 10, 10, 11, 8,
                        12, 13, 14, 14, 15, 12,
                        16, 17, 18, 18, 19, 16,
                        20, 21, 22, 22, 23, 20]

        self.cube_indices = numpy.array(self.cube_indices, dtype=numpy.uint32)

        plane = [-0.5, -0.5, 0.0, 0.0, 0.0,
                 2.0, -0.5, 0.0, 1.0, 0.0,
                 2.0, 1.0, 0.0, 1.0, 1.0,
                 -0.5, 1.0, 0.0, 0.0, 1.0]

        plane = numpy.array(plane, dtype=numpy.float32)

        self.plane_indices = [0, 1, 2, 2, 3, 0]
        self.plane_indices = numpy.array(self.plane_indices, dtype=numpy.uint32)

        vertex_shader = """
        #version 330
        in layout(location = 0) vec3 position;
        in layout(location = 1) vec2 textCoords;
        uniform mat4 vp;
        uniform mat4 model;
        out vec2 outText;
        void main()
        {
            gl_Position =  vp * model * vec4(position, 1.0f);
            outText = textCoords;
        }
        """

        fragment_shader = """
        #version 330
        in vec2 outText;
        out vec4 outColor;
        uniform sampler2D renderedTexture;
        void main()
        {
            outColor = texture(renderedTexture, outText);
        }
        """

        shader = OpenGL.GL.shaders.compileProgram(OpenGL.GL.shaders.compileShader(vertex_shader, GL_VERTEX_SHADER),
                                                  OpenGL.GL.shaders.compileShader(fragment_shader, GL_FRAGMENT_SHADER))

        # cube VAO
        self.cube_vao = glGenVertexArrays(1)
        glBindVertexArray(self.cube_vao)
        cube_VBO = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER, cube_VBO)
        glBufferData(GL_ARRAY_BUFFER, cube.itemsize * len(cube), cube, GL_STATIC_DRAW)
        cube_EBO = glGenBuffers(1)
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cube_EBO)
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, self.cube_indices.itemsize * len(self.cube_indices), self.cube_indices, GL_STATIC_DRAW)
        # position
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, cube.itemsize * 5, ctypes.c_void_p(0))
        glEnableVertexAttribArray(0)
        # textures
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, cube.itemsize * 5, ctypes.c_void_p(12))
        glEnableVertexAttribArray(1)
        glBindVertexArray(0)

        # plane VAO
        self.plane_vao = glGenVertexArrays(1)
        glBindVertexArray(self.plane_vao)
        plane_VBO = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER, plane_VBO)
        glBufferData(GL_ARRAY_BUFFER, plane.itemsize * len(plane), plane, GL_STATIC_DRAW)
        plane_EBO = glGenBuffers(1)
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, plane_EBO)
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, self.plane_indices.itemsize * len(self.plane_indices), self.plane_indices,
                     GL_STATIC_DRAW)
        # position
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, plane.itemsize * 5, ctypes.c_void_p(0))
        glEnableVertexAttribArray(0)
        # textures
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, plane.itemsize * 5, ctypes.c_void_p(12))
        glEnableVertexAttribArray(1)
        glBindVertexArray(0)

        ###########################################################################################

        self.plane_texture = glGenTextures(1)
        glBindTexture(GL_TEXTURE_2D, self.plane_texture)
        # texture wrapping params
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
        # texture filtering params
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w_width, w_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, None)
        glBindTexture(GL_TEXTURE_2D, 0)

        depth_buff = glGenRenderbuffers(1)
        glBindRenderbuffer(GL_RENDERBUFFER, depth_buff)
        glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w_width, w_height)

        self.FBO = glGenFramebuffers(1)
        glBindFramebuffer(GL_FRAMEBUFFER, self.FBO)
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self.plane_texture, 0)
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_buff)
        glBindFramebuffer(GL_FRAMEBUFFER, 0)

        ###########################################################################################
        self.crate_texture = glGenTextures(1)
        glBindTexture(GL_TEXTURE_2D, self.crate_texture)
        # Set the texture wrapping parameters
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
        # Set texture filtering parameters
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
        # load image
        image = Image.open("models/crate.jpg")
        img_data = numpy.array(list(image.getdata()), numpy.uint8)
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.width, image.height, 0, GL_RGB, GL_UNSIGNED_BYTE, img_data)
        glBindTexture(GL_TEXTURE_2D, 0)
        ###########################################################################################

        glEnable(GL_DEPTH_TEST)

        view = matrix44.create_from_translation(Vector3([0.0, 0.0, -5.0]))
        projection = matrix44.create_perspective_projection_matrix(45.0, self.aspect_ratio, 0.1, 100.0)

        vp = matrix44.multiply(view, projection)

        glUseProgram(shader)
        vp_loc = glGetUniformLocation(shader, "vp")
        self.model_loc = glGetUniformLocation(shader, "model")
        glUniformMatrix4fv(vp_loc, 1, GL_FALSE, vp)

        return True

    def on_render(self, gl_area, gl_context):

        glClearColor(0.2, 0.25, 0.27, 1.0)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

        rot_y = pyrr.Matrix44.from_y_rotation(self.application_clock * 2)

        # draw to the default frame buffer
        glBindVertexArray(self.cube_vao)
        glBindTexture(GL_TEXTURE_2D, self.crate_texture)
        for i in range(len(self.cube_positions)):
            model = matrix44.create_from_translation(self.cube_positions[i])
            if i == 0:
                glUniformMatrix4fv(self.model_loc, 1, GL_FALSE, rot_y * model)
            elif i == 1:
                glUniformMatrix4fv(self.model_loc, 1, GL_FALSE, model)
            else:
                glUniformMatrix4fv(self.model_loc, 1, GL_FALSE, model)

            glDrawElements(GL_TRIANGLES, len(self.cube_indices), GL_UNSIGNED_INT, None)

        # draw to the custom frame buffer
        glBindFramebuffer(GL_FRAMEBUFFER, self.FBO)
        glClearColor(0.0, 0.0, 0.0, 1.0)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

        for i in range(len(self.cube_positions)):
            model = matrix44.create_from_translation(self.cube_positions[i])
            if i == 0:
                glUniformMatrix4fv(self.model_loc, 1, GL_FALSE, rot_y * model)
            elif i == 1:
                glUniformMatrix4fv(self.model_loc, 1, GL_FALSE, model)
            else:
                glUniformMatrix4fv(self.model_loc, 1, GL_FALSE, model)

            glDrawElements(GL_TRIANGLES, len(self.cube_indices), GL_UNSIGNED_INT, None)
        glBindVertexArray(0)
        glBindFramebuffer(GL_FRAMEBUFFER, 0)

        # draw the plane
        glBindVertexArray(self.plane_vao)
        glBindTexture(GL_TEXTURE_2D, self.plane_texture)
        glUniformMatrix4fv(self.model_loc, 1, GL_FALSE, self.plane_position)
        glDrawElements(GL_TRIANGLES, len(self.plane_indices), GL_UNSIGNED_INT, None)
        glBindVertexArray(0)

        self.queue_draw()   # Schedules a redraw for Gtk.GLArea

class RootWindow(Gtk.Application):
    def __init__(self):
        Gtk.Application.__init__(self)

    def do_activate(self):
        window = Gtk.Window(application=self)
        window.set_title("Render To Texture")
        window.set_default_size(1280, 720)
        window.set_position(Gtk.WindowPosition.CENTER)
        window.add(GLCanvas())
        window.show_all()

win = RootWindow()
exit_status = win.run(sys.argv)
sys.exit(exit_status)

这里是完整的GLFW程序(original source):

import glfw
from OpenGL.GL import *
import OpenGL.GL.shaders
import numpy
import pyrr
from pyrr import matrix44, Vector3
from PIL import Image


def window_resize(window, width, height):
    glViewport(0, 0, width, height)


cube_positions = [(1.0, 1.0, 0.0), (0.0, 0.0, 0.0), (2.0, 0.0, 0.0)]
plane_position = matrix44.create_from_translation(Vector3([-3.0, 1.0, 0.0]))


def main():
    if not glfw.init():
        return

    w_width, w_height = 1280, 720
    aspect_ratio = w_width / w_height

    window = glfw.create_window(w_width, w_height, "My OpenGL window", None, None)

    if not window:
        glfw.terminate()
        return

    glfw.make_context_current(window)
    glfw.set_window_size_callback(window, window_resize)

    cube = [-0.5, -0.5,  0.5, 0.0, 0.0,
             0.5, -0.5,  0.5, 1.0, 0.0,
             0.5,  0.5,  0.5, 1.0, 1.0,
            -0.5,  0.5,  0.5, 0.0, 1.0,

            -0.5, -0.5, -0.5, 0.0, 0.0,
             0.5, -0.5, -0.5, 1.0, 0.0,
             0.5,  0.5, -0.5, 1.0, 1.0,
            -0.5,  0.5, -0.5, 0.0, 1.0,

             0.5, -0.5, -0.5, 0.0, 0.0,
             0.5,  0.5, -0.5, 1.0, 0.0,
             0.5,  0.5,  0.5, 1.0, 1.0,
             0.5, -0.5,  0.5, 0.0, 1.0,

            -0.5,  0.5, -0.5, 0.0, 0.0,
            -0.5, -0.5, -0.5, 1.0, 0.0,
            -0.5, -0.5,  0.5, 1.0, 1.0,
            -0.5,  0.5,  0.5, 0.0, 1.0,

            -0.5, -0.5, -0.5, 0.0, 0.0,
             0.5, -0.5, -0.5, 1.0, 0.0,
             0.5, -0.5,  0.5, 1.0, 1.0,
            -0.5, -0.5,  0.5, 0.0, 1.0,

             0.5, 0.5, -0.5,  0.0, 0.0,
            -0.5, 0.5, -0.5,  1.0, 0.0,
            -0.5, 0.5,  0.5,  1.0, 1.0,
             0.5, 0.5,  0.5,  0.0, 1.0]

    cube = numpy.array(cube, dtype=numpy.float32)

    cube_indices = [ 0,  1,  2,  2,  3,  0,
                     4,  5,  6,  6,  7,  4,
                     8,  9, 10, 10, 11,  8,
                    12, 13, 14, 14, 15, 12,
                    16, 17, 18, 18, 19, 16,
                    20, 21, 22, 22, 23, 20]

    cube_indices = numpy.array(cube_indices, dtype=numpy.uint32)

    plane = [-0.5, -0.5, 0.0, 0.0, 0.0,
              2.0, -0.5, 0.0, 1.0, 0.0,
              2.0,  1.0, 0.0, 1.0, 1.0,
             -0.5,  1.0, 0.0, 0.0, 1.0]

    plane = numpy.array(plane, dtype=numpy.float32)

    plane_indices = [0, 1, 2, 2, 3, 0]
    plane_indices = numpy.array(plane_indices, dtype=numpy.uint32)

    vertex_shader = """
    #version 330
    in layout(location = 0) vec3 position;
    in layout(location = 1) vec2 textCoords;
    uniform mat4 vp;
    uniform mat4 model;
    out vec2 outText;
    void main()
    {
        gl_Position =  vp * model * vec4(position, 1.0f);
        outText = textCoords;
    }
    """

    fragment_shader = """
    #version 330
    in vec2 outText;
    out vec4 outColor;
    uniform sampler2D renderedTexture;
    void main()
    {
        outColor = texture(renderedTexture, outText);
    }
    """

    shader = OpenGL.GL.shaders.compileProgram(OpenGL.GL.shaders.compileShader(vertex_shader, GL_VERTEX_SHADER),
                                              OpenGL.GL.shaders.compileShader(fragment_shader, GL_FRAGMENT_SHADER))

    # cube VAO
    cube_vao = glGenVertexArrays(1)
    glBindVertexArray(cube_vao)
    cube_VBO = glGenBuffers(1)
    glBindBuffer(GL_ARRAY_BUFFER, cube_VBO)
    glBufferData(GL_ARRAY_BUFFER, cube.itemsize * len(cube), cube, GL_STATIC_DRAW)
    cube_EBO = glGenBuffers(1)
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cube_EBO)
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, cube_indices.itemsize * len(cube_indices), cube_indices, GL_STATIC_DRAW)
    # position
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, cube.itemsize * 5, ctypes.c_void_p(0))
    glEnableVertexAttribArray(0)
    # textures
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, cube.itemsize * 5, ctypes.c_void_p(12))
    glEnableVertexAttribArray(1)
    glBindVertexArray(0)


    # plane VAO
    plane_vao = glGenVertexArrays(1)
    glBindVertexArray(plane_vao)
    plane_VBO = glGenBuffers(1)
    glBindBuffer(GL_ARRAY_BUFFER, plane_VBO)
    glBufferData(GL_ARRAY_BUFFER, plane.itemsize * len(plane), plane, GL_STATIC_DRAW)
    plane_EBO = glGenBuffers(1)
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, plane_EBO)
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, plane_indices.itemsize * len(plane_indices), plane_indices, GL_STATIC_DRAW)
    # position
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, plane.itemsize * 5, ctypes.c_void_p(0))
    glEnableVertexAttribArray(0)
    # textures
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, plane.itemsize * 5, ctypes.c_void_p(12))
    glEnableVertexAttribArray(1)
    glBindVertexArray(0)

    ###########################################################################################

    plane_texture = glGenTextures(1)
    glBindTexture(GL_TEXTURE_2D, plane_texture)
    # texture wrapping params
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
    # texture filtering params
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w_width, w_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, None)
    glBindTexture(GL_TEXTURE_2D, 0)

    depth_buff = glGenRenderbuffers(1)
    glBindRenderbuffer(GL_RENDERBUFFER, depth_buff)
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w_width, w_height)

    FBO = glGenFramebuffers(1)
    glBindFramebuffer(GL_FRAMEBUFFER, FBO)
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, plane_texture, 0)
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_buff)
    glBindFramebuffer(GL_FRAMEBUFFER, 0)

    ###########################################################################################
    crate_texture = glGenTextures(1)
    glBindTexture(GL_TEXTURE_2D, crate_texture)
    # Set the texture wrapping parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
    # Set texture filtering parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
    # load image
    image = Image.open("res/crate.jpg")
    img_data = numpy.array(list(image.getdata()), numpy.uint8)
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.width, image.height, 0, GL_RGB, GL_UNSIGNED_BYTE, img_data)
    glBindTexture(GL_TEXTURE_2D, 0)
    ###########################################################################################

    glEnable(GL_DEPTH_TEST)

    view = matrix44.create_from_translation(Vector3([0.0, 0.0, -5.0]))
    projection = matrix44.create_perspective_projection_matrix(45.0, aspect_ratio, 0.1, 100.0)

    vp = matrix44.multiply(view, projection)

    glUseProgram(shader)
    vp_loc = glGetUniformLocation(shader, "vp")
    model_loc = glGetUniformLocation(shader, "model")
    glUniformMatrix4fv(vp_loc, 1, GL_FALSE, vp)

    while not glfw.window_should_close(window):
        glfw.poll_events()

        glClearColor(0.2, 0.25, 0.27, 1.0)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

        rot_y = pyrr.Matrix44.from_y_rotation(glfw.get_time() * 2)

        # draw to the default frame buffer
        glBindVertexArray(cube_vao)
        glBindTexture(GL_TEXTURE_2D, crate_texture)
        for i in range(len(cube_positions)):
            model = matrix44.create_from_translation(cube_positions[i])
            if i == 0:
                glUniformMatrix4fv(model_loc, 1, GL_FALSE, rot_y * model)
            elif i == 1:
                glUniformMatrix4fv(model_loc, 1, GL_FALSE, model)
            else:
                glUniformMatrix4fv(model_loc, 1, GL_FALSE, model)

            glDrawElements(GL_TRIANGLES, len(cube_indices), GL_UNSIGNED_INT, None)

        # draw to the custom frame buffer
        glBindFramebuffer(GL_FRAMEBUFFER, FBO)
        glClearColor(0.0, 0.0, 0.0, 1.0)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

        for i in range(len(cube_positions)):
            model = matrix44.create_from_translation(cube_positions[i])
            if i == 0:
                glUniformMatrix4fv(model_loc, 1, GL_FALSE, rot_y * model)
            elif i == 1:
                glUniformMatrix4fv(model_loc, 1, GL_FALSE, model)
            else:
                glUniformMatrix4fv(model_loc, 1, GL_FALSE, model)

            glDrawElements(GL_TRIANGLES, len(cube_indices), GL_UNSIGNED_INT, None)
        glBindVertexArray(0)
        glBindFramebuffer(GL_FRAMEBUFFER, 0)

        # draw the plane
        glBindVertexArray(plane_vao)
        glBindTexture(GL_TEXTURE_2D, plane_texture)
        glUniformMatrix4fv(model_loc, 1, GL_FALSE, plane_position)
        glDrawElements(GL_TRIANGLES, len(plane_indices), GL_UNSIGNED_INT, None)
        glBindVertexArray(0)

        glfw.swap_buffers(window)

    glfw.terminate()


if __name__ == "__main__":
    main()

Settings for Project Interpreter

python opengl gtk3 glfw render-to-texture
1个回答
0
投票

解决方案

事实证明,GLArea未使用默认的帧缓冲区0。这里的问题是在渲染循环结束时使用glBindFramebuffer(GL_FRAMEBUFFER,0)将帧缓冲区重置为0。而是在渲染循环开始时使用default_ID = glGetIntegerv(GL_FRAMEBUFFER_BINDING)来获取当前的默认ID。在循环结束时,使用glBindFramebuffer(GL_FRAMEBUFFER,default_ID)重置为默认帧缓冲区。

    import sys
import gi, pyrr
import numpy

gi.require_version('Gtk', '3.0')
from pyrr import matrix44, Vector3
from gi.repository import Gtk
from OpenGL.GL import *
from OpenGL.GL.shaders import compileProgram
from PIL import Image


class GLCanvas(Gtk.GLArea):
    def __init__(self):
        Gtk.GLArea.__init__(self)
        self.set_required_version(3, 2)             # Sets the version of OpenGL required by this OpenGL program
        self.connect("realize", self.on_initialize) # This signal is used to initialize the OpenGL state
        self.connect("render", self.on_render)      # This signal is emitted for each frame that is rendered
        self.add_tick_callback(self.tick)           # This is a frame time clock that is called each time a frame is rendered
        self.set_start_time = False                 # Boolean to track whether the clock has been initialized
        self.set_has_depth_buffer(True)
        self.set_has_stencil_buffer(True)

    def tick(self, widget, frame_clock):
        self.current_frame_time = frame_clock.get_frame_time()  # Gets the current timestamp in microseconds
        if self.set_start_time == False:                        # Initializes the timer at the start of the program
            self.starting_time = self.current_frame_time        # Stores the timestamp set when the program was initalized
            self.set_start_time = True                          # Prevents the initialization routine from running again in this instance
        self.application_clock = (self.current_frame_time - self.starting_time)/1000000    # Calculate the total number of seconds that the program has been running
        return True                                                     # Returns true to indicate that tick callback should contine to be called

    def on_initialize(self, gl_area):
        # Prints information about our OpenGL Context
        opengl_context = self.get_context()             # Retrieves the Gdk.GLContext used by gl_area
        opengl_context.make_current()                   # Makes the Gdk.GLContext current to the drawing surfaced used by Gtk.GLArea
        major, minor = opengl_context.get_version()     # Gets the version of OpenGL currently used by the opengl_context
        # https://stackoverflow.com/questions/287871/how-to-print-colored-text-in-terminal-in-python
        print("\033[93m OpenGL context created successfully.\n -- Using OpenGL Version \033[94m" + str(major) + "." + str(minor) + "\033[0m")

        # Checks to see if there were errors creating the context
        if gl_area.get_error() != None:
            print(gl_area.get_error())

        # Get information about current GTK GLArea canvas
        window = gl_area.get_allocation()

        w_width, w_height = window.width, window.height
        self.aspect_ratio = w_width / w_height

        self.cube_positions = [(1.0, 1.0, 0.0), (0.0, 0.0, 0.0), (2.0, 0.0, 0.0)]
        self.plane_position = matrix44.create_from_translation(Vector3([-3.0, 1.0, 0.0]))

        cube = [-0.5, -0.5, 0.5, 0.0, 0.0,
                0.5, -0.5, 0.5, 1.0, 0.0,
                0.5, 0.5, 0.5, 1.0, 1.0,
                -0.5, 0.5, 0.5, 0.0, 1.0,

                -0.5, -0.5, -0.5, 0.0, 0.0,
                0.5, -0.5, -0.5, 1.0, 0.0,
                0.5, 0.5, -0.5, 1.0, 1.0,
                -0.5, 0.5, -0.5, 0.0, 1.0,

                0.5, -0.5, -0.5, 0.0, 0.0,
                0.5, 0.5, -0.5, 1.0, 0.0,
                0.5, 0.5, 0.5, 1.0, 1.0,
                0.5, -0.5, 0.5, 0.0, 1.0,

                -0.5, 0.5, -0.5, 0.0, 0.0,
                -0.5, -0.5, -0.5, 1.0, 0.0,
                -0.5, -0.5, 0.5, 1.0, 1.0,
                -0.5, 0.5, 0.5, 0.0, 1.0,

                -0.5, -0.5, -0.5, 0.0, 0.0,
                0.5, -0.5, -0.5, 1.0, 0.0,
                0.5, -0.5, 0.5, 1.0, 1.0,
                -0.5, -0.5, 0.5, 0.0, 1.0,

                0.5, 0.5, -0.5, 0.0, 0.0,
                -0.5, 0.5, -0.5, 1.0, 0.0,
                -0.5, 0.5, 0.5, 1.0, 1.0,
                0.5, 0.5, 0.5, 0.0, 1.0]

        cube = numpy.array(cube, dtype=numpy.float32)

        self.cube_indices = [0, 1, 2, 2, 3, 0,
                        4, 5, 6, 6, 7, 4,
                        8, 9, 10, 10, 11, 8,
                        12, 13, 14, 14, 15, 12,
                        16, 17, 18, 18, 19, 16,
                        20, 21, 22, 22, 23, 20]

        self.cube_indices = numpy.array(self.cube_indices, dtype=numpy.uint32)

        plane = [-0.5, -0.5, 0.0, 0.0, 0.0,
                 2.0, -0.5, 0.0, 1.0, 0.0,
                 2.0, 1.0, 0.0, 1.0, 1.0,
                 -0.5, 1.0, 0.0, 0.0, 1.0]

        plane = numpy.array(plane, dtype=numpy.float32)

        self.plane_indices = [0, 1, 2, 2, 3, 0]
        self.plane_indices = numpy.array(self.plane_indices, dtype=numpy.uint32)

        vertex_shader = """
        #version 330
        in vec3 position;
        in vec2 textCoords;
        uniform mat4 vp;
        uniform mat4 model;
        out vec2 outText;
        void main()
        {
            gl_Position =  vp * model * vec4(position, 1.0f);
            outText = textCoords;
        }
        """

        fragment_shader = """
        #version 330
        in vec2 outText;
        out vec4 outColor;
        uniform sampler2D renderedTexture;
        void main()
        {
            outColor = texture(renderedTexture, outText);
        }
        """

        shader = OpenGL.GL.shaders.compileProgram(OpenGL.GL.shaders.compileShader(vertex_shader, GL_VERTEX_SHADER),
                                                  OpenGL.GL.shaders.compileShader(fragment_shader, GL_FRAGMENT_SHADER))

        # cube VAO
        self.cube_vao = glGenVertexArrays(1)
        glBindVertexArray(self.cube_vao)
        cube_VBO = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER, cube_VBO)
        glBufferData(GL_ARRAY_BUFFER, cube.itemsize * len(cube), cube, GL_STATIC_DRAW)
        cube_EBO = glGenBuffers(1)
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cube_EBO)
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, self.cube_indices.itemsize * len(self.cube_indices), self.cube_indices, GL_STATIC_DRAW)
        # position
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, cube.itemsize * 5, ctypes.c_void_p(0))
        glEnableVertexAttribArray(0)
        # textures
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, cube.itemsize * 5, ctypes.c_void_p(12))
        glEnableVertexAttribArray(1)
        glBindVertexArray(0)

        # plane VAO
        self.plane_vao = glGenVertexArrays(1)
        glBindVertexArray(self.plane_vao)
        plane_VBO = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER, plane_VBO)
        glBufferData(GL_ARRAY_BUFFER, plane.itemsize * len(plane), plane, GL_STATIC_DRAW)
        plane_EBO = glGenBuffers(1)
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, plane_EBO)
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, self.plane_indices.itemsize * len(self.plane_indices), self.plane_indices,
                     GL_STATIC_DRAW)
        # position
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, plane.itemsize * 5, ctypes.c_void_p(0))
        glEnableVertexAttribArray(0)
        # textures
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, plane.itemsize * 5, ctypes.c_void_p(12))
        glEnableVertexAttribArray(1)
        glBindVertexArray(0)

        ###########################################################################################

        self.plane_texture = glGenTextures(1)
        glBindTexture(GL_TEXTURE_2D, self.plane_texture)
        # texture wrapping params
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
        # texture filtering params
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w_width, w_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, None)
        glBindTexture(GL_TEXTURE_2D, 0)

        depth_buff = glGenRenderbuffers(1)
        glBindRenderbuffer(GL_RENDERBUFFER, depth_buff)
        glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w_width, w_height)

        self.FBO = glGenFramebuffers(1)
        glBindFramebuffer(GL_FRAMEBUFFER, self.FBO)
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self.plane_texture, 0)
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_buff)
        glBindFramebuffer(GL_FRAMEBUFFER, 0)

        ###########################################################################################
        self.crate_texture = glGenTextures(1)
        glBindTexture(GL_TEXTURE_2D, self.crate_texture)
        # Set the texture wrapping parameters
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
        # Set texture filtering parameters
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
        # load image
        image = Image.open("models/crate.jpg")
        img_data = numpy.array(list(image.getdata()), numpy.uint8)
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.width, image.height, 0, GL_RGB, GL_UNSIGNED_BYTE, img_data)
        glBindTexture(GL_TEXTURE_2D, 0)
        ###########################################################################################

        glEnable(GL_DEPTH_TEST)

        view = matrix44.create_from_translation(Vector3([0.0, 0.0, -5.0]))
        projection = matrix44.create_perspective_projection_matrix(45.0, self.aspect_ratio, 0.1, 100.0)

        vp = matrix44.multiply(view, projection)

        glUseProgram(shader)
        vp_loc = glGetUniformLocation(shader, "vp")
        self.model_loc = glGetUniformLocation(shader, "model")
        glUniformMatrix4fv(vp_loc, 1, GL_FALSE, vp)

        return True

    def on_render(self, gl_area, gl_context):
        default_ID = glGetIntegerv(GL_FRAMEBUFFER_BINDING)
        glClearColor(0.2, 0.25, 0.27, 1.0)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

        rot_y = pyrr.Matrix44.from_y_rotation(self.application_clock * 2)

        # draw to the default frame buffer
        glBindVertexArray(self.cube_vao)
        glBindTexture(GL_TEXTURE_2D, self.crate_texture)
        for i in range(len(self.cube_positions)):
            model = matrix44.create_from_translation(self.cube_positions[i])
            if i == 0:
                glUniformMatrix4fv(self.model_loc, 1, GL_FALSE, rot_y * model)
            elif i == 1:
                glUniformMatrix4fv(self.model_loc, 1, GL_FALSE, model)
            else:
                glUniformMatrix4fv(self.model_loc, 1, GL_FALSE, model)

            glDrawElements(GL_TRIANGLES, len(self.cube_indices), GL_UNSIGNED_INT, None)

        # draw to the custom frame buffer
        glBindFramebuffer(GL_FRAMEBUFFER, self.FBO)
        glClearColor(0.0, 0.0, 0.0, 1.0)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

        for i in range(len(self.cube_positions)):
            model = matrix44.create_from_translation(self.cube_positions[i])
            if i == 0:
                glUniformMatrix4fv(self.model_loc, 1, GL_FALSE, rot_y * model)
            elif i == 1:
                glUniformMatrix4fv(self.model_loc, 1, GL_FALSE, model)
            else:
                glUniformMatrix4fv(self.model_loc, 1, GL_FALSE, model)

            glDrawElements(GL_TRIANGLES, len(self.cube_indices), GL_UNSIGNED_INT, None)

        glBindFramebuffer(GL_FRAMEBUFFER, default_ID)
        glBindVertexArray(0)

        # draw the plane
        glBindVertexArray(self.plane_vao)
        glBindTexture(GL_TEXTURE_2D, self.plane_texture)
        glUniformMatrix4fv(self.model_loc, 1, GL_FALSE, self.plane_position)
        glDrawElements(GL_TRIANGLES, len(self.plane_indices), GL_UNSIGNED_INT, None)
        glBindVertexArray(0)

        self.queue_draw()   # Schedules a redraw for Gtk.GLArea

class RootWindow(Gtk.Application):
    def __init__(self):
        Gtk.Application.__init__(self)

    def do_activate(self):
        window = Gtk.Window(application=self)
        window.set_title("Render To Texture")
        window.set_default_size(1280, 720)
        window.set_position(Gtk.WindowPosition.CENTER)
        window.add(GLCanvas())
        window.show_all()

win = RootWindow()
exit_status = win.run(sys.argv)
sys.exit(exit_status)
© www.soinside.com 2019 - 2024. All rights reserved.