ОБНОВЛЕНИЕ: Поскольку мне было нужно что-то сразу, я создал простую шейдерную оболочку, которая делает то, что мне нужно. Вы можете найти его здесь: ShaderManager на GitHub. Обратите внимание, что он предназначен для Objective-C/iOS, поэтому может быть не пригоден для всех. Если у вас есть предложения по улучшению дизайна, пожалуйста, дайте мне знать!
Исходная проблема:
Я новичок в использовании шейдеров GLSL. Я достаточно хорошо знаком с языком GLSL и интерфейсом OpenGL, но мне сложно создавать простой API, с помощью которого можно использовать шейдеры.
Интерфейс OpenGL C для взаимодействия с шейдерами кажется громоздким. Кажется, я не могу найти учебники в сети, которые охватывают дизайн API таких вещей.
Мой вопрос таков: У любого есть хороший, простой, дизайн или шаблон API, чтобы обернуть API-интерфейс шейдерной программы OpenGL?
Возьмем следующий простой пример. Скажем, у меня есть один вершинный шейдер, который просто эмулирует фиксированную функциональность и два флеш-шейдера - один для рисования гладких прямоугольников и один для рисования гладких кругов. У меня есть следующие файлы:
Shader.vsh : Simple vertex shader, with the following inputs/outputs:
-- Uniforms: mat4 Model, mat4 View, mat4 Projection
-- Attributes: vec4 Vertex, vec2 TexCoord, vec4 Color
-- Varying: vec4 vColor, vec2 vTexCoord
Square.fsh : Fragment shader for drawing squares based on tex coord / color
Circle.fsh : Fragment shader for drawing circles based on tex coord / color
Базовая привязка
Теперь, каков стандартный способ их использования? Связать ли эти шейдеры с двумя шейдерами OpenGL? То есть:
Shader.vsh + Square.fsh = SquareProgram
Shader.vsh + Circle.fsh = CircleProgram
Или я вместо этого создаю одну большую программу, где шейдеры фрагментов проверяют некоторые условные равномерные переменные и вызывают функцию шейдера для генерации их результата. Например:
Shader.vsh + Square.fsh + Circle.fsh + Main.fsh = ShaderProgram
//Main.fsh here would simply check whether to call out to square or circle
С двумя отдельными программами мне, вероятно, нужно будет позвонить
glUseProgram(CircleProgram); or glUseProgram(SquareProgram);
Перед каждым типом элемента я хочу рисовать. Затем я должен был установить форму (Модель/Вид/Проекция) и атрибуты каждой программы, прежде чем использовать ее. Это кажется таким громоздким.
С помощью единственной опции ShaderProgram мне все равно нужно установить какой-то булевский переключатель (круг или квадрат) в шейдере фрагмента, который будет проверяться перед рисованием каждого пикселя. Это также кажется сложным.
Как замечание, мне удалось связать два фрагментарных шейдера, каждый с функцией main(), в одну шейдерную программу? Как OpenGL узнает, какой из них вызывать?
Установка переменных
Вызовы:
glUniform*
glVertexAttribPointer
Используются для установки униформ и местоположений указателя атрибутов в текущей программе.
Для разных классов и структур может потребоваться доступ и установка переменных в текущем шейдере (или изменении текущего шейдера) из разных мест кода. Я не могу придумать хороший способ сделать это, что отделяет шейдерный код от кода, который хочет его использовать.
То есть для каждой фигуры, которую я хочу рисовать, необходимо будет установить атрибуты координаты вершины и текстуры - требуя дескрипторов для этих атрибутов, сгенерированных OpenGL.
Камера должна будет установить свою матрицу проекции как однородную в вершинном шейдере, тогда как классу, управляющему стеке матрицы модели, необходимо будет установить свою собственную униформу в вершинном шейдере.
Изменение шейдеров на части путем рисования сцены означало бы, что всем этим классам потребуется снова установить их униформы и атрибуты.
Как большинство людей проектируют вокруг этого?
Глобальный словарь шейдеров, к которым обращается дескриптор или имя, с геттерами и сеттерами для их параметров?
Конструкция OO с шейдерными объектами, каждая из которых имеет параметры?
Я просмотрел следующие обертки:
Jon Teapot: GLSL Shader Manager - Это оболочка шейдеров в классах С++. Похоже, что это не что иное, как оболочка, которая обеспечивает принципы OO в C API, в результате чего API С++ практически одинаковый.
Я после любого вида дизайна, который упрощает использование программ Shader, и меня не интересует конкретная используемая парадигма (OO, процедурная и т.д.)