Подтвердить что ты не робот

Отображение атрибутов шейдера вершин в GLSL

Я кодирую небольшой движок рендеринга с шейдерами GLSL:

Каждая Mesh (ну, submesh) имеет несколько вершинных потоков (например, положение, нормаль, текстура, тангенс и т.д.) в один большой VBO и MaterialID.

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

Затем у меня есть шейдер GLSL, с его формами и атрибутами. Пусть говорят:

uniform vec3 DiffuseColor;
uniform sampler2D NormalMapTexture;
attribute vec3 Position;
attribute vec2 TexCoord;

Я немного застрял в попытке разработать способ шейдера GLSL для определения сопоставлений потоков (семантики) для атрибутов и униформ, а затем привязать вершинные потоки к соответствующим атрибутам.

Что-то в строках выражения сетке: "Поместите свой позиционный поток в атрибут" Позиция "и ваши текс-координаты в" TexCoord ". Также поместите свой материал в диффузный цвет в" DiffuseColor "и ваш материал второй текстуры в" NormalMapTexture ""

В настоящее время я использую жестко закодированные имена для атрибутов (т.е. vertex pos всегда "Position" и т.д.) и проверяя каждое унифицированное имя и имя атрибута, чтобы понять, для чего используется шейдер.

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

Поэтому мне просто интересно, как это делают люди в широкомасштабных механизмах рендеринга.

Edit:

Рекомендации предлагаемых методов:

1. Атрибут/Равномерная семантика задается именем переменной (что я делаю сейчас) Использование предопределенных имен для каждого возможного атрибута. Связывание GLSL запрашивает имя для каждого атрибута и связывает массив вершин на основе имени переменной:

//global static variable

semantics (name,normalize,offset) = {"Position",false,0} {"Normal",true,1},{"TextureUV,false,2}

 ...when linking
for (int index=0;index<allAttribs;index++)
{
   glGetActiveAttrib(program,index,bufSize,length,size[index],type[index],name);      
   semantics[index]= GetSemanticsFromGlobalHardCodedList(name);
} 
... when binding vertex arrays for render
 for (int index=0;index<allAttribs;index++)
{
    glVertexAttribPointer(index,size[index],type[index],semantics[index]->normalized,bufferStride,semantics[index]->offset);

}  

2. Предопределенные местоположения для каждого семантического

Связующее GLSL всегда связывает массивы вершин с теми же местами. Это зависит от того, будет ли шейдер использовать соответствующие имена для соответствия. (Это кажется ужасно похожим на метод 1, но если я не понял, это подразумевает привязку ВСЕХ доступных вершинных данных, даже если шейдер не потребляет их)

.. when linking the program...
glBindAttribLocation(prog, 0, "mg_Position");
glBindAttribLocation(prog, 1, "mg_Color");
glBindAttribLocation(prog, 2, "mg_Normal");

3. Словарь доступных атрибутов из Material, Engine globals, Renderer и Mesh

Поддерживать список доступных атрибутов, опубликованных активным Материалом, глобальными двигателями, текущим рендерером и текущей сценой Node.

например:

 Material has (uniformName,value) =  {"ambientColor", (1.0,1.0,1.0)}, {"diffuseColor",(0.2,0.2,0.2)}
 Mesh has (attributeName,offset) = {"Position",0,},{"Normals",1},{"BumpBlendUV",2}

затем в шейдере:

 uniform vec3 ambientColor,diffuseColo;
 attribute vec3 Position;

При привязке данных вершин к шейдеру связующее GLSL будет перебирать атрибуты и связываться с найденным (или нет?) в словаре:

 for (int index=0;index<allAttribs;index++)
    {
       glGetActiveAttrib(program,index,bufSize,length,size[index],type[index],name);      
      semantics[index] = Mesh->GetAttributeSemantics(name);
}

и то же самое с униформами, только запрос активен и материал и глобалы.

4b9b3361

Ответ 1

Свойства:

В вашей сетке есть несколько потоков данных. Для каждого потока вы можете сохранить следующую информацию: (имя, тип, данные).

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

Когда вы рисуете сетку с указанной программой GLSL, вы просматриваете словарь атрибутов программ и связываете соответствующие потоки сетки (или сообщаете об ошибке в случае несогласованности).

Обмундирование:

Пусть словарь параметров шейдера - это набор (имя, тип, ссылка на данные). Как правило, у вас могут быть следующие словари:

  • Материал (диффузный, зеркальный, блеск и т.д.) - взято из материала
  • Двигатель (камера, модель, огни, таймеры и т.д.) - взяты из одномодового двигателя (глобальный)
  • Render (настраиваемые параметры, связанные с создателем шейдера: радиус SSAO, размер размытия и т.д.) - предоставляется исключительно классом создателя шейдера (рендеринга)

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

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

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

Ответ 2

По моему опыту, OpenGL не определяет концепцию семантики атрибутов или униформы.

Все, что вы можете сделать, это определить свой собственный способ сопоставления семантики с переменными OpenGL, используя единственный параметр, который вы можете контролировать об этих переменных: их расположение.

Если вы не ограничены проблемами платформы, вы можете попытаться использовать "новый" GL_ARB_explicit_attrib_location (ядро в OpenGL 3.3, если я 'm not mistaken), который позволяет шейдерам явно выражать, какое местоположение предназначено для какого атрибута. Таким образом, вы можете жестко задавать (или настраивать), какие данные вы хотите привязать к местоположению атрибутов, и запрашивать местоположение шейдеров после их компиляции. Похоже, эта функция еще не созрела и, возможно, подвержена ошибкам в различных драйверах.

Другим способом является привязка местоположений ваших атрибутов с помощью glBindAttribLocation. Для этого вам нужно знать имена атрибутов, которые вы хотите привязать, и местоположения, которые вы хотите назначить им.

Чтобы узнать имена, используемые в шейдере, вы можете:

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

Я бы не рекомендовал использовать метод разбора GLSL (хотя он может удовлетворить ваши потребности, если вы в достаточно простых контекстах): синтаксический анализатор легко может быть побежден препроцессором. Предположим, что ваш шейдерный код становится несколько сложным, вы можете начать использовать #includes, #defines, #ifdef и т.д. Надежный синтаксический анализ предполагает, что у вас есть надежный препроцессор, который может стать довольно тяжелым лифтом для настройки.

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

В нашем движке мы с радостью помещаем места предопределенных имен определенным значениям, например:

glBindAttribLocation(prog, 0, "mg_Position");
glBindAttribLocation(prog, 1, "mg_Color");
glBindAttribLocation(prog, 2, "mg_Normal");
...

После этого, он должен записывать шейдер, чтобы он соответствовал предопределенной семантике атрибутов.

AFAIK это самый распространенный способ делать вещи, OGRE использует его, например. Это не ракетостроение, но хорошо работает на практике.

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

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

Меня это не устраивает, поэтому я буду рад иметь некоторую противоречивую информацию:)

Ответ 3

Возможно, вы захотите рассмотреть собственно анализ самого GLSL.

Синтаксис объявления единообразного/атрибута довольно прост. Вы можете создать небольшой ручной синтаксический анализатор, который ищет строки, начинающиеся с uniform или attribute, получить тип и имя, а затем выставить некоторые С++ API, используя строки. Это избавит вас от проблем с жестко закодированными именами. Если вы не хотите, чтобы ваши руки были грязными при ручном разборе, пара подобных Spirit сделала бы трюк.
Вероятно, вы не захотите полностью разбирать GLSL, поэтому вам нужно убедиться, что вы не делаете ничего смешного в замедлениях, которые могут изменить реальный смысл. Одним из осложнений, которые приходит на ум, является условная компиляция с использованием макросов в GLSL.