Shader "Tutorial/Simple3DShader"{ Properties {_MainTex ("Texture",2D) ="white" {} } SubShader { // Заметьте отсуствие строк, которые ускоряли работу // шейдеров для картинок, в шейдере, накладываемом // на 3д объект они бы привели к артефактам Pass { CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc" // Ранее мы пользовались заранее подготовленными // структурами для шейдеров, теперь мы объявили // свои собственные struct appdata { // Позиция вершины в мировых координатах float4 vertex : POSITION; // Координаты развёртки, соответствующие вершине float2 uv : TEXCOORD0; }; struct v2f { // Координаты развёртки float2 uv : TEXCOORD0; // Экранные координаты вершины float4 vertex : POSITION; }; // То, что appdata и v2f так похожи, это скорее // случайность, чаще эти структуры заметно отличаются // Кроме структур, мы использовали и готовый // вертексный шейдер, который был создан командой Unityv2fvert (appdata v) {v2f o; // Чтобы получить экранные координаты вершины, // умножаем матрицу вида камеры на мировые // координаты вершиныo.vertex=mul(UNITY_MATRIX_MVP,v.vertex); // Координаты развёртки передаём дальше без измененийo.uv=v.uv;return o; }sampler2D _MainTex;fixed4frag (v2f i) : COLOR {fixed4 col =tex2D(_MainTex,i.uv); col =1- col;return col; } ENDCG } }}
Чуть более сложный пример шейдера:
Shader "Tutorial/LittleMoreComplex3D"{ Properties {_MainTex ("Texture",2D) ="white" {} } SubShader { Pass { CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; float4 normal : NORMAL0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : POSITION; };v2fvert (appdata v) {v2f o; // Всё отличие от простейшего 3D шейдера // это изменение положение вершин объекта // в направлении нормали.v.vertex=v.vertex+v.normal;o.vertex=mul(UNITY_MATRIX_MVP,v.vertex);o.uv=v.uv;return o; }sampler2D _MainTex;fixed4frag (v2f i) : COLOR {fixed4 col =tex2D(_MainTex,i.uv); col =1- col;return col; } ENDCG } }}
Реакция на клик мышью
При помощи простых математических операций можно сделать довольно красивые эффекты, следующий шейдер будет отзываться на клик мышью.
Принцип работы этого шейдера в том, что он каждую вершину, которая находится на определённом расстоянии от точки клика, сдвигает в направлении нормали. Расстояние определяется извне шейдера, устанавливается в C# путём SetFloat.
distance(_ClickPos,mul(_Object2World,v.vertex));
эта функция находит расстояние между точками в пространстве, но важно чтобы обе точки были в одной системе координат, а нам даны координаты вертекса в локальном пространстве модели. Чтобы это исправить мы умножаем матрицу _Object2World на локальные координаты и получаем мировые координаты. Сама матрица _Object2World создана unity без нашего участия, нам остаётся только пользоваться.
mul(_Object2World,v.vertex)
Следующие строки:
float a =step(dist-0.8, _WaveSpread);float b =step(_WaveSpread, dist+0.8);
созданы чтобы определить ширину волны на поверхности, магическое число 0.8 умноженное на 2 и есть ширина волны.
min(a,b)
a и b, при таком подходе, одновременно будут равны 1 только тогда, когда расстояние от точки клика до вершины больше чем dist-0.8, но меньше чем dist+0.8. Чем мы и пользуемся чтобы интерполировать(а на самом деле выбрать) между v.vertex и v.vertex + v.normal, где v.vertex это обычные координаты вершины, а v.vertex + v.normal это сдвинутые в сторону нормали. Более красивого перехода можно было бы добиться при использовании не step, результатом которой может быть только 1 или 0, а smoothstep, который даёт не только 0 или 1, но и промежуточные значения.
float a =smoothstep(dist -1.5,dist -0.8, _WaveSpread);float b =smoothstep(_WaveSpread -1.5,_WaveSpread -0.8, dist);
Здесь мы после клика получаем текстуры от материала, меняем их местами и запускаем работу шейдера с нуля. Постоянно отображается вторая текстура, а первая текстура отображается только в момент пробегания волны, она как бы закрашивается сверху второй.
На этом хотелось бы закончить ознакомление с миром шейдеров. После прочтения этого урока должно появиться понимание принципов его работы, и, при использовании документации, на которую даны ссылки, можно разработать множество интересных эффектов. Следующим этапом может стать либо ознакомление с surface шейдерами, либо с моделями освещения.