1

我使用 OpenGL 和 GLSL 编写了一个简单的图形引擎。直到这里,当我需要创建一个新的网格场景节点时,我为每个网格创建了一个 VAO、一个 VBO 和一个 IBO。我以这种方式为每个网格加载了顶点属性:

glBufferData(GL_ARRAY_BUFFER, this->GetVerticesByteSize(VERTEX_POSITION)
        + this->GetVerticesByteSize(VERTEX_TEXTURE) + this->GetVerticesByteSize(VERTEX_NORMAL), NULL, this->m_Usage);
    glBufferSubData(GL_ARRAY_BUFFER, 0, this->GetVerticesByteSize(VERTEX_POSITION), &this->m_VertexBuffer[VERTEX_POSITION][0]);
    if (!this->m_VertexBuffer[VERTEX_TEXTURE].empty())
        glBufferSubData(GL_ARRAY_BUFFER, this->GetVerticesByteSize(VERTEX_POSITION),
            this->GetVerticesByteSize(VERTEX_TEXTURE), &this->m_VertexBuffer[VERTEX_TEXTURE][0]);
    if (!this->m_VertexBuffer[VERTEX_NORMAL].empty())
        glBufferSubData(GL_ARRAY_BUFFER, this->GetVerticesByteSize(
            VERTEX_POSITION) + this->GetVerticesByteSize(VERTEX_TEXTURE),
                this->GetVerticesByteSize(VERTEX_NORMAL), &this->m_VertexBuffer[VERTEX_NORMAL][0]);

但是如果场景是由很多网格组成的,那么它的性能就不正确(太多的状态变化)。所以,我决定为我场景的所有几何体创建一个独特的 VAO、VBO 和 IBO(单例类)。

执行此操作的方法如下:

为每个网格加载特定类(我们称之为“VertexAttributes”)中的所有顶点属性。加载所有网格后,我们可以在唯一的 VBO 中分配大顶点缓冲区。所以像上面一样,我首先调用函数“glBufferData”来分配整个内存,其中包含场景中所有顶点属性的大小,然后在循环中为每种顶点属性调用函数“glBufferSubData”。

但是是否可以多次调用 glBufferData(对于每个网格)并在场景加载期间填充 VBO(对于每个网格逐步)。所以它看起来像一个realloc。是否可以使用 OpenGL 来做到这一点,或者我的第一种方法是好的?

4

1 回答 1

3

但是是否可以多次调用 glBufferData(对于每个网格)并在场景加载期间填充 VBO(对于每个网格逐步)。所以它看起来像一个realloc。是否可以使用 OpenGL 来做到这一点,或者我的第一种方法是好的?

不会。无论何时调用glBufferData,都会创建一个新的数据存储(具有新的大小),而之前的内容会丢失。

但是,在许多情况下,将多个对象组合在同一个 VBO 中仍然是一种有效的策略,尤其是在这些对象中的许多可能被绘制在一起的情况下。

您不能动态调整缓冲区对象的大小。您可以做的是预先分配更大的缓冲区并更新其中的一部分。拥有一堆大小合理的可用缓冲区并动态填充可能是一种可行的策略。请注意,还有GL_ARB_copy_buffer(自 GL 3.1 以来的核心,因此广泛可用),它将允许您非常有效的服务器端副本,您甚至可以realloc通过分配新缓冲区并复制旧内容来模拟“”行为。

哪种策略最好总是取决于情况。如果您经常动态加载或销毁对象,则使用一些复杂的缓冲区分配和管理策略可能会得到回报。

于 2014-05-18T16:39:46.533 回答