Ошибка быстрого создания объекта OpenGL

8

У меня есть некоторый код, который проходит через набор объектов и отображает экземпляры этих объектов. Список объектов, которые должны быть отображены, хранится в виде std :: map>, где объект класса MeshResource содержит вершины и индексы с фактическими данными, а объект classMeshRenderer определяет точку в пространстве, в которой должна находиться сетка. предоставлено в.

Мой код рендеринга выглядит следующим образом:

glDisable(GL_BLEND);
    glEnable(GL_CULL_FACE);
    glDepthMask(GL_TRUE);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);

    for (std::map<MeshResource*, std::vector<MeshRenderer*> >::iterator it = renderables.begin(); it != renderables.end(); it++)
    {
        it->first->setupBeforeRendering();
        cout << "<";
        for (unsigned long i =0; i < it->second.size(); i++)
        {
            //Pass in an identity matrix to the vertex shader- used here only for debugging purposes; the real code correctly inputs any matrix.
            uniformizeModelMatrix(Matrix4::IDENTITY);
            /**
             * StartHere fix rendering problem.
             * Ruled out:
             *  Vertex buffers correctly.
             *  Index buffers correctly.
             *  Matrices correct?
             */
            it->first->render();
        }
        it->first->cleanupAfterRendering();
    }

    geometryPassShader->disable();
    glDepthMask(GL_FALSE);
    glDisable(GL_CULL_FACE);
    glDisable(GL_DEPTH_TEST);

Функция в MeshResource, которая обрабатывает настройку униформ, выглядит следующим образом:

void MeshResource::setupBeforeRendering()
{
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    glEnableVertexAttribArray(2);
    glEnableVertexAttribArray(3);
    glEnableVertexAttribArray(4);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID);
    glBindBuffer(GL_ARRAY_BUFFER, vboID);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0); // Vertex position
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*) 12); // Vertex normal
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*) 24); // UV layer 0
    glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*) 32); // Vertex color
    glVertexAttribPointer(4, 1, GL_UNSIGNED_SHORT, GL_FALSE, sizeof(Vertex), (const GLvoid*) 44); //Material index
}

Код, который отображает объект:

void MeshResource::render()
{
    glDrawElements(GL_TRIANGLES, geometry->numIndices, GL_UNSIGNED_SHORT, 0);
}

И код, который очищает это:

void MeshResource::cleanupAfterRendering()
{
    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);
    glDisableVertexAttribArray(2);
    glDisableVertexAttribArray(3);
    glDisableVertexAttribArray(4);
}

Конечным результатом этого является то, что я получаю черный экран, хотя конец моего конвейера рендеринга после кода рендеринга (по сути, просто рисование осей и линий на экране) работает должным образом, поэтому я уверен, что это не проблема с прохождение униформы. Однако, если я немного изменю код, чтобы код рендеринга вызывал настройку непосредственно перед рендерингом, вот так:

void MeshResource::render()
{
    setupBeforeRendering();
    glDrawElements(GL_TRIANGLES, geometry->numIndices, GL_UNSIGNED_SHORT, 0);
}

Программа работает по желанию. Однако я не хочу этого делать, поскольку моя цель - настроить данные вершин, материалов и т. Д. Один раз для каждого типа объекта, а затем визуализировать каждый экземпляр, обновляя только информацию преобразования.

UniformizeModelMatrix работает следующим образом:

void RenderManager::uniformizeModelMatrix(Matrix4 matrix)
{
    glBindBuffer(GL_UNIFORM_BUFFER, globalMatrixUBOID);
    glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(Matrix4), matrix.ptr());
    glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
HJ Media Studios
источник
У меня есть почти идентичные настройки для рендеринга моих моделей. За исключением того, что мой вызов render связывает буфер и каждый раз устанавливает указатели атрибутов. Вы сталкиваетесь с проблемами производительности с этим? Это работает очень быстро для меня.
MichaelHouse
Я не столкнулся с проблемами производительности, если у меня нет сотен идентичных объектов на экране, но все же я не могу понять, что здесь не так, и было бы здорово узнать, почему код работает не так, как ожидалось.
HJ Media Studios
1
Нам просто нужно привлечь внимание @NicolBolas, он является постоянным экспертом openGL.
MichaelHouse
Может быть хорошей идеей использовать offsetofпри указании атрибутов вершин
JBeurer

Ответы:

2

Прежде всего, OpenGL полон странных вещей, поэтому ошибка драйвера, какой бы маловероятной она ни была, по-прежнему является опцией - рассмотрите возможность тестирования приложения на разных настройках (nVidia против AMD, более старые драйверы) и других крошечных модификаций кода. Например, вы можете начать с удаления "glBindBuffer (GL_UNIFORM_BUFFER, 0);" линия - похоже, ничего полезного не делает.

Так как все здесь кажется правильным, проблема, скорее всего, не здесь. Есть два варианта: gDEBugger и пошаговое выполнение кода в отладчике C ++. Похоже, что что-то сбрасывается непосредственно перед рисованием. В gDEBugger есть функция «истории вызовов», которая может помочь вам увидеть, какие вызовы были сделаны до вызова и в каком порядке.

Кстати, я настоятельно рекомендую вам обернуть каждый вызывающий ошибку вызов макросом, который проверяет все возможные ошибки и выдает их. Это должен быть макрос для поддержки расширенной отладки (печать файла, строки и самой ошибочной строки кода), которую можно отключить в сборках выпуска. Если какое-то секретное правило нарушено, такая установка должна немедленно предупредить вас об этом.

snake5
источник
5
Я бы не стал ссылаться на сайт Gremedy. Эта версия gDEBugger древняя, неподдерживаемая и очень глючная. developer.amd.com/tools/heterogene-computing/amd-gdebugger - это современная версия, поддерживаемая AMD, с поддержкой Windows и Linux (к сожалению, без OS X). На сайте AMD есть и другие фантастические инструменты отладки и отладки GL, не говоря уже об инструментах, предлагаемых NVIDIA и Intel.
Шон Мидлдич
0

Я почти уверен, что атрибут должен привязываться к текущему буферу, поэтому нет никакой причины повторять этот бизнес с атрибутами каждый кадр, если вы не перестраиваете буфер каждый раз ....

Таким образом, вы, вероятно, должны сделать это так или иначе - либо оставить все как есть, либо перестраивать все целиком каждый кадр.

Yudrist
источник
0

TL; DR: ошибки водителя.

В моих тестах по состоянию на сегодня (октябрь 2016 г.) большинство драйверов не поддерживают должным образом одинаковые буферы .

Некоторые не уважают, glUniformBlockBindingнекоторые не обновляют унифицированные данные ( glBufferSubDataи glBufferData) должным образом, где кешированные шейдеры / графические процессоры внутренних копий указанных буферов не сохраняются согласованными.


То, как я понимаю это (и то, как Nvidia также понимает это)

  • Свяжите / сопоставьте ваш объект Uniform Buffer с глобальной таблицей, общей для всех шейдеров в драйвере / GPU OpenGL с помощью glBindBufferBaseили glBindBufferRange.
  • Сопоставьте доступ к унифицированному буферу шейдера с записью в эту глобальную таблицу, используя glUniformBlockBinding(shader_id, shader_ubo_index, global_ubo_index);этот параметр, для каждой программы шейдера , а не для общего доступа.

Примечание: global_ubo_index - это НЕ имя объекта единого буфера, а индекс в этой глобальной таблице.

Эта «сложность» (которая является отличной функцией для разделения UBO между различными шейдерами, например значениями освещения), кажется, что большинство драйверов OpenGL ошибаются. Чтобы быть справедливым, формулировка в документации OpenGL не самая однозначная, как это может быть.

Мне пришлось прибегнуть к использованию простой старой формы для других водителей.

Оба скриншота с использованием единых буферных объектов, два разных драйвера:

Унифицированные ошибки буфера

Стефан Хоккенхалл
источник
С какими драйверами вы тестировали? Какая платформа?
Акалтар