Qt6 Почему glDrawElements не использует данные из буфера массива элементов [закрыто]

Вопрос или проблема

Я пытаюсь создать приложение с использованием Qt6 и QOpenGLWidget. Я всегда понимал концепцию VAO и EBO как загрузку данных в память GPU, чтобы эти данные не приходилось передавать каждый раз (исправьте меня, если я не прав). Далее мы используем glDrawElements, в котором указываем количество вершин и смещение в EBO, но по какой-то причине это не работает в Qt.

В теории это должно выглядеть следующим образом:

drawer->glGenVertexArrays(1, &vao);
drawer->glGenBuffers(1, &vbo);
drawer->glGenBuffers(1, &ebo);

drawer->glBindVertexArray(vao);

float * vertices = new float[9]{-0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f, 0.0f, 0.5f, 0.0f};
indices = new unsigned int[3]{0,1,2};

drawer->glBindBuffer(GL_ARRAY_BUFFER, vbo);
drawer->glBufferData(GL_ARRAY_BUFFER, 9*sizeof(float), vertices, GL_STATIC_DRAW);

drawer->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
drawer->glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * sizeof(unsigned int), indices, GL_STATIC_DRAW);

drawer->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
drawer->glEnableVertexAttribArray(0);

//РИСУЕМ
drawer->glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);

Но это не работает в Qt, потому что, как я выяснил, изменив свой код, по какой-то причине glDrawElements здесь принимает указатель на данные в качестве последнего аргумента, что очень странно, потому что последний аргумент должен содержать смещение в EBO, так как сами данные уже загружены. Поэтому эти строки здесь совершенно бессмысленны:

drawer->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
drawer->glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * sizeof(unsigned int), indices, GL_STATIC_DRAW);

glDrawElements работает только так (не имеет значения были ли закомментированы две строки, упомянутые выше):

drawer->glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, indices);

Существует ли способ заставить glDrawElements принимать смещение в качестве последнего аргумента, а не указатель на индексы?

Ответ или решение

Вопрос, с которым вы столкнулись в вашем приложении на Qt6, касается использования функции glDrawElements, а именно почему она, похоже, не использует данные из элемента массива (EBO) так, как ожидалось. Давайте разберем это подробнее.

Понимание VAO и EBO

Вы совершенно правы, подразумевая, что Vertex Array Object (VAO) и Element Buffer Object (EBO) предназначены для загрузки данных в память GPU, чтобы минимизировать количество передаваемых данных за каждую итерацию рендеринга. При правильно настроенных VAO и EBO вызов glDrawElements должен использовать индексы, находящиеся в EBO, а не требовать указателя на данные индексов.

Стандартное использование glDrawElements

Обычно, при вызове glDrawElements в OpenGL, последний параметр определяет смещение в данных индексов, если они хранятся в EBO. Однако, если вы указываете указатель на данные индексов, OpenGL интерпретирует это как загрузку индексов непосредственно из заданного указателя в памяти.

Ваш код:

drawer->glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, indices);

вызывает типичное поведение, когда вы передаете адрес, где находятся ваши индексы. Это работает, но не соответствует стандартному использованию EBO.

Почему это может происходить в Qt6

  1. Контекст OpenGL: Возможно, что контекст OpenGL, используемый в Qt6, настроен таким образом, что не позволяет оптимально использовать EBO. Убедитесь, что вы используете совместимую версию OpenGL с поддержкой VAO и EBO.

  2. Драйверы / Платформа: Различные драйверы графики могут интерпретировать вызовы OpenGL по-разному. Это может вызвать неожиданные результаты. Убедитесь, что вы используете последние версии драйверов для вашей графической карты.

  3. Ошибки при связывании: Убедитесь, что в вашем коде нет ошибок в связывании VAO и EBO перед рендерингом. Например, проверьте, что:

    • Вы вызываете glBindVertexArray(vao) перед glDrawElements.
    • Вы вызываете glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); перед glDrawElements.

Как использовать glDrawElements правильно

Если вы хотите, чтобы glDrawElements использовал информацию из EBO, ваш вызов должен выглядеть следующим образом:

// Обязательная установка
drawer->glBindVertexArray(vao);
drawer->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);

// Рендеринг с использованием индексов из EBO
drawer->glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, (void*)0);

Заключение

Если после выполнения всех проверок у вас все еще не работает правильно, рассмотрите возможность создания минимального воспроизводимого примера, чтобы процесс отладки был более эффективным. Сообщение об ошибках и их контекст могут также помочь в нахождении решения. Возможно, другие разработчики и эксперты в OpenGL смогут предоставить вам необходимую помощь в сообществе, если ваш вопрос будет должным образом переформулирован и уточнен.

Если вам нужно больше разъяснений или дополнительных примером кода, не стесняйтесь задавать вопросы.

Оцените материал
Добавить комментарий

Капча загружается...