在绘制另一个VBO时更新VBO

时间:2020-07-21 14:01:31

标签: python multithreading opengl multiprocessing vbo

我正在尝试使用VBO和VAO渲染场景,我想用新数据更新该场景。问题是我不预先知道要渲染多少个顶点,因此无法很好地分配内存。

现在,我已经尝试了“仅分配将要使用的最大内存量”方法,但我不确定这是最好的方法(我的VBO可能超过3 GB)。因此我的想法是改为使用2个VBO,并使用glBufferData更新一个,而另一个更新。

因为我不希望在更新缓冲区时冻结程序,所以我想尝试多处理以使“绘制”和“更新”进程同时运行。但是,当我调用应该同时绘制和更新的函数时,无论如何它都会冻结并在更新第二个缓冲区时显示空白屏幕。当我停止更新第二个缓冲区时,它可以正常工作。

用于缓冲区创建和绘制/更新的代码:

def __init__(self, coords_list, layer_list, model_list):
        self.fgbuffer, self.bgbuffer = 0, 0
        self.fgarray, self.bgarray = 0, 0
        now = time.time()
        self.render_list = gen_render_list(coords_list)
        self.render_vbo, self.render_vao = glGenBuffers(1), glGenVertexArrays(1)
        self.render_vbo_2, self.render_vao_2 = glGenBuffers(1), glGenVertexArrays(1)
        glBindVertexArray(self.render_vao)
        glBindBuffer(GL_ARRAY_BUFFER, self.render_vbo)
        glBufferData(GL_ARRAY_BUFFER, np.array(self.render_list, dtype='float32'), GL_STREAM_DRAW)
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 36, ctypes.c_void_p(0))
        glEnableVertexAttribArray(0)
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 36, ctypes.c_void_p(12))
        glEnableVertexAttribArray(1)
        glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 36, ctypes.c_void_p(20))
        glEnableVertexAttribArray(2)
        glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, 36, ctypes.c_void_p(32))
        glEnableVertexAttribArray(3)
        glBindVertexArray(self.render_vao_2)
        glBindBuffer(GL_ARRAY_BUFFER, self.render_vbo_2)
        glBufferData(GL_ARRAY_BUFFER, np.array(self.render_list, dtype='float32'), GL_STREAM_DRAW)
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 36, ctypes.c_void_p(0))
        glEnableVertexAttribArray(0)
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 36, ctypes.c_void_p(12))
        glEnableVertexAttribArray(1)
        glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 36, ctypes.c_void_p(20))
        glEnableVertexAttribArray(2)
        glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, 36, ctypes.c_void_p(32))
        glEnableVertexAttribArray(3)
        self.fgbuffer, self.fgarray = self.render_vbo, self.render_vao
        self.bgbuffer, self.bgarray = self.render_vbo_2, self.render_vao_2

    def update_bgbuffer(self):
        glBindVertexArray(self.bgarray)
        glBindBuffer(GL_ARRAY_BUFFER, self.bgbuffer)
        glBufferData(GL_ARRAY_BUFFER, np.array(self.render_list, dtype='float32'), GL_STREAM_DRAW)

    def draw_buffer(self, program, texture):
        program.use()
        glBindTexture(GL_TEXTURE_2D_ARRAY, texture)
        glBindVertexArray(self.fgarray)
        glDrawArrays(GL_TRIANGLES, 0, len(self.render_list) * 6)

    def draw_and_update(self, program, texture):
        draw = multiprocessing.Process(target = self.draw_buffer, args = (program, texture))
        update = multiprocessing.Process(target = self.update_bgbuffer, args = ())
        draw.start()
        update.start()

我认为有更好的方法来创建两个相同的缓冲区,但这并不是我的问题所在。

渲染循环:

while not window.check_if_closed():
        window.refresh(0)
        glActiveTexture(GL_TEXTURE0)

        shader_program_scene.use()
        glEnable(GL_DEPTH_TEST)
        if glfw.get_key(window.window, glfw.KEY_U) == glfw.PRESS:
            world_render.draw_and_update(shader_program_scene, all_textures)
        else:
            world_render.draw_buffer(shader_program_scene, all_textures)

        glBindVertexArray(0)

我曾经认为,通过单独的线程将数据发送到GPU可以消除必须等待传输完成才能绘制的问题,但显然并非如此。

如果有人可以向我解释我应该如何同时使用两个缓冲区,我将不胜感激。预先感谢!

1 个答案:

答案 0 :(得分:0)

OpenGL Context是线程本地的。上下文不能在多个线程中是当前的。您必须“切换”上下文。必须使线程中的上下文为最新。
分别参见OpenGL and multithreading Multithreaded Rendering on OpenGL

glBufferData创建并初始化缓冲区对象的数据存储(将其视为类似于内存分配和将数据复制到内存的方式)。如果只想更新缓冲区数据,则必须使用glBufferSubDataglBufferSubData使用现有缓冲区并将数据复制到该缓冲区。
另请参见What is the proper way to modify OpenGL vertex buffer?