【问题标题】:OES_vertex_array_object and client stateOES_vertex_array_object 和客户端状态
【发布时间】:2012-11-05 09:46:39
【问题描述】:

我希望 OpenGL ES 2.0 中的顶点数组对象保存来自不同缓冲区的两个属性,第二个缓冲区是从客户端内存中读取的 (glBindBuffer(GL_ARRAY_BUFFER, 0)) 但我得到一个运行时错误:

GLuint my_vao;
GLuint my_buffer_attrib0;
GLfloat attrib0_data[] = { 0, 0, 0, 0 };
GLfloat attrib1_data[] =  { 1, 1, 1, 1 };

void init()
{
    // setup vao
    glGenVertexArraysOES(1, &my_vao);
    glBindVertexArrayOES(my_vao);

    // setup attrib0 as a vbo
    glGenBuffers( 1, &my_buffer_attrib0 );
    glBindBuffer(GL_ARRAY_BUFFER, my_buffer_attrib0);
    glBufferData( GL_ARRAY_BUFFER, sizeof(attrib0_data), attrib0_data, GL_STATIC_DRAW );
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);

    glEnableVertexAttribArray( 0 );
    glEnableVertexAttribArray( 1 );

    // "end" vao
    glBindVertexArrayOES( 0 );

}

void draw()
{

    glBindVertexArrayOES(my_vao);
    // (now I assume attrib0 is bound to my_buffer_attrib0, 
    //  and attrib1 is not bound. but is this assumption true?)

    // setup attrib1
    glBindBuffer( GL_ARRAY_BUFFER, 0 );
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, attrib1_data);

    // draw using attrib0 and attrib1
    glDrawArrays( GL_POINTS, 0, 1 );  // runtime error: Thread1: EXC_BAD_ACCESS (code=2, address=0x0)

}

我想要实现的是将两个属性的绑定包装成一个顶点数组缓冲区:

void draw_ok()
{
    glBindVertexArrayOES( 0 );

    // setup attrib0
    glBindBuffer( GL_ARRAY_BUFFER, my_buffer_attrib0 );
    glVertexAttribPointer( 0, 4, GL_FLOAT, GL_FALSE, 0, 0);

    // setup attrib1
    glBindBuffer( GL_ARRAY_BUFFER, 0 );
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, attrib1_data);

    glEnableVertexAttribArray( 0 );
    glEnableVertexAttribArray( 1 );

    // draw using attrib0 and attrib1
    glDrawArrays( GL_POINTS, 0, 1);  // ok
}

是否可以在一个顶点数组对象中绑定两个不同的缓冲区? OES_vertex_array_object 与(普通)OpenGL 顶点数组对象不同吗?另请注意,我在运行 iOS 模拟器的 XCode 中收到此错误。这些是相关链接:

【问题讨论】:

    标签: opengl-es opengl-es-2.0


    【解决方案1】:

    嗯,扩展规范中的一句话解释得很简单:

    是否应该允许顶点数组对象封装客户端顶点数组?

    已解决:否。OpenGL ES 工作组一致认为,与 OpenGL 的兼容性以及通过强制使用 VBO 来引导开发人员进行更高性能绘图的能力比损害 VAO 采用的可能性更重要。

    因此,您确实可以在 VAO 中绑定两个不同的缓冲区,(好吧,缓冲区绑定不存储在 VAO 中,无论如何,只有各个属性的源缓冲区,通过 glVertexAttribPointer 设置)但您不能使用VAO 中的客户空间内存,只有 VBO。桌面 GL 也是如此。

    所以我建议您将所有顶点数据存储在 VBO 中。如果您想使用客户端内存,因为数据是动态更新的,并且您认为 VBO 不会在那里为您购买任何东西,那仍然是错误的方法。只需使用具有动态用法的 VBO(GL_DYNAMIC_DRAW 甚至 GL_STREAM_DRAW)并使用 glBuffer(Sub)DataglMapBuffer(或旧的 glBufferData(..., NULL); glMapBuffer(GL_WRITE_ONLY) 组合)对其进行更新。

    【讨论】:

    • 你得到了接受的答案,因为你不是我,并且如果 OES-VAO 与 desktop-VAO 相同,也会回答:) 谢谢。
    【解决方案2】:

    删除以下行:

    glBindBuffer( GL_ARRAY_BUFFER, 0 );

    来自draw() 函数。您之前没有绑定任何缓冲区,它可能会弄乱缓冲区状态。

    【讨论】:

    • 我希望从客户端内存中读取第二个属性(attrib1),因此在调用 glVertexAttribPointer 之前必须取消绑定 GL_ARRAY_BUFFER。但这似乎把事情搞砸了,我不确定为什么。我想要实现的一个示例是让 VAO 存储几何图形,然后在绑定 VAO 后将该 VAO 的另一个属性设置为我的自定义颜色。
    • @telephone 您不能将客户端内存与 VAO 一起使用,请参阅我的回答。
    【解决方案3】:

    经过一番挖掘(阅读),在OES_vertex_array_object 中找到了答案。似乎 OES_vertex_array_object 专注于服务器端的状态,当且仅当绑定零对象时才使用客户端状态。 OES_vertex_array_object 是否与普通的 OpenGL VAO 相同还有待回答。如果您知道这个问题的答案,请发表评论。以下是OES_vertex_array_object的引用:

         This extension introduces vertex array objects which encapsulate
         vertex array states on the server side (vertex buffer objects).
    
    
    
         * Should a vertex array object be allowed to encapsulate client
         vertex arrays?
    
         RESOLVED: No. The OpenGL ES working group agreed that compatibility
         with OpenGL and the ability to to guide developers to more
         performant drawing by enforcing VBO usage were more important than
         the possibility of hurting adoption of VAOs.
    
    
    
         An INVALID_OPERATION error is generated if
         VertexAttribPointer is called while a non-zero vertex array object
         is bound, zero is bound to the <ARRAY_BUFFER> buffer object binding
         point and the pointer argument is not NULL [fn1].
           [fn1: This error makes it impossible to create a vertex array
           object containing client array pointers, while still allowing
           buffer objects to be unbound.]
    
    
    
         And the presently attached vertex array object has the following
         impacts on the draw commands:
    
           While a non-zero vertex array object is bound, if any enabled
           array's buffer binding is zero, when DrawArrays or
           DrawElements is called, the result is undefined.
    

    所以 EXC_BAD_ACCESS 是未定义的结果!

    【讨论】:

    • +1 表示“所以 EXC_BAD_ACCESS 是未定义的结果!”。 ,我一直在寻找一个错误。由于某种原因,客户端状态 GL_VERTEX_ARRAY 被谁知道一段时间后禁用了,所以在 glDrawArray 救了我之后重新启用它: glEnableClientState(GL_VERTEX_ARRAY);我从来没有认为 EXC_BAD_ACCESS 是未定义的结果,而是意外的内存释放,但不,这里没有释放内存。感谢您的提示,这非常有帮助:)
    【解决方案4】:

    您想要的功能现已被社区接受为 WebGL 的扩展:

    http://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/

    【讨论】:

    • 这个答案似乎与问题无关。该链接表明 WebGL 现在支持 OES_vertex_array_object。很好,但没有解决问题。接受的答案解释了为什么不能以所询问的方式使用 VAO,并就如何做提供建议。
    猜你喜欢
    • 2022-08-10
    • 2013-03-30
    • 2012-03-18
    • 2013-01-13
    • 2021-04-20
    • 2013-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多