我想要一个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中收到此错误。这些是相关链接:
答案 0 :(得分:7)
嗯,扩展规范的引用很简单地解释了它:
是否允许顶点数组对象封装客户端顶点数组?
决议:不会.OpenGL ES工作组同意,与OpenGL的兼容性以及通过强制执行VBO来指导开发人员进行更高性能绘图的能力比伤害采用VAO的可能性更重要。
所以你确实可以在VAO中绑定两个不同的缓冲区,(好吧,缓冲区绑定不存储在VAO中,无论如何,只有各个属性的源缓冲区,通过glVertexAttribPointer
设置)但是你不能在VAO中使用客户端空间内存,只能使用VBO。桌面GL也是如此。
因此我建议您将所有顶点数据存储在VBO中。如果您想使用客户端内存,因为数据是动态更新的,并且您认为VBO不会在那里购买任何东西,那仍然是错误的方法。只需使用动态使用的VBO(GL_DYNAMIC_DRAW
甚至GL_STREAM_DRAW
),然后使用glBuffer(Sub)Data
或glMapBuffer
(或旧的glBufferData(..., NULL); glMapBuffer(GL_WRITE_ONLY)
组合)进行更新。
答案 1 :(得分:1)
删除以下行:
glBindBuffer( GL_ARRAY_BUFFER, 0 );
draw()
函数的。你以前没有绑定任何缓冲区,它可能会搞乱缓冲区状态。
答案 2 :(得分:1)
经过一些挖掘(阅读)后,在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是未定义的结果!
答案 3 :(得分:1)
您所希望的功能现在已被社区接受为WebGL的扩展:
http://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/