ShaderLab
Прежде чем начать писать шейдер, нам нужно изучить ShaderLab. ShaderLab - это
описательный язык программирования, внутри которого пишется сам
шейдер.Этот язык выполняет различные функции:язык механизм под названием ShaderLab берет на свои
плечи очень много задач, которые не приходится выполнять нам, поэтому не
изучать его нам не представляется никакой возможности.
описательный язык программирования, внутри которого пишется сам
шейдер.Этот язык выполняет различные функции:
- Содержит в себе шейдерный код
- Обеспечивает взаимодействие с инспектором и материалом
- Включает в себя встроенные переменные и функции, облегчающие процесс
- Описывает свойства шейдера
- Содержит множество решений для различного графического оборудования
- ...
плечи очень много задач, которые не приходится выполнять нам, поэтому не
изучать его нам не представляется никакой возможности.
Структура ShaderLab
ShaderLab является языком программирования, а значит как и у любого
языка, у него есть своя струтура.
Давайте разбираться. :)
Любой шейдер в юнити пишется по такому шаблону:
языка, у него есть своя струтура.
Давайте разбираться. :)
Любой шейдер в юнити пишется по такому шаблону:
Shader "Name" { [Properties] SubShader{CGPROGRAM Код на языке CG
ENDCG} [Fallback] }
Начинается шейдер с ключевого слова Shader, после, в кавычках,
указывается имя шейдера. Причем в имени можно указать путь в
выпадающем окне выбора шейдера в материале. Далее идет блок свойств.
Начинается он с ключевого слова Properties {}. Остановимся на нем
поподробнее.
указывается имя шейдера. Причем в имени можно указать путь в
выпадающем окне выбора шейдера в материале. Далее идет блок свойств.
Начинается он с ключевого слова Properties {}. Остановимся на нем
поподробнее.
Properties
В этом блоке мы описываем переменные, которые будут видны в инспекторе.
Задавать их нужно в таком формате:
**__Имя переменной("Имя в инспекторе", тип переменной) = значение
переменной __**
В этом блоке мы описываем переменные, которые будут видны в инспекторе.
Задавать их нужно в таком формате:
**__Имя переменной("Имя в инспекторе", тип переменной) = значение
переменной __**
Типы переменных в блоке Properties
- Range(min,max) = number float в промежутке от min до max
- Float = number
- Int = number
- Vector = (numer,number,number,number) x,y,z,w
- Color = (numer,number,number,number) r,g,b,a
- 2D = "defaulttexture" {} 2D текстура
- Cube = "defaulttexture" {} Кубическая текстура
Пример:
_MainTexture("MainTexture", 2D) = "white" {}
_MainColor("MainColor",Color) = (1,1,1,1)
_Atten("Atten",Range(0,1)) = 0.5
Как это выглядит в инспекторе
SubShader
Каждый шейдер в Unity создержит список subshader’ов(должен быть как
минимум один). Когда Unity должен отобразить меш, он ищет шейдер для использования и выбирает
первый subshader, который способен работать на видеокарте пользователя.
минимум один). Когда Unity должен отобразить меш, он ищет шейдер для использования и выбирает
первый subshader, который способен работать на видеокарте пользователя.
Subshader определяет список проходов рендеринга (Pass'ов) и
опционально устанавливает любое,общее для всех проходов, состояние. Кроме того,
могут быть установлены специфичные для subshader тэги.
(c) Документация юнити.
Т.е. SubShader состоит из определенного числа проходов, в которых
выполняются определенные инструкции ( CG код). А теперь немного про тэги.
Тэги нужны для того, что бы назначить, как и когда будет
рендерится шейдер.
опционально устанавливает любое,общее для всех проходов, состояние. Кроме того,
могут быть установлены специфичные для subshader тэги.
(c) Документация юнити.
Т.е. SubShader состоит из определенного числа проходов, в которых
выполняются определенные инструкции ( CG код). А теперь немного про тэги.
Тэги нужны для того, что бы назначить, как и когда будет
рендерится шейдер.
Пример:
SubShader
{
Tags{"Queue" = "Transparent"}
Pass
{
CGPROGRAM
ENDCG
}
}
Тэги
Тэги пишутся внутри блока Tags{} по шаблону:
Tags { "Имя тэга1" = "значение1" "Имя тэга" = "значение2" }
Отсюда видно, что тэги идут парами ["Тэг" = "значение"] (с кавычками)
Тэги пишутся внутри блока Tags{} по шаблону:
Tags { "Имя тэга1" = "значение1" "Имя тэга" = "значение2" }
Отсюда видно, что тэги идут парами ["Тэг" = "значение"] (с кавычками)
Разберем самый используемый тэг, служащий для назначения очереди
отрисовки:
отрисовки:
Имя тэга здесь будет Queue что в переводе означает очередь.
Значения тега Queue:
Значения тега Queue:
- Background - объект рендерится в первую очередь. Используется
- Geometry - стандартная очередь рендера, используется для
- AlphaTes - используется для Альфа-теста геометрии. Во время
отрисовывать Альфа-тест геометрию после того как все остальные объекты
отрисованы в Geometry.
- Transparent - отрисовка выполняется после Geometry и AlphaTest,
объектов как стекло, частицы и т.д.
- Overlay - объект рендерится в последнюю очередь. Используется для
[ Документация ]
Путь рендера (Pass)
Вертексные и пиксельные шейдеры пишутся внутри блока Pass {}
Подробнее про написание шейдеров мы поговорим с следующей статье, а
сейчас лишь обратим внимание на тэги и установки для рендера. Что, тэги
уже были в SubShader ?
Так вот, в Pass так-же есть свои тэги.Тэги в Pass пишутся так-же в блоке
Tags{}, и даже по тому-же шаблону. Просто имена тэгов и значения разные,
ну и, соответственно, они обозначают другие свойства.Для того, что бы
понять, что они делают, нужно прочитать [ это] . А после идти на
страницу Pass-тэгов и читать [ это].
Подробнее про написание шейдеров мы поговорим с следующей статье, а
сейчас лишь обратим внимание на тэги и установки для рендера. Что, тэги
уже были в SubShader ?
Так вот, в Pass так-же есть свои тэги.Тэги в Pass пишутся так-же в блоке
Tags{}, и даже по тому-же шаблону. Просто имена тэгов и значения разные,
ну и, соответственно, они обозначают другие свойства.Для того, что бы
понять, что они делают, нужно прочитать [ это] . А после идти на
страницу Pass-тэгов и читать [ это].
Установки для рендера
Для того что-бы задать определенные установки для ренера в пределах
одного Pass'а,такие как: смешивание, отсечение пикселей, настройки Z
буффера, смещение и т.д., используют специальные команды. Пишутся они в
формате: Имя Значение. Например
Для того что-бы задать определенные установки для ренера в пределах
одного Pass'а,такие как: смешивание, отсечение пикселей, настройки Z
буффера, смещение и т.д., используют специальные команды. Пишутся они в
формате: Имя Значение. Например
Cull Off
Zwrite On
Основные установки и значения:
- Cull - Задаёт те стороны полигонов, которые должны быть отсечены
- Cull Back - отсекает полигоны, которые направлены от камеры
- Cull Front - отсекает полигоны, которые направлены на камеру
- ZWrite - Записываются ли пиксели объекта в буфер глубины (по
- On - Записывает
- Off - Не записывает
- ZTest- Как проверка глубины должна быть исполнена. По умолчанию
- Less - Отрисовывает ближайшие пиксели ( с меньшей глубиной)
- LEqual (Less or Equal) - Отрисовывает ближайшие пиксели,
- Greater - Отрисовывает пиксели с большей глубиной
- GEqual ( Greater + Equal)
- Always - Отрисовывает пиксели не зависимо от глубины.
- Blend - смешивание. Тема интересная и важная,но и большая по объему. Вот ссылки на материал, в котором очень хорошо описано смешивание в юнити:
- Статья на хабре очень хорошо объясняет как это работает.
- Документация. Unity
- AlphaTest - выполняется перед смешиванием. С помощью этой
документации) отекать пиксели с помощью операторов
(Greater,GEqual,Less,LEqual,Equal,NotEqual,Always,Never) и значения
переменной AlphaValue.
Пример:
Pass
{
...
AlphaTest Less 0.7 // рендерим только те пиксели, значение альфа у
которых меньше 0.7
...
}
Shader "MyShaders/AlphaTest"
{
Properties
{
_Alpha("AlphaValue",Range(0,1)) = 0.6
}
SubShader
{
Pass
{
AlphaTest Greater _Alpha // рендерим только те пиксели, значение
альфа у которых больше _Alpha
CGPROGRAM
...
ENDCG
}
}
}
Ну что ж, про основные установки я написал.Если интересно,то про
остальные можете почитать документации
остальные можете почитать документации
Uniform переменные
Про uniform переменные много говорить не стану. Просто нужно знать,
что это внешние переменные, которые располагаются в CG коде и должны быть названы
точно так же,как в блоке Properties{}, что бы ShaderLab смог автоматически передать
значения в эти переменные.
Про uniform переменные много говорить не стану. Просто нужно знать,
что это внешние переменные, которые располагаются в CG коде и должны быть названы
точно так же,как в блоке Properties{}, что бы ShaderLab смог автоматически передать
значения в эти переменные.
Shader "MyShaders/AnotherShader"
{
Properties
{
_SomeVar('SomeVariable",Range(0,1)) = 0.5
_Tex("Texture",2D) = white{}
}
SubShader
{
Pass
{
CGPROGRAM
...
uniform float _SomeVar;
uniform sampler2D _Tex;
...
ENDCG
}
}
}
Fallback
После всех SubShader'ов можно назначить Fallback. Роль Fallback'а
заключается в том, что если не один из SubShader'ов не сможет
запуститься на данном устройстве, то запустится шейдер, который указан в
Fallback'е.
В данном примере, если не SubShader по каким-то причинам не запустится,
то для объекта выполнится шейдер "Diffuse"
заключается в том, что если не один из SubShader'ов не сможет
запуститься на данном устройстве, то запустится шейдер, который указан в
Fallback'е.
В данном примере, если не SubShader по каким-то причинам не запустится,
то для объекта выполнится шейдер "Diffuse"
Shader "AlphaTest"
{
SubShader
{
Pass
{
CGPROGRAM
...
uniform float _SomeVar;
uniform sampler2D _Tex;
...
ENDCG
}
}
Fallback "Diffuse"
}