Простой цвет.


Введение.

Здесь я собираюсь объяснить, что вам нужно сделать, чтобы создать шейдер в Unity. Вы получите объект с одним цветом, но мы можем расширить его позже. Если вы обнаружите, что у вас проблемы с пониманием всего, я рекомендую вам сначала прочитать руководство по основам языка hlsl.

Фреймворк Shaderlab

При написании шейдеров в Unity мы не можем начать с написания кода, сначала нужно сказать Unity, как он должен использовать наш шейдер. Вот почему мы начинаем с определения раздела «Шейдер» с именем шейдера и внутри этого раздела «SubShader». Мы можем определить несколько подшейдеров в каждом шейдере и рассказать Unity, когда использовать какой, но большую часть времени мы хотим использовать один и тот же субшадер везде, поэтому мы пока пишем только один.
 
Shader "Tutorial/02_Simple"{
 Subshader{
 }
}
В этом субшадере мы напишем наш шейдерный проход. Когда подшейдер отображается, все проходы выводятся последовательно, но пока нам нужен только один проход. В этом проходе мы добавляем несколько тегов, чтобы рассказать Unity, как мы хотим, чтобы он обрабатывал этот проход. Для этого шейдера мы хотим, чтобы объект, который мы визуализируем, был полностью непрозрачным, и мы хотим, чтобы он визуализировался вместе с другими непрозрачными объектами.
 
Shader "Tutorial/02_Simple"{
 Subshader{
  Pass{
   Tags{
    "RenderType" = "Opaque"
    "Queue" = "Geometry"
   }
  }
 }
}

HLSL Код

После того, как мы все это сделали, мы можем начать запись hlsl-части шейдера. Важно понимать, как информация поступает в шейдер. Сначала информация из 3d модели предоставляется вершинному шейдеру, который изменяет информацию о положении и параметрах вершин, а затем результат проходит через растеризатор, который преобразует вершины и треугольники в пиксели, которые можно рисовать на экране. Но в этот момент шейдер еще не знает, какой цвет имеет каждый пиксель, поэтому для каждого пикселя объекта вызывается фрагментный шейдер. Он получает вывод вершинного шейдера с интерполированными значениями между вершинами. Затем фрагментный шейдер возвращает цвет, который будет нарисован на экране.
Чтобы сообщить Unity, что мы пишем здесь код hlsl, мы начинаем эту часть с CGPROGRAM и заканчиваем ее с помощью ENDCG. Чтобы использовать полезные функции, предоставляемые нам Unity, мы включаем файл UnityCG.cginc.
 
Shader "Tutorial/02_Simple"{
 Subshader{
  Pass{
   Tags{
    "RenderType" = "Opaque"
    "Queue" = "Geometry"
   }

   CGPROGRAM
   #include "unityCG.cginc"

   ENDCG
  }
 }
}
}
Начнем с добавления структуры для входных данных. Его обычно называют «appdata», и пока мы получим только вершинные позиции объекта. Чтобы сделать это, мы должны пометить переменную, которая будет заполнена позицией пространства объектов с помощью атрибута position.
 
   struct appdata {
    float4 vertex : POSITION;
   }
Затем мы записываем структуру, которая будет возвращена вершинным шейдером. Пока нам нужно только положение вершин относительно экрана. Чтобы Unity знало, что это данные в переменной, мы отмечаем его атрибутом sv_position.
 
   struct v2f {
    float4 vertex : SV_POSITION;
   }
Далее пишем вершинный шейдер, он возвращает вершину в структуре v2f фрагментному шейдеру и принимает информацию об объекте в appdata. Сначала мы инициализируем новый экземпляр структуры, затем заполняем его положением экрана в вершине и возвращаем его для обработки растеризатором. Функция UnityObjectToClipPos находится внутри файла UnityCG.cginc и позволяет нам не беспокоиться о матричном умножении на данный момент.
 
   v2f vert(appdata v) {
    v2f o;
    o.vertex = UnityObjectToClipPos(v.vertex);
    return o;
   }
И, наконец, мы пишем фрагментарный шейдер. Пока мы просто вернем красный цвет, изменим это на что-то более интересное в следующих уроках. Мы должны отметить функцию как sv_target, поэтому Unity знает, что результат этой функции будет отображаться на экране.
 
   fixed4 frag(v2f i) : SV_TARGET{
    return fixed4(0.5, 0, 0, 1);
   }

После написания наших типов данных и функций мы должны сказать Unity, какая функция используется для чего, это делается с помощью #pragma shaderFunction, поэтому мы пишем #pragma vertex vert, чтобы показать Unity наш вершинный шейдер и #pragma frag, чтобы показать Unity наш фрагментный шейдер.
 
Shader "Tutorial/01_Basic"{
 SubShader{
  Tags{
    "RenderType" = "Opaque"
    "Queue" = "Geometry"
  }
  Pass{


   CGPROGRAM
   #include "UnityCG.cginc"

   #pragma vertex vert
   #pragma fragment frag

   struct appdata {
    float4 vertex : POSITION;
   };

   struct v2f {
    float4 vertex : SV_POSITION;
   };

   v2f vert(appdata v) {
    v2f o;
    o.vertex = UnityObjectToClipPos(v.vertex);
    return o;
   }

   fixed4 frag(v2f i) : SV_TARGET{
    return fixed4(0.5, 0, 0, 1);
   }

   ENDCG
  }
 }
}


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

Здесь вы можете найти исходный код шейдера: https://github.com/ronja-tutorials/ShaderTutorials/blob/master/Assets/002_basic/basic_color.shader
Переводчик Беляев В.А. ака seaman

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

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