Отображение атрибутов вершинных шейдеров в GLSL - PullRequest
37 голосов
/ 02 февраля 2011

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

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

Каждый материал имеет набор текстур и свойств (например, specular-color, diffuse-color, color-texture, normal-map и т. Д.)

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

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

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

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

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

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

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

Редактировать:

Резюме предлагаемых методов:

1. Attribute / Uniform семантика задается именем переменной (что я сейчас делаю). Использование предопределенных имен для каждого возможного атрибута. Связыватель 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, Globals Engine, Renderer и Mesh

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

например:

 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 ]

16 голосов
/ 08 февраля 2011

Атрибуты:

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

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

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

Униформа:

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

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

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

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

  • Загрузчик заполняет декларации потоков данных сетки и словари материалов.
  • В Render используется шейдер, который знает имена, предоставляетдополнительные параметры и выбирает правильные сетки для рисования.
8 голосов
/ 07 февраля 2011

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

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

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

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

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

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

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

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

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

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

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

AFAIK - это наиболее распространенный способ ведения дел, например, OGRE . Это не ракетостроение, но хорошо работает на практике.

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

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

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

3 голосов
/ 07 февраля 2011

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

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

...