在绘制另一个 VBO 时更新 VBO

Updating VBO while drawing another VBO

我正在尝试使用 VBO 和 VAO 渲染一个场景,我想用新数据更新这个场景。问题是我事先不知道要渲染多少个顶点,所以我不能很好地分配内存。

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

绘制

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

缓冲区创建代码和drawing/updating:

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 可以消除必须等待传输完成才能绘制的问题,但显然不是这样。

如果可能的话,如果有人能向我解释我应该如何同时使用两个缓冲区,我将不胜感激。提前致谢!

OpenGL Context 是本地线程。上下文不能在多个线程中是当前的。您必须“切换”上下文。上下文必须在线程中成为当前上下文。
另见 OpenGL and multithreading respectively

glBufferData creates and initializes a buffer object's data store (think about it as like as memory allocation and copy of the data to the memory). If you just want to update the buffer data, then you have to use glBufferSubDataglBufferSubData 使用现有缓冲区并将数据复制到缓冲区。
另见 What is the proper way to modify OpenGL vertex buffer?