Материал OpenGL для каждой сетки (шейдер)

Итак, я работаю над простым игровым движком с C++ и OpenGL 4. Сейчас я борюсь с рендерингом импортированных моделей.

Я использую FBX sdk для импорта моделей fbx, используя очень наивный подход: в основном я посещаю каждый узел fbx и добавляю данные сетки в одну большую структуру, которая позже используется для рендеринга. Однако я хочу иметь возможность указать другой шейдер фрагмента для каждого материала, используемого моделью (например, другой шейдер для автомобильных дисков и фар).

Для справки: в UE4 есть система материалов, которая позволяет пользователю определять простой шейдер с помощью редактора, похожего на чертеж.

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

Проблемы, с которыми я сталкиваюсь:

  1. Понятно, что я должен разделить вызовы отрисовки для каждой части модели, в которой используется другой материал, поскольку я не могу поменять местами программу в середине вызова отрисовки (можно ли?): на данный момент лучше иметь отдельный vao /vbo/ebo для каждой части или отдельной и отслеживать, где заканчивается часть и начинается следующая? (думаю это лучший вариант)
  2. Хорошей практикой является предварительная компиляция только фрагмента шейдера и подключение его к текущей программе на лету (например, glAttach + glLinkProgram + glUseProgram) или лучше предварительно связать всю программу для каждого материала, учитывая, что вершина шейдер всегда один и тот же?

person Sneppy    schedule 26.09.2018    source источник


Ответы (1)


  1. Нет, вы не можете изменить программу в середине вызова отрисовки. Существуют разные мнения и тесты о том, как будет работать графический процессор в зависимости от расположения ваших данных. По моему опыту, если вы не собираетесь изменять данные своих мешей после их первой загрузки, наиболее эффективным способом будет иметь один VAO с двумя VBO: один для индексов и один для остальных данных. Выполняя вызовы отрисовки, вы смещаете буфер индексов на основе данных сетки (которые вы должны отслеживать), а также смещаете конфигурацию атрибутов шейдера. Такой подход обеспечивает более удобный для кэширования и эффективный доступ к памяти, поскольку блок памяти будет непрерывным. Однако, как я уже упоминал, бывают случаи, когда это не самый эффективный подход (хотя я считаю, что он все равно будет достаточно эффективным). Это зависит от вашего железа и драйвера.

  2. Предварительно скомпилируйте и свяжите все свои программы перед запуском цикла рендеринга. Это самый эффективный подход

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

person Nadir    schedule 26.09.2018
comment
вы смещаете буфер индексов на основе данных сетки * и *смещаете конфигурацию атрибутов шейдера Зачем это делать? В том, чтобы не делать этого, и заключается весь смысл glDrawElementsBaseVertex и ему подобных. - person Nicol Bolas; 26.09.2018
comment
@NicolBolas, и это то, о чем я говорил. Я не имел в виду, что он должен изменить индексы или положение вершин в буферах, мой плохой, если это было непонятно для вас - person Nadir; 26.09.2018