问题
I want a vertex array object in OpenGL ES 2.0 to hold two attributes from different buffers, the second buffer being read from client memory (glBindBuffer(GL_ARRAY_BUFFER, 0)
) But I get a runtime error:
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)
}
What I want to achieve is to wrap the binding of two attributes as a vertex array buffer:
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
}
Is it possible to bind two different buffers in a vertex array object? Are OES_vertex_array_object's different from (plain) OpenGL vertex array objects? Also note that I get this error in XCode running the iOS simulator. These are related links:
- Use of VAO around VBO in Open ES iPhone app Causes EXC_BAD_ACCESS When Call to glDrawElements
- OES_vertex_array_object
回答1:
Well, a quote from the extension specifications explains it quite simply:
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.
So you can indeed bind two different buffers in a VAO, (well, the buffer binding isn't stored in the VAO, anyway, only the source buffers of the individual attributes, set through glVertexAttribPointer
) but you cannot use client space memory in a VAO, only VBOs. This is the same for desktop GL.
So I would advise you to store all your vertex data in VBOs. If you want to use client memory because the data is updated dynamically and you think VBOs won't buy you anything there, that's still the wrong approach. Just use a VBO with a dynamic usage (GL_DYNAMIC_DRAW
or even GL_STREAM_DRAW
) and update it using glBuffer(Sub)Data
or glMapBuffer
(or the good old glBufferData(..., NULL); glMapBuffer(GL_WRITE_ONLY)
combination).
回答2:
Remove the following line:
glBindBuffer( GL_ARRAY_BUFFER, 0 );
from the draw()
function. You didn't bind any buffer before and it may mess up buffer state.
回答3:
After some digging (reading), answers was found found in OES_vertex_array_object. It seems that OES_vertex_array_object's focus on state on the server side, and client state are used if and only if the zero object is bound. It remains to answer if OES_vertex_array_object's are the same as plain OpenGL VAO's. Please comment if you know the answer to this. Below are quotations from 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.
So EXC_BAD_ACCESS was the undefined result!
回答4:
The functionality you desire has now been accepted by the community as an extension to WebGL:
http://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/
来源:https://stackoverflow.com/questions/9536973/oes-vertex-array-object-and-client-state