Войти
ПрограммированиеФорумГрафика

Динамическая генерация шейдеров

Страницы: 1 2 Следующая »
#0
2:36, 14 апр. 2015

Приветствую.

Задался вопросом динамической генерации кода шейдера, но пока не знаю как к этому всему подступиться. Хочется в результате получить что-то типа узлового редактора материалов, т.е. собирать программу из неких заготовок: модели освещения, текстурирование, смешивание и т.п.

Кто уже занимался подобным или просто имеет представление как это сделать? Как хранить сниппеты и объединять их в конечный код? В гугле ничего не нашел, поэтому надеюсь на вашу помощь. API и ЯП не имеют значения, мне интересен сам подход.


#1
3:24, 14 апр. 2015

CGAdept
> В гугле ничего не нашел
погугли Micro Shader (типа http://www.shawnhargreaves.com/hlsl_fragments/hlsl_fragments.html)

Возможно оно

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

#2
5:08, 14 апр. 2015

Сначала определись какие функции должны быть доступны чрез подобное редактирование. У меня получилось около 17 функций с разной реализацией.

#3
11:19, 14 апр. 2015

Делал подобную вещь но для OpenCL. По сути получается тупо работа со строками и все. Если интересно - https://github.com/Kvalme/libclnoise

#4
14:19, 14 апр. 2015

war_zes, спасибо за отправную точку. Messenger, спасибо за код, но я подозреваю, что там не тупо со строками работать придется.

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

gl_FragColor = vec4(0.5, 0.5, 0.5, 1.0);

Допустим, я хочу передать в код параметр, определяющий финальный цвет.

gl_FragColor = myConst;
Ну и кроме того добавлю ключевые слова const vec4 myConst=... - это дело техники.

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

gl_FragColor = myFactor * myConst;

Собственно пока одно до меня не дойдет - в какой структуре данных хранить эту информацию. Пока предполагаю ориентированный граф.

Бунтарчик, мне бы пока с алгоритмом разобраться. Или набор предполагаемых функций очень важен даже на данном этапе? Я просто предполагаю держать в узле сниппет кода и подставляемые значения - какой угодно сложности, например, для Ламберта "saturate(dot(%0, %1))", где %0 - это нормаль, а %1 - вектор освещения. И в процессе сборки кода эти значения заменятся на то, что я укажу.

#5
14:34, 14 апр. 2015

По простому - каждый узел хранит что-то типа:

res_type result_N = func(param1,param2);

Например имеем:

add:

vec4 result_N = param1 + param2;

mul:

vec4 result_N = param1 * param2;

result:

gl_FragColor  = param1;

Затем когда генерируем, то выстраиваем по порядку строки заменяя шаблонные имена:

vec4 result_1 = 1.0+2.0; // Раскрытый add(1.0,2.0) 
vec4 result_2 = result_1*1.5; // Раскрытый mul add(result_1 ,1.5)
gl_FragColor = result_2; // Раскрытый result(result_2)
Где числа 1.0,2.0,1.5 - для примера - можно из юниформов/аттрибутов достать.

Как-то так.

#6
14:39, 14 апр. 2015

Che@ter
Спасибо, кое-что уже начало доходить) Чуть позже отпишусь о том, что получилось или к чему пришел.

#7
14:42, 14 апр. 2015

По поводу хранения - я специально для использования этой либы писал гуй в котором строилась схема типа ((Perlin, Billow) ->Min->Gradient->PlaneMap) это в виде xml передается в генератор и уже создается сам код шейдера.
Для генерации кода разные модули вынесены в отдельные функции (см src/modules) где описаны их входы и выходы по которым и определяется можно ли построить такую схему и откуда брать параметры. Поэтому появилось в коде чтото вида float frequency = floatAtt[0];
Понятно что для других шейдеров это не проканает, но по сути просто надо будет не 2 массива использовать, а создать униформы или атрибуты

#8
14:52, 14 апр. 2015

CGAdept
> мне бы пока с алгоритмом разобраться. Или набор предполагаемых функций очень
> важен даже на данном этапе?
Так вроде вся проблема только в том, как определить набор функций.
Потому что если у тебя OpenGL, то слинковать множество фрагментных шейдеров вместе не составляет труда, это входит в базовый функционал OpenGL. Соответственно берёшь свои функции, выносишь каждую из них в соответствющий шейдер, компилируешь все эти шейдеры и линкуешь вместе. У меня в движке так сделано.

Если интересно, вот стадии:
http://sourceforge.net/p/shengine/code/HEAD/tree/SH-Engine/Shaders/Stages/

Код линковки шейдеров:
http://sourceforge.net/p/shengine/code/HEAD/tree/SH-Engine/Includ… /shShader.cpp

Для удобства я сделал возможность использовать хедеры в шейдерах.

Например мне нравится как я сделал функцию эмиссии:
http://sourceforge.net/p/shengine/code/HEAD/tree/SH-Engine/Shader… Emission.glsl

Есть варианты:
"solid" - обычное свечение
"angular" - свечение с зависимостью от угла зрения (4-й параметр - степень)
"directed" - свечение с зависимостью от направления нормали (4-й параметр - степень)
"display" - эффект экрана (первые два параметра задают разрешение, третий - яркость)
"diffuse" - режим, при котором свечение выступает в роли эмбиента
В соответствии с заданным из материала режимом, подставляется нужный дефайн, который делает соответствующую ветку в шейдере.

#9
22:16, 14 апр. 2015

Я сейчас пилю модульную систему шейдеров. Я придумал такую терминологию:
1) Интерфейс шейдера - это uniform'ы, которые он принимает
2) Формат вершин - это атрибуты вершинного шейдера
3) Тип модуля шейдера - это прототип функций для каждого шейдерного этапа, а также набор реализуемых интерфейсов. Также содержит в себе модуль своего типа по умолчанию
4) Модуль шейдера - реализация функций из соответствующего типа
5) Шаблон модуля - это объект, который может генерировать модуль шейдера каким-либо образом
  а) Частный случай шаблона - паттерн модуля - просто строка с кодом, в которую потом подставляются значения параметров. Разные параметры приведут к созданию разных модулей
6) Шаблон шейдера - имеет фиксированный набор типов модулей. Представляет собой код main'а и может быть чего-то ещё, в коде указано место, куда должен подставляться полный код всех модулей генератора
7) Генератор шейдеров - указывает на шаблон шейдера и содержит в себе все модули. Вызовом ToShader() создаёт на основе всего этого готовый шейдер

Всё реализовано через строки, параметры хранятся в map<string, string>. Вручную в коде весь этот зоопарк настраивать неудобно, поэтому я собираюсь описывать всё это в файле. Сейчас делаю парсер. Синтаксис можно увидеть в примере ниже. Он Си-подобный, но строки там можно записывать не только в кавычках, но и между такими двойными скобками {[ и ]}, чтобы подсветка синтаксиса шейдерного кода в редакторах работала. Пока я ещё не всё дописал и ещё даже не проверял, тут могут быть некоторые недоработки и конфликты. Но в общем, идея должна быть понятна.

+ Пример шаблона

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

#10
5:30, 15 апр. 2015

Подпишусь

p.s у меня сейчас убер-шейдер

#11
11:50, 15 апр. 2015

У меня получился почти свой язык с трансляцией в объектную модель и сборкой шейдеров из кусков. По сути, это такой компилятор убершейдера, только ifdef'ы оформляются не в коде шейдеров, а в отдельном коде модели материала.
Модель разделяется на несколько логических частей: интерфейс материала, интерфейс "сцены", биндинг инпутов (по сути, описание необходимых входных данных от вершин) и собственно, фрагменты кода из которых собираются шейдеры.
Интерфейсы материала и сцены это по сути наборы параметров различных типов (bool, float, color, vec, texture). Разница между интерфейсом материала и сцены в том, что по сути в интерфейсе материала описываются параметры, которые можно изменять для каждого отдельного объекта в сцене, а в интерфейсы сцены - глобальные для любого материала параметры (например - направление источника света, шадоумапы, включен ли АО и прочее). Есть не доделаный редактор под все это.

+ Показать

#12
13:07, 15 апр. 2015

Приветствую.

Решил сначала поступить по примеру Che@ter. Просто писать свой псевдоязык пока не хочется. Вот на чем остановился. Есть такие типы блоков:
1. Вывод шейдера - корневой узел, для вершинного шейдера - gl_Position, для фрагментного - gl_FragColor.
2. Данные. Константа, текстурный сэмплер, либо юниформ, технически не важно - просто тип данных.
3. Операция. Унарная, бинарная или полноценная функция, в общем, что-то, что преобразовывает данные.

Каждый блок имеет:
1. Ссылку на другой блок, если в этом есть необходимость. Например, блок умножения имеет две ссылки на аргументы. Каждый из аргументов может быть как типом данных, так и операцией.
2. Функцию, которая вносит изменения в текст шейдерной программы согласно своему определенному поведению.
3. Идентификатор - для связки с другими блоками.
4. Другая служебная информация.

Также есть хранилище, где эти блоки просто хранятся списком.

В качестве примера приведу такой фрагмент кода:
vec3 finalCOlor = color * intesity;
gl_FragColor = vec4(finalColor, 1.0f);

Чтобы собрать этот шейдер в хранилище должны быть такие блоки:
1. Вывод шейдера - ссылается на блок №4.
2. Данные color.
3. Данные intensity.
4. Операция "Умножение" - ссылается на блоки №2 и №3.

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

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

P.S. Может разбавить текст пояснительными картинками?

#13
14:53, 15 апр. 2015

CGAdept
> Однако, сдается мне, что иду я не по тому пути, ибо накладные расходы на
> создание такого шейдера выше, чем ручное написание кода. Как считаете?
Надеемся на компилятор. Возможно после создания такого шейдера нужно вручную пооптимизировать(поискать параметры с одиночным участием в других аргументах).

В целом шейдеры лучше писать вручную... это быстрее. Но при использовании такого графа можно будет вывести результат как в glsl, так и hlsl.

#14
5:44, 16 апр. 2015

Пилю прототип, а там видно будет - стоит оно того или нет.

Страницы: 1 2 Следующая »
ПрограммированиеФорумГрафика

Тема в архиве.