Глава вторая

2D(или полноэкранные) шейдеры

Добавление текстуры в шейдер

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);

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

				return col;
			}
			ENDCG
		}
	}
}

col = 1 - col;

В записанной выше строке есть скрытая работа, как уже было сказано ранее, fixed4 это структура состоящая из 4х элементов типа fixed, более того мы можем обратиться к каждому элементу по отдельности, вот так: col.r, или col.g, или col.b, или col.a, более того, можно обращаться к паре или тройке элементов: col.rgb или col.ba.

У цветового rgba есть синоним из мира геометрии xyzw, они абсолютно эквивалентны и, даже если вы работаете с цветами, к ним можно обращаться через xyzw, но чтобы не создавать двусмысленности xyzw лучше использовать с координатами. Вернёмся к вопросу о скрытой работе.

col = 1 - col;

На самом деле означает, что будет сделано следующее:

col.r = 1 - col.r;
col.g = 1 - col.g;
col.b = 1 - col.b;
col.a = 1 - col.a;

Смешение текстур

Следующий шейдер берёт соответствующие пиксели двух картинок и интерполирует цвет этих пикселей между собой формируя таким образом результирующую картинку.

Shader "Tutorial/ImageMerger"
{
	Properties
	{
		// В этом шейдере нам понадобится две текстуры и одна
		// переменная для указания степени смешивания
		_FirstTex("First Texture", 2D) = "white" {}
		_SecondTex("Second Texture", 2D) = "white" {}
		_LerpFactor("Lerp Factor", Range(0, 1)) = 0.5
		// Это свойство можно было объявить иначе
		// _LerpFactor("Lerp Factor", Float) = 0.5
		// но слайдер удобнее для пользователя, чем поле ввода
	}
	SubShader
	{
		Cull Off
		ZWrite Off
		ZTest Always

		Pass
		{
			CGPROGRAM
			#pragma vertex vert_img 
			#pragma fragment frag 

			#include "UnityCG.cginc"

			sampler2D _FirstTex;
			sampler2D _SecondTex;
			float _LerpFactor;

			fixed4 frag(v2f_img i) : COLOR
			{
				fixed4 firstColor = tex2D(_FirstTex, i.uv);
				fixed4 secondColor = tex2D(_SecondTex, i.uv);

				firstColor = lerp(firstColor, secondColor, _LerpFactor);

				return firstColor;
			}
			ENDCG
		}
	}
}

lerp - это готовая функция, которая принимает две переменные, которые надо между собой интерполировать и одну переменную, которая укажет степень их интерполяции. Чтобы понять работу этой функции, представьте себе две точки на бумаге и проведите отрезок от первой точки ко второй, а _LerpFactor скажет где на этом отрезке поставить третью точку, которая и будет результатом функции, если _LerpFactor = 0, то результат будет совпадать с первой точкой _LerpFactor = 1, результат совпадёт со второй, а _LerpFactor = 0.5 укажет точно на середину отрезка.

Наложение одной текстуры поверх другой

Ещё один шейдер исключительно для примера того, что можно сделать. Он берёт одну картинку, а поверх неё накладывает другую так, чтобы были едва видны очертания накладываемой картинки. По схожему принципу работает фильтр Overlay в фотошопе.

Shader "Tutorial/NoiseOverlay"
{
	Properties
	{
		_MainTex("Main Texture", 2D) = "white" {}
		_NoiseTex("Noise Texture", 2D) = "white" {}
		_NoiseStrength("Noise Strength", 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 _NoiseStrength;

			fixed4 frag(v2f_img i) : COLOR
			{ 
				half4 base = tex2D(_MainTex, i.uv);
				half4 overlay = tex2D(_NoiseTex, i.uv);

				float4 effect = lerp(1 - 2 * (1 - base) * (1 - overlay), (2 * base) * overlay, step(base, 0.5f));
				// step(a, x) = 0 если x < a 
				// step(a, x) = 1 если x >= a 

				return lerp(base, effect, (overlay.w * _NoiseStrength));
			}
			ENDCG
		}
	}
}

Last updated