Введение.
Одним из наиболее важных способов получения информации в наших шейдерах являются текстуры. Текстуры читаются через «samplers», они позволяют нам быстро читать текстуры и делать такие вещи, как фильтрация и mipmapping, без необходимости беспокоиться об этом.
Чтобы начать реализацию текстур в вашем шейдере, полезно, чтобы вы знали, как использовать свойства в шейдерах, вы можете найти урок для этого здесь.
Декларация Sampler
Мы добавляем текстуру к нашему шейдеру, объявляя sampler2D в нашей глобальной области (в hlsl-части шейдера вне функций или структур). Затем мы добавляем его к свойствам и устанавливаем тип в 2D, а значение по умолчанию - «white» {} (белый), таким образом, сэмплер будет возвращать белый для всех координат, если у него нет текстуры. Это пока ничего не изменит в рендеринге нашего шейдера.
Shader "Tutorial/03_Properties"{
Properties{
_Color("Color", Color) = (0, 0, 0, 1)
_MainTex("Texture", 2D) = "white" {}
}
...
// текстура
sampler2D _MainTex;
//оттенок текстуры
fixed4 _Color;
Текстурные координаты.
Затем мы добавим UV-координаты в нашу структуру ввода. Координаты UV - это координаты, которые определяют, какая часть текстуры показана на какой части сетки. Они уже находятся в сетке, поэтому нам не нужно создавать их в шейдере, мы можем просто использовать их. Чтобы получить UV-координаты, мы добавляем двухмерный вектор с плавающей точкой и присваиваем ему атрибут textcoord0, чтобы он заполнялся координатами. В вершинном шейдере мы копируем uv из входной структуры в координату uv в структуре, передаваемой фрагментному шейдеру, после чего в фрагментном шейдере мы можем использовать эти координаты. Пока мы будем использовать координаты как красные и зеленые значения для нашего цвета.
CGPROGRAM
//Включаем полезные функции шейдера
#include "UnityCG.cginc"
//определяем вешинный и фрагментный шейдер
#pragma vertex vert
#pragma fragment frag
// текстура
sampler2D _MainTex;
// оттенок текстуры
fixed4 _Color;
//Данные, которые передаются в вершинный шейдер
struct appdata {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
//Данные передаваемые в фрагментный шейдер из вершинного
struct v2f {
float4 position : SV_POSITION;
float2 uv : TEXCOORD0;
};
// вершинный шейдер
v2f vert(appdata v) {
v2f o;
//Конвертируем позицию вершины из пространства объекта в пространство экрана,
// чтобы они могли быть отрендерены
o.position = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
// фрагментный шейдер
fixed4 frag(v2f i) : SV_TARGET{
return fixed4(i.uv.x, i.uv.y, 0, 1);
}
ENDCG
Здесь хорошо видно, что координаты uv начинаются с {0,0} (черный) в левом нижнем углу и идут в {1,1} желтый в верхнем правом углу. Следующий шаг - использовать эти значения для чтения из текстуры. Для этого мы используем функцию tex2D, которая берет пробоотборник как первый параметр и координаты uv как второй параметр. С этим дополнением мы можем добавить текстуру к нашей модели в инспекторе и должны уметь ее видеть. Используйте любое изображение, которое вы хотите для этого.
// фрагментный шейдер
fixed4 frag(v2f i) : SV_TARGET{
fixed4 col = tex2D(_MainTex, i.uv);
return col;
}
Тайлинг.
Чтобы улучшить ситуацию, добавим тайлинг текстуры и оттенок. Рядом с текстурой вы можете увидеть параметр «tiling» и «offset» (смещение). Их изменение ничего не делает прямо сейчас, но при правильном использовании они могут масштабировать и перемещать текстуру на сетке. Чтобы активировать это, мы добавляем новый 4-мерный float в нашу глобальную область и называем его TextureName_ST, TextureName - это имя текстуры, которую вы используете. ST обозначает масштаб / трансляцию, в первых двух параметрах вектора (x & y) сохраняется тайлинг текстуры, а во вторых 2 параметрах вектора (z & w) смещение текстуры. Чтобы использовать эти значения, мы можем просто вызвать макрос TRANSFORM_TEX, который дает нам Unity. Он принимает исходные UV-координаты и название текстуры, для которой мы хотим изменить UV-координаты. Мы используем его в вершинном шейдере, где мы копируем координаты из ввода в структуру v2f. После этого мы теперь можем использовать тайлинг и смещение в редакторе, как и ожидалось.
// вершинный шейдер
v2f vert(appdata v) {
v2f o;
//Конвертируем позицию вершины из пространства объекта в пространство экрана,
// чтобы они могли быть отрендерены
o.position = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
Оттенок.
Наконец, мы добавим возможность оттенять текстуру. Мы будем использовать переменную Color из предыдущего урока для оттенка. Для этого мы переименуем его, чтобы он назывался оттенком в инспекторе, а в шейдере фрагмента мы умножаем цвет от текстуры с оттенком. С этими дополнениями мы теперь можем изменить оттенок, и он будет умножен на цвет изображения. Это означает, что белый оттенок ничего не изменит, полностью красный оттенок [1,0,0,1] будет показывать только красные части изображения и т. д. ...
Shader "Tutorial/03_Properties"{
Properties{
_Color("Tint", Color) = (0, 0, 0, 1)
_MainTex("Texture", 2D) = "white" {}
}
…
fixed4 frag(v2f i) : SV_TARGET{
fixed4 col = tex2D(_MainTex, i.uv);
col *= _Color;
return col;
}
Shader "Tutorial/03_Properties"{
Properties{
_Color("Tint", Color) = (0, 0, 0, 1)
_MainTex("Texture", 2D) = "white" {}
}
SubShader{
Tags{
"RenderType" = "Opaque"
"Queue" = "Geometry"
}
Pass{
CGPROGRAM
//Включаем полезные функции шейдера
#include "UnityCG.cginc"
//определяем вешинный и фрагментный шейдер
#pragma vertex vert
#pragma fragment frag
//масштаб/смещение текстуры
float4 _MainTex_ST;
//текстура
sampler2D _MainTex;
//оттенок текстуры
fixed4 _Color;
//Данные, которые передаются в вершинный шейдер
struct appdata {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
//данные, которые используются для генерации пикселей
//и могут прочитаны фрагментным шейдером
struct v2f {
float4 position : SV_POSITION;
float2 uv : TEXCOORD0;
};
//вершинный шейдер
v2f vert(appdata v) {
v2f o;
//конвертируем позицию вершины из пространства объекта
//в пространство экрана для визуализации
o.position = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
//фрагментный шейдер
fixed4 frag(v2f i) : SV_TARGET{
fixed4 col = tex2D(_MainTex, i.uv);
col *= _Color;
return col;
}
ENDCG
}
}
}
При этом наш шейдер имеет в основном те же функциональные возможности, что и при создании new => shader => unlit, но мы понимаем, что он делает, и мы можем улучшить его в будущем!
Здесь вы можете найти исходный код шейдера: https://github.com/ronja-tutorials/ShaderTutorials/blob/master/Assets/004_Textures/textures.shader
Перевод Беляев В.А. ака seaman
Комментариев нет:
Отправить комментарий