Текстуры.

Введение.

Одним из наиболее важных способов получения информации в наших шейдерах являются текстуры. Текстуры читаются через «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

Комментариев нет:

Отправить комментарий