1

我的应用程序在“glDrawElements”(和 glDrawArrays)上崩溃。

我想知道,崩溃的原因可能是什么?

目前我有:

Foreach mesh

     - Bind VBO/VAO

           if( VAO empty )

                - bind VAO(id)
                - bind VBO(id)

                Foreach attribs
                    - glEnableVertexAttribArray
                    - glVertexAttribPointer
                End foreach

                - unbindVAO(0)
                - unbindVBO(0)

                Foreach attribs
                    - glDisableVertexAttribArray
                End foreach

            endif

     - Bind IBO(id)

     - Bind program/shader(id)
        -> send uniforms

     -> glDrawElements

End foreach
  • 当我有很多 VBO/VAO/IBO 时,我的应用程序在 glDrawElements 上崩溃
  • 使用不同的设备,当我有很多 VAO/VBO/IBO 时,我得到了奇怪的人工制品

我认为我的缓冲区有些奇怪(比如冲突),绑定的正确顺序是什么?我需要在哪里解除绑定 VAO、VBO、IBO、程序、纹理……?

编辑:

看起来当我删除一个几何图形时会出现崩溃,他的缓冲区已从 opengl 中删除(因为我不再使用它们)。所以我认为我的缓冲区总是有界的。

OpenGL跟踪:

glBindBuffer(target = GL_ARRAY_BUFFER, buffer = 8)
glEnableVertexAttribArray(index = 2)
glVertexAttribPointer(indx = 2, size = 3, type = GL_FLOAT, normalized = false, stride = 20, ptr = 0x0)
glEnableVertexAttribArray(index = 0)
glVertexAttribPointer(indx = 0, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 20, ptr = 0xc)
glEnableVertexAttribArray(index = 4)
glVertexAttribPointer(indx = 4, size = 2, type = GL_UNSIGNED_SHORT, normalized = true, stride = 20, ptr = 0x10)
glBindBuffer(target = GL_ARRAY_BUFFER, buffer = 0)
glBindBuffer(target = GL_ELEMENT_ARRAY_BUFFER, buffer = 7)
glUseProgram(program = 0)
glUseProgram(program = 6)
glUniformMatrix4fv(location = 2, count = 1, transpose = false, value = [1.6974937, 0.0, 0.0, 0.0, 0.0, 2.100419, -0.49304545, -0.49301255, 0.0, -1.1902374, -0.87008023, -0.8700222, -9.582167, -2.1815264, 15.627364, 15.64632])
glActiveTexture(texture = GL_TEXTURE0)
glBindTexture(target = GL_TEXTURE_2D, texture = 1)
glUniform1i(location = 8, x = 0)
glDisable(cap = GL_BLEND)
glBlendFunc(sfactor = GL_LINES, dfactor = GL_POINTS)
glEnable(cap = GL_DEPTH_TEST)
glUniformMatrix4fv(location = 7, count = 1, transpose = false, value = [50.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 50.0, 0.0, 0.0, -0.1, -150.0, 1.0])
glUniform3fv(location = 3, count = 1, v = [0.8235294, 0.8235294, 0.8235294])
glUniform2fv(location = 0, count = 1, v = [0.0, 0.0])
glUniform2fv(location = 1, count = 1, v = [1.0, 1.0])
glDrawElements(mode = GL_TRIANGLE_STRIP, count = 4, type = GL_UNSIGNED_BYTE, indices = 0x0)
4

2 回答 2

3

解除绑定 VAO不应禁用顶点属性数组。在 OpenGL 3 核心上下文中,当您解除绑定 VAO 时,您将不再有可应用于顶点数组命令的上下文;您必须始终绑定 VAO,否则这些命令将是无效操作。

此外,VAO 持久存储顶点数组状态。这个想法不是每次绘制时都启用或禁用状态,而是绑定一个已经设置了所有必要状态的 VAO。

以下是您应该如何考虑使用顶点数组对象设置顶点数组。由于 VAO 存储了大部分状态,因此您不必执行诸如禁用顶点数组或取消绑定 VBO 之类的操作来防止状态泄漏。每当您想绘制不同的顶点数组时,只需更改绑定的 VAO。

第 1 阶段: GL 顶点数组/缓冲区对象初始化

构建网格时:

  - 生成 VAO、VBO、IBO
  - 绑定VAO、VBO、IBO

   -> 将顶点数据上传到 VBO
   -> 上传索引数组到 IBO

  Foreach 属性 <n>
    - 设置属性指针 (n)
    - 启用属性数组 (n)
  结束 Foreach  

第 2 阶段:绘制网格实例

渲染对象(网格实例)时:

  - 绑定Mesh的VAO

  - 绑定程序/着色器(id)
    -> 发送制服

  -> glDrawElements

此外,如果您的软件设置正确(例如,使用顶点数组绘制的所有东西都有自己的 VAO 来管理状态),那么取消绑定 VAO 确实是不必要的。想想应用纹理,你很少会在绘制后取消绑定纹理。你指望你绘制的下一批确切地知道它需要什么纹理状态;如果它需要不同的纹理(或根本不需要),那么应该改变纹理状态。每批后恢复纹理状态是浪费资源,恢复顶点数组状态也是如此。


在旁注中,我正在查看您的 OpenGL 跟踪并遇到了一些您可能不知道的东西。您正在使用GL_UNSIGNED_BYTE由 API 提供但硬件不一定支持的索引。在很多硬件上(例如任何桌面 GPU)GL_UNSIGNED_SHORT是首选的索引类型(即使对于非常小的顶点集合)。GL_UNSIGNED_BYTE当您的顶点少于 256 个时,很容易假设 using会节省空间并因此提高吞吐量,但实际上它可能会让您偏离“快速路径”。如果硬件不支持 8 位索引,那么驱动程序不可避免地必须在您提交索引后将其转换为 16 位。在这种情况下,它会增加驱动程序的工作量并且不会节省任何 GPU 内存,遗憾的是。

于 2013-08-23T21:17:33.983 回答
0

如果在调用 glVertexAttribPointer 时缓冲区绑定到 GL_ARRAY_BUFFER,则指针被视为缓冲区内的偏移量。否则,它被视为指向系统内存的指针。因此,如果没有缓冲区绑定并且您传递了一个无效指针,例如零(期望缓冲区已绑定),GL 会尝试进行无效读取并且程序崩溃。

glDrawElements 也是一样,如果缓冲区绑定到 GL_ELEMENT_ARRAY_BUFFER,则指针参数被视为缓冲区内的偏移量。

这里,GL_ARRAY_BUFFER 缓冲区只需要在 gl*Pointer() 调用期间和 GL_ELEMENT_ARRAY_BUFFER 在 glDrawElements() 调用期间绑定。

启用客户端状态调用 glEnableVertexAttribArray 并且不提供指针也会导致崩溃。

编辑

我相信 VAO 只是记录顶点属性数组、绑定缓冲区和指向这些缓冲区的指针的配置。要使用,请在设置所有内容之前绑定 VAO,就好像您要进行绘图调用一样,然后取消绑定。现在,当您绑定该 VAO 时,状态会恢复,您可以简单地进行绘图调用,而无需大量 GL 调用。

bind VAO
for each attrib,
    call glEnableVertexAttribArray //in the next draw call, use the VBO I'm about to set up.
    bind VBO
    call glVertexAttribPointer //use data in bound VBO with size,stride,offset
    unbind VBOconfig
end for
unbind VAO
//not certain but are attrib arrays still enabled after unbinding VAO (maybe disabling is unnecessary)

现在进行绘图调用,绑定 VAO,draw(),取消绑定。

最后,对于 glEnableVertexAttribArray 和 glVertexAttribPointer 我不知道,但索引是否需要是统一变量位置?

于 2013-08-23T13:34:50.657 回答