gpt4 book ai didi

opengl - VAO 和元素数组缓冲区状态

转载 作者:行者123 更新时间:2023-12-03 11:35:37 27 4
gpt4 key购买 nike

我最近使用顶点数组对象 (VAO) 编写了一些 OpenGL 3.3 代码,后来在英特尔图形适配器上对其进行了测试,令我失望的是,元素数组缓冲区绑定(bind)显然不是 VAO 状态的一部分,因为调用:

glBindVertexArray(my_vao);
glDrawElements(GL_TRIANGLE_STRIP, count, GL_UNSIGNED_INTEGER, 0);

没有效果,而:

glBindVertexArray(my_vao);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, my_index_buffer); // ?
glDrawElements(GL_TRIANGLE_STRIP, count, GL_UNSIGNED_INTEGER, 0);

渲染几何。我认为这只是英特尔 OpenGL 实现中的一个错误(因为在 GL_ARB_vertex_array_object(甚至在 GL_OES_vertex_array_object)中明确指出元素数组 保存状态的一部分),但后来它发生在移动 NVIDIA Quadro 4200。那可不好玩。

它是驱动程序错误、规范错误还是我的代码中某处的错误?该代码在 GeForce 260 和 480 上完美运行。

有人有类似的经历吗?

同样奇怪的是 GL_EXT_direct_state_access 没有将元素数组缓冲区绑定(bind)到 VAO 的函数(但它确实具有指定顶点属性数组和数组缓冲区的函数)。 GPU制造商是在搞砸规范并欺骗我们,还是什么?

编辑 :

我原本不打算展示任何源代码,因为我认为这里没有必要。但根据要求,这是重现问题的最小测试用例:

static GLuint n_vertex_buffer_object, p_index_buffer_object_list[3];
static GLuint p_vao[2];

bool InitGLObjects()
{
const float p_quad_verts_colors[] = {
1, 0, 0, -1, 1, 0,
1, 0, 0, 1, 1, 0,
1, 0, 0, 1, -1, 0,
1, 0, 0, -1, -1, 0, // red quad
0, 0, 1, -1, 1, 0,
0, 0, 1, 1, 1, 0,
0, 0, 1, 1, -1, 0,
0, 0, 1, -1, -1, 0, // blue quad
0, 0, 0, -1, 1, 0,
0, 0, 0, 1, 1, 0,
0, 0, 0, 1, -1, 0,
0, 0, 0, -1, -1, 0 // black quad
};
const unsigned int p_quad_indices[][6] = {
{0, 1, 2, 0, 2, 3},
{4, 5, 6, 4, 6, 7},
{8, 9, 10, 8, 10, 11}
};
glGenBuffers(1, &n_vertex_buffer_object);
glBindBuffer(GL_ARRAY_BUFFER, n_vertex_buffer_object);
glBufferData(GL_ARRAY_BUFFER, sizeof(p_quad_verts_colors), p_quad_verts_colors, GL_STATIC_DRAW);
glGenBuffers(3, p_index_buffer_object_list);
for(int n = 0; n < 3; ++ n) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, p_index_buffer_object_list[n]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(p_quad_indices[n]), p_quad_indices[n], GL_STATIC_DRAW);
}

glGenVertexArrays(2, p_vao);
glBindVertexArray(p_vao[0]);
{
glBindBuffer(GL_ARRAY_BUFFER, n_vertex_buffer_object);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), p_OffsetInVBO(0));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), p_OffsetInVBO(3 * sizeof(float)));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, p_index_buffer_object_list[0]); // red
}
glBindVertexArray(0);

glBindVertexArray(p_vao[1]);
{
glBindBuffer(GL_ARRAY_BUFFER, n_vertex_buffer_object);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), p_OffsetInVBO(0));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), p_OffsetInVBO(3 * sizeof(float)));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, p_index_buffer_object_list[1]); // blue
}
glBindVertexArray(0);

#ifdef BIND_BLACK_QUAD_ELEMENT_ARRAY_BUFFER
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, p_index_buffer_object_list[2]);
// bind the buffer with the black quad (not inside VAO, should NOT be seen)
#endif // BIND_BLACK_QUAD_ELEMENT_ARRAY_BUFFER

// [compile shaders here]

return true; // success
}

上面的代码创建了一个包含三个四边形的顶点缓冲区,红色一个,蓝色一个和黑色一个。然后它创建三个指向各个四边形的索引缓冲区。然后创建并设置两个 VAO,一个应包含红色四边形索引,另一个应包含蓝色四边形索引。根本不应该渲染黑色四边形(假设定义了 BIND_BLACK_QUAD_ELEMENT_ARRAY_BUFFER)。

void onDraw()
{
glClearColor(.5f, .5f, .5f, 0);
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);

glUseProgram(n_program_object);

static int n_last_color = -1;
int n_color = (clock() / 2000) % 2;
if(n_last_color != n_color) {
printf("now drawing %s quad\n", (n_color)? "blue" : "red");
n_last_color = n_color;
}

glBindVertexArray(p_vao[n_color]);
#ifdef VAO_DOESNT_STORE_ELEMENT_ARRAY_BUFFER
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, p_index_buffer_object_list[n_color]); // fixes the problem
#endif // VAO_DOESNT_STORE_ELEMENT_ARRAY_BUFFER
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}

这会将视口(viewport)清除为灰色并以重复的方式渲染蓝色或红色四边形(它还会打印哪一个)。虽然这适用于桌面 GPU,但它不适用于笔记本 GPU(除非定义了 VAO_DOESNT_STORE_ELEMENT_ARRAY_BUFFER 宏,否则会呈现黑色四边形。取消定义 BIND_BLACK_QUAD_ELEMENT_ARRAY_BUFFER 宏会使四边形变为蓝色,因为蓝色索引缓冲区最后绑定(bind)。但它没有无论如何渲染红色四边形。

所以在我看来,这要么是我对 VAO 应该如何工作的理解上的致命误解,要么是我的代码中的错误,要么是驱动程序错误。

Full source
Binaries (windows, 32 bit)

最佳答案

What is also strange is that GL_EXT_direct_state_access does not have a function to bind an element array buffer to VAO


对于目前遇到此问题并至少针对 OpenGL 4.5 的任何人,现在有一个函数可以直接将元素数组缓冲区绑定(bind)到 VAO,而无需绑定(bind) VAO: glVertexArrayElementBuffer ,并且使用它可能会解决使您挖掘此问题的任何问题。

关于opengl - VAO 和元素数组缓冲区状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8973690/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com