Графы шейдеров это новый инструмент для создания шейдеров в юнити. Он позволяет создавать шейдеры людям не имеющим навыков написания кода. Результат каждой операции виден при редактировании. Идеальный инструмент для новичков и экспериментаторов.

Добавление Shader Graph в проект делается при помощи Package Manager.



Но на сегодня доступна версия только для Lightweight Render Pipeline, поэтому для экспериментов нужно создавать проект так:



Простейший шейдер


Shader Graph позволяет создать два вида шейдеров Unlit(без освещения) и PBR(фотореалистичный рендер), а так же sub(нода для шейдера). Последнее можно использовать внутри Unlit и PBR шейдеров.



Unlit не использует встроенных возможностей в юнити по освещнию и затенению модели, только отображает текстуру поверх модели и поэтому с ним намного проще ознакомиться.

Создаём материал и создаём Unlit Graph. Перетягиванием назначаем материалу шейдер.



Открыв шейдер двойным кликом мы увидим мастер-ноду



На выходе этого шейдера мы можем контролировать:

  • Position — позицию вершины
  • Color — цвет каждого пикселя поверхности
  • Alpha — его прозрачность
  • AlphaClipThreshold — порог прозрачности, если мы не используем полупрозрачность

Подавляющее большинство шейдеров не использует полупрозрачность из-за вычислительной сложности и ограничений, которые накладываются на такие шейдеры. И там, где можно обойтись без полупрозрачности, надо обходиться без неё.

Будет ваш шейдер использовать полупрозрачность или нет, можно настроить в мастер-ноде:



  • Opaque — непрозрачный
  • Transparent — полупрозрачный

Чтобы раскрасить модель мы можем подать на вход(color) мастер-ноды трёхмерный вектор или цвет, что для шейдера по сути одно и то же, только по разному отображается в графе.
Новые ноды создаются через контекстное меню



в данном случае мы можем использовать две ноды Color или Vector4



но чтобы их можно было настраивать из инспектора нам нужно создать свойство



а потом мышкой перетянуть его в граф тем самым создав ноду.



  • Exposed — позволяет это свойство видеть в инспекторе при редактировании материала
  • Default — задаёт значение цвета по умолчанию
  • Mode — позволяет выбрать диапазон яркости(HDR позволяет выйти за рамки обычной яркости)

Чтобы созданное свойство влияло на цвет материала надо его выход соединить со входом Color у мастер-ноды.



Тот же шейдер, но кодом
Shader "Tutorial/Simpliest" // Shader - обязательное начало для любого шейдера, 
                             // после этого ключевого слова в
							 // кавычках пишется url-подобное имя шейдера
{
	Properties // блок свойств, которые будут отображаться во вкладке 
               //  inspector в Unity
	{
		_Color ("Color", Color) = (0.5,0.6,0.7,1)
		//Каждая строка связана с переменной и содержит следующие данные:
		// _Color - имя переменной, оно должно совпадать по написанию с 
        //          одной из переменных внутри CGPROGRAM
		// "Color" - текст, который будет отображаться в окне 
        //           Inspector перед значением переменной
		// Color - тип данных, от него зависит как будет выглядеть 
        //         блок выбора значения в Inspector, бывает
		//         5 типов данных: 
		//         Color - выглядит как выбор цвета, 
		//         Vector - как 4 текстовых поля ввода,
		//         Float - поле ввода одного числа с плавающей запятой, 
		//         2D - текстура, 
		//         CUBE - выбор кубической текстуры
		// (0.5,0.6,0.7,1) - значение переменной по умолчанию
	}
	SubShader // в одном шейдере может быть несколько этих блоков, 
              // но одновременно работать может только один
	{
		// No culling or depth
		// Это зарезервированные слова, в этом шейдере они указаны 
        // для упрощения работы GPU, благодаря им потребуется меньше 
        // вычислений для отображения шейдера, а ZTest Always говорит 
        // о том, что этот шейдер будет рисовать объект поверх всех остальных
		Cull Off 
		ZWrite Off 
		ZTest Always
​
		Pass // этих блоков может быть несколько внутри одного SubShader,
             // каждый Pass это отдельный проход рендера по объекту с этим 
             // шейдером, результат следующего Pass рисуется поверх предыдущего
		{
			CGPROGRAM // Зарезервированное слово, оно лишь отмечает начало 
                      //  кода самого шейдера
​
			#pragma vertex vert_img // использовать для вертексного шейдера 
                                     // vert_img, которая описана не нами
			#pragma fragment frag   // для фрагментного шейдера использовать 
                                     //функцию frag, описанную ниже
			
			#include "UnityCG.cginc" // позволяет нам использовать готовые функции, 
                                      // написанные командой Unity
			                          // в их числе и vert_img, код файла можно найти 
                                      // в файле:
		                              // %UNITY%\Editor\Data\CGIncludes\UnityCG.cginc
​
			fixed4 _Color; // fixed4 - тип переменной, именно этот тип представляет 
                           // собой структуру из 4х переменных типа fixed
​
			fixed4 frag (v2f_img i) : COLOR
			{
				fixed4 col = _Color;
				return col;
			}
			ENDCG // Зарезервированное слово, оно отмечает конец кода самого шейдера
		}
	}
}


Самый простой шейдер с текстурой


Чтобы наложить нашу текстуру на меш, нам надо создать ноду, которую можно будет настроить извне Shader Graph. Для этого создадим свойство



и вытянем его, при этом создастся нода текстуры



После этого нужно создать ноду сэмплера текстуры, которая сможет на вход получать текстуру и uv-координату, а на выход давать цвет пикселя.



Выход сэмплера соединяем со входом color мастер-ноды



Простейший шейдер с текстурой кодом
Shader "Tutorial/Texture"
{
	Properties
	{
		_MainTex("Texture", 2D) = "white" {}
		// В предыдущей части в качестве свойства был цвет, 
		// а теперь текстура, в Inspector будет предложено
		// выбрать одну. Здесь "white" это значение по умолчанию,
		// означает, что будет создана текс��ура белого цвета.
	}
	SubShader
	{
		Cull Off
		ZWrite Off
		ZTest Always

		Pass
		{
			CGPROGRAM
			#pragma vertex vert_img 
			#pragma fragment frag 

			#include "UnityCG.cginc"

			sampler2D _MainTex;
			// sampler2D - это тип переменной который надо ставить когда
			// мы хотим работать с текстурой, заметьте, что имя переменной
			// _MainTex совпадает с именем свойства в блоке Properties,
			// это обязательно для корректной работы.

			fixed4 frag(v2f_img i) : COLOR
			{
				// Следующая строка позволяет нам получить цвет пикселя в точке
				// с которой мы работаем в этой итерации, если помните, то ранее 
				// было сказано, что фрагментный шейдер работает с каждым видимым 
				// пикселем объекта. 
				// tex2D - это готовая функция для получения значения цвета,
				// первый параметр (_MainTex) это из какой текстуры мы хотим
				// получить цвет, а второй (i.uv) это UV координаты в которых 
				// мы хотим узнать цвет.
				fixed4 col = tex2D(_MainTex, i.uv);

				return col;
			}
			ENDCG
		}
	}
}


Негатив текстуры


Перед отображением текстуры на экране мы можем её изменить применив математические операции. Например создать негатив простым вычитанием.

Добавим ноду Substract уменьшаемое будет (1;1;1;1), а вычитаемое выходом текстуры.



Негатив текстуры кодом
Shader "Tutorial/Texture"
{
	Properties
	{
		_MainTex("Texture", 2D) = "white" {}
	}
	SubShader
	{
		Cull Off
		ZWrite Off
		ZTest Always

		Pass
		{
			CGPROGRAM
			#pragma vertex vert_img 
			#pragma fragment frag 

			#include "UnityCG.cginc"

			sampler2D _MainTex;

			fixed4 frag(v2f_img i) : COLOR
			{
				fixed4 col = tex2D(_MainTex, i.uv);

				col = 1 - col;
				// Инверсия цвета, цвет в шейдере представлен 4-мя компонентами
				// RedGreenBlueAlpha - КрасныйЗелёныйСинийНепрозрачность,
				// причём значение каждого компонента в диапазоне от 0 до 1

				return col;
			}
			ENDCG
		}
	}
}


Смешение двух текстур


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

А саму операцию смешивания произведёт нода Lerp.



Смешение двух текстур кодом
Shader "Tutorial/NoiseOverlay"
{
	Properties
	{
		_MainTex("Main Texture", 2D) = "white" {}
		_NoiseTex("Noise Texture", 2D) = "white" {}
		_LerpValue("Lerp Value", Range(0, 1)) = 0.5
	}
	SubShader
	{
		Cull Off
		ZWrite Off
		ZTest Always
​
		Pass
		{
			CGPROGRAM
			#pragma vertex vert_img 
			#pragma fragment frag 
​
			#include "UnityCG.cginc"
​
			sampler2D _MainTex;
			sampler2D _NoiseTex;
			float _LerpValue;
​
			fixed4 frag(v2f_img i) : COLOR
			{ 
				half4 base = tex2D(_MainTex, i.uv);
				half4 overlay = tex2D(_NoiseTex, i.uv);
​
				return lerp(base, overlay ,  _LerpValue);
			}
			ENDCG
		}
	}
}


Cutout маска


Чтобы сделать полностью прозрачной часть модели нужно подать на вход мастер-ноды значение Alpha канала, создать свойство-слайдер и подать его на вход AlphaClipThreshold



Слайдер нужен для исправления бага в Graph shader, который не позволяет сделать cutout и к тому же он позволит менять значение из настроек материала.

Инверсия UV


Для работы с UV нужно создать ноду UV и подключить её к сэмплеру текстуры



здесь же можно выбрать канал UV, у некоторых моделей этих каналов может быть несколько, на случай многослойных текстур. Этим шагом мы не изменили ровным счётом ничего, а чтобы инвертировать UV, нам нужно создать ноду которая инвертирует значения UV, нам подойдёт обычное умножение на -1 координаты по Y.



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



Впечатления


Создание шейдера при помощи Shader Graph сильно упрощает задачу хотя бы потому, что можно наблюдать за изменением результата после каждого этапа вычислений. Са�� принцип создания через редактор нод позволяет создать что-то новое даже тем, кто ничего не понимает в шейдерах. Инструмент ещё сырой, но уже очень полезный. Так как можно поэкспериментировать в редакторе, а потом воспроизвести созданное кодом, названия функций в большинстве случаев совпадает с названием нод, поэтому Shader Graph может оказаться полезным и программистам.

P.S. благодарю Darkirius за помощь в подготовке статьи

P.P.S. так же вы можете ознакомиться с уроками по написанию шейдеров в юнити по ссылке Гит-книга