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

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

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

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

тогда у меня есть шейдер GLSL, с его униформой и атрибутами. Скажем:

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

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

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

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

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

так мне просто интересно, как люди делают это в крупных движки.

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 binder всегда будет привязывать массивы вершин к одним и тем же местоположениям.Шейдер должен использовать соответствующие имена для спичка. (Это кажется ужасно похожим на метод 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

ведение списка доступных атрибутов, опубликованных активным материалом, глобалами движка, текущим визуализатором и текущим узлом сцены.

например:

 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);
}

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

3 ответов


атрибуты:

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

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

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

форме:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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