Перевод статьи о шейдерах из блога разработчиков GMS. Оригинал
тут. Сразу прошу прощения за мой посредственный английский. Просьба сообщать в ЛС о неточностях перевода (или если у вас есть более удачный вариант перевода).
Вторая часть
тутАвтор: Mike Dailly
Перевод: Dmi7ry
Примеры использования шейдеров
В связи с близким выходом Студии v1.2, самое время приоткрыть завесу над тем, что такое шейдеры, что они могут делать и как их можно будет использовать в Студии. Однако, так как это довольно большая тема, я разделю её на несколько статей, и первая будет содержать обзор, который даст вам идеи, каким образом вы будете использовать их.
Стоит обратить внимание на то, что Студия нацелена на кросс-платформенную разработку, и мы выбрали шейдерный язык, который позволит нам легко делать это -
GLSL ES, так как он может быть автоматически преобразован во все другие типы. Это в свою очередь означает, что вам достаточно написать шейдер только один раз и он будет работать везде, где есть шейдеры.
Также нужно отметить то, что
GLSL ES имеет некоторые ограничения, но мы их рассмотрим позже. А для начала давайте вкратце рассмотрим, что такое шейдеры и как они работают.
Обзор шейдеров: часть 1Во-первых, что такое шейдеры? Когда мы говорим о шейдерах, мы на самом деле говорим о двух различных типах программ, которые работают непосредственно на видеокарте - вершинном шейдере (vertex shader) и пиксельном шейдере (pixel shader). Обе эти небольшие программы работают вместе, манипулируя тем, что видеокарта выводит на экран, позволяя в режиме реального времени менять позицию и цвет (или RGBA) данных, которые фактически заносятся в буфер дисплея.
Итак, какие же эффекты способны делать шейдеры? Если кратко - почти любые. Давайте возьмём несколько примеров, что разработчики хотели бы сделать в Студии, но просто не могут сейчас.
Насыщенность цвета. Допустим, при выстреле в плохого парня вы хотите, чтобы бандит "вспыхнул", позволяя игроку узнать, что пуля попала в цель. В настоящее время мы можем его сделать темнее, но не светлее. То есть если мы сейчас устанавливаем цвет рисования
c_black, спрайт станет выглядеть подобно тени, но мы не сможем сделать наоборот - по крайней мере, не очень легко. Какие-то разработчики используют некоторые трюки с затемнением, но это не особо хорошее решение. Однако с шейдерами это становится сделать гораздо проще: так как пишется информация о цвете, вы можете просто изменить значения на белый (или любой другой цвет), сохраняя при этом уровень прозрачности (который сохраняет форму в целости). И это крошечный шейдер, который позволил создать вспышку, которую все искали.
Конечно же, вы можете сделать гораздо больше - вроде правильной глубины резкости, преломление стекла и воды, сдвиг цветового пространства
HSV или даже использовать множественные текстуры для таких вещей, как карты нормалей и так далее. Если вы можете что-то представить, вероятно, это можно сделать.
В прошлом я также использовал их, чтобы делать вещи, которые на самом деле не имеют ничего общего с рендерингом. Я присваивал каждому объекту значение и тогда рендерил его. Как только весь экран был отрендерен, я мог "взять" цвет с экрана и перевести его обратно в объект, на который я нажал. Для выбора из десятков тысяч объектов, это было очень удобно и просто.
Очевидно, что всё это невероятно мощно. Итак, что делает Студия при рендеринге? Хорошо, когда мы строим четырёхугольный полигон, это на самом деле два треугольника, каждый из которых имеет собственный набор данных о вершинах - позиция вершины, цвет и информация о текстуре, которую использует видеокарта для построения.
Как же эти данные выглядят? Каждая точка содержит X, Y, Z (для 2D координата Z не существенна), цвет и координаты текстуры для U и V в диапазоне от 0.0 до 1.0. Это образует один угол, выглядя примерно так:
X=10
Y=10
Z=1
Colour=$FFFFFFFF
U=0.0
V=1.0
Перед тем, как с головой погрузиться в написание шейдеров, давайте посмотрим, как они создаются и используются в Студии.
Шейдеры были добавлены в качестве обычного ресурса с возможностью их редактирования через встроенный редактор скриптов, включая подсветку синтаксиса и использование автозавершения. Вместе с тем, мы также немного доработали редактор, чтобы создавать их было ещё проще.
Как вы можете видеть, в настоящее время в редакторе скриптов есть две вкладки, названные Vertex (вершинные шейдеры) и Fragment (или Pixel, пиксельные шейдеры), внутри которых вы можете написать соответствующий скрипт. Точно так же, как имена скриптов, у каждого шейдера есть имя, которое вы можете использовать для выбора шейдера.
Как вы можете увидеть из изображения выше, Студия будет также утверждать некоторые определённые вещи для вас, такие как матрицы, освещение и различные другие установки, освобождая вас от необходимости устанавливать их.
Теперь, когда мы можем создать шейдер, как мы можем его использовать внутри Студии? Здесь есть два аспекта шейдеров. Первый - непосредственно дескриптор шейдера и второй - константы шейдера (как вершинного так и пиксельного). Сначала нужно установить шейдер, что очень просто:
shader_set( MaskShader );
а затем, чтобы отключить его использование:
shader_reset();
Теперь, когда вы можете сделать некоторые интересные вещи только с этим, что делает шейдеры неоценимыми, это возможность установить константы непосредственно в шейдере. Чтобы получить константу, видимую и в шейдере и в
GML через
GLSL ES, вы должны использовать ключевое слово
UNIFORM. Затем вам нужно использовать их, чтобы передать конкретные детали в экземпляр, такие, как, например, оттенок цвета, сила свечения или даже преломления.
Однако, первое, что вам нужно сделать - получить дескриптор каждой константы. Здесь есть два типа констант: униформы (uniforms) и образцы (samplers). Униформы - это обычные константы: целые, булевы, плавающие, векторы, матрицы и т.п., в то время как образцы - это текстуры. В отличии от обычного использования GML, вы можете использовать до 8 текстур одновременно - или столько, сколько поддерживает устройство, так как количество может быть меньше.
В приведённом выше примере маски нам понадобится доступ к униформе
u_vMaskCol. Этот четырёхмерный вектор (vec4) мы используем в пиксельном шейдере для установки цвета маски, применяемую, когда используется спрайт попадания - как следствие, мы можем "мигать" (или делать блеклым) спрайтом в качестве эффекта.
global.maskshader_col = shader_get_uniform( MaskShader, “u_MaskCol” );
Будет искаться переменная и, если она найдена, её дескриптору будет присваиваться значение глобальной переменной
maskshader_col. После, когда захотите установить константу, вы можете использовать эту переменную, устанавливая её так, как вам нравится.
shader_set( MaskShader );
shader_set_uniform_f( global.maskshader_col, Red, Green, Blue, AlphaMask );
Сначала вы устанавливаете шейдер, который берёт на себя рендеринг из Студии, а также говорит системе, какие из констант шейдера будут установлены. Значения передаются в простых переменных с плавающей запятой, а что они означают, будет определяться вашим шейдером.
И вот оно! Студия будет заполнять все матрицы видов/проекций, устанавливать основные текстуры (названные
gm_BaseTexture) и после вызывать ваш шейдер, когда идёт отрисовка спрайтов/тайлов/фонов и т.п.
Все пиксельные шейдеры требуют чтобы вы установили
gl_FragColor при выходе и этот vec4 выведется на экран.
Для обычного использования вы можете по-прежнему использовать команды вроде
draw_self(),
draw_sprite_ext() и т.п., и Студия будет создавать примитивы, настраивать матрицы и текстуры, предоставляя вам простую работу по отрисовке пикселей.
Итак, это была первая часть. Вторая часть будет содержать подробности создания и использования шейдеров. А сейчас - немного
*кхе-кхе* лёгкого чтения -
спецификация языка шейдеров OpenGL ES