Шейдер спрайтов.

Введение.

В Unity способ визуализации спрайтов очень похож на способ отображения 3d-объектов. Большая часть работы выполняется компонентом рендеринга спрайта. Я немного поразмыслил над тем, что делает этот компонент, и как мы можем изменить наш шейдер, чтобы сделать некоторые вещи, которые делает рендеринг спрайтов по умолчанию.
Этот урок будет основываться на прозрачном шейдере, который мы сделали ранее, поэтому лучше всего сначала изучить его.

Установка сцены.

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

Изменяем шейдер.

Со всеми этими изменениями и прозрачным материалом, помещенным в слот материала средства визуализации спрайтов, все уже работает.

Компонент рендеринга спрайтов автоматически генерирует сетку на основе нашего изображения и задает UV-координаты, чтобы он работал так же, как и 3D-модели, к которым мы привыкли. Он помещает цвет визуализатора спрайтов в вершинные цвета сгенерированной сетки, и он сортирует вершины в перевернутой форме, когда мы активируем flip X или Y. Он также связывается с конвейером рендеринга Unity, поэтому спрайты, которые имеют более высокий уровень сортировки, рендерятся позже и будут нарисованы сверху.
Наш шейдер в настоящее время не поддерживает зеркалирование и вершинные цвета, поэтому давайте исправим это.
Причина, по которой наш спрайт исчезает, когда мы переворачиваем его (и снова появляется, когда мы переворачиваем его по x и y), заключается в том, что для отражения спрайта по оси x рендеринг поворачивает его на 180 ° вокруг оси y, и теперь мы видим его заднюю часть. А из-за оптимизации, называемой «отбрасывание обратной поверхности (backface culling)», обратные стороны граней не отображаются. Обычно отбраковка обратной сторона хороша, потому что, мы не видим внутреность объекта, так зачем его визуализировать? И задние стороны граней обычно имеют неправильное освещение в любом случае, потому что их нормали смотрят в сторону от камеры.
В этом случае нам не нужно беспокоиться ни о какой из этих вещей, т.к. спрайты не имеют «внутренностей», которые могут быть оптимизированы, и мы также не делаем освещения, поэтому мы можем просто отключить отбрасывание обратной поверхности. Мы можем сделать это в субшадере или шейдерном проходе.

Cull Off

Чтобы получить цвета вершин, мы добавляем новую переменную 4d (красный, зеленый, синий, альфа) в нашу входную структуру и отмечаем ее как цвет. Затем мы переносим цвет из входа в структуру v2f в вершинном шейдере, а в фрагментном шейдере умножаем возвращаемый цвет на полученный цвет вершины из вершинного шейдера.
struct appdata{
    float4 vertex : POSITION;
    float2 uv : TEXCOORD0;
    fixed4 color : COLOR;
};

struct v2f{
    float4 position : SV_POSITION;
    float2 uv : TEXCOORD0;
    fixed4 color : COLOR;
};

v2f vert(appdata v){
    v2f o;
    o.position = UnityObjectToClipPos(v.vertex);
    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    o.color = v.color;
    return o;
}

fixed4 frag(v2f i) : SV_TARGET{
    fixed4 col = tex2D(_MainTex, i.uv);
    col *= _Color;
    col *= i.color;
    return col;
}
 
С этими изменениями шейдер теперь будет действовать так, как мы ожидаем, и мы сможем расширить его, чтобы делать другие вещи, с которыми мы будем заниматься в будущем.
Shader "Tutorial/007_Sprite"{
 Properties{
  _Color ("Tint", Color) = (0, 0, 0, 1)
  _MainTex ("Texture", 2D) = "white" {}
 }

 SubShader{
  Tags{ 
   "RenderType"="Transparent" 
   "Queue"="Transparent"
  }

  Blend SrcAlpha OneMinusSrcAlpha

  ZWrite off
  Cull off

  Pass{

   CGPROGRAM

   #include "UnityCG.cginc"

   #pragma vertex vert
   #pragma fragment frag

   sampler2D _MainTex;
   float4 _MainTex_ST;

   fixed4 _Color;

   struct appdata{
    float4 vertex : POSITION;
    float2 uv : TEXCOORD0;
    fixed4 color : COLOR;
   };

   struct v2f{
    float4 position : SV_POSITION;
    float2 uv : TEXCOORD0;
    fixed4 color : COLOR;
   };

   v2f vert(appdata v){
    v2f o;
    o.position = UnityObjectToClipPos(v.vertex);
    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    o.color = v.color;
    return o;
   }

   fixed4 frag(v2f i) : SV_TARGET{
    fixed4 col = tex2D(_MainTex, i.uv);
    col *= _Color;
    col *= i.color;
    return col;
   }

   ENDCG
  }
 }
}
 
Компонент рендеринга спрайтов также подготавливает сетку, так что спрайты, полигонные спрайты и анимации работают с нашим шейдером.
То, что поддерживает sprite shader от Unity, а наш до сих пор нет - инстнсинг, пиксельная привязка и внешний альфа-канал. Но это слишком сложно сейчас, и большинство людей не используют, поэтому я решил не реализовывать их.


Вы также можете найти исходный код здесь: https://github.com/ronja-tutorials/ShaderTutorials/blob/master/Assets/007_Sprites/sprite.shader.

Переводчик Беляев В.А. ака seaman

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

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