Недавно я написал код OpenGL 3.3 с объектами Vertex Array (VAO) и протестировал его позже на графическом адаптере Intel, где я обнаружил, к моему разочарованию, что привязка буфера элемента массива, очевидно, не является частью состояния 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 в Intel (потому что в GL_ARB_vertex_array_object (и даже в GL_OES_vertex_array_object) четко указано, что элементный массив является частью сохраненного состояния), но затем он произошел на мобильном NVIDIA Quadro 4200. Это не весело.
Это ошибка драйвера, ошибка спецификации или ошибка где-то в моем коде? Код работает безупречно на GeForce 260 и 480.
У кого-то был подобный опыт?
Также странно, что GL_EXT_direct_state_access не имеет функции привязки буфера массива элементов к VAO (но он имеет функции для указания массивов атрибутов вершин и, следовательно, буферов массива). Являются ли производители графических процессоров завинчиванием спецификаций и обмана на нас, или что?
ИЗМЕНИТЬ
Я изначально не собирался показывать какой-либо исходный код, потому что считал, что здесь не нужно. Но, как просили, вот минимальный тестовый пример, который воспроизводит проблему:
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);
}
Это очистит окно просмотра до серого и повторяет синий или красный квадрат (он также печатает один). Хотя это работает на настольном графическом процессоре, оно не работает на графическом процессоре ноутбука (черный квадрат отображается, если не указан макрос VAO_DOESNT_STORE_ELEMENT_ARRAY_BUFFER. Невозможно определить макрос BIND_BLACK_QUAD_ELEMENT_ARRAY_BUFFER, что делает синий цвет синим, поскольку синий буфер буфера привязан последним. сделайте красный квадрат, несмотря ни на что.
Итак, как я его вижу, это либо фатальное заблуждение в моем понимании того, как должно работать VAO, ошибка в моем коде или ошибка драйвера.