[Перевод] Зрение Хищника: эффект термального видения

kknxyeldzhw3q3qy0mvl05dfate.gif


В процессе поисков наилучшей реализации термального шейдера я наткнулся на matcap-шейдер, опубликованный пользователем bgolus в форумах Unity — неплохая отправная точка.

Я сильно изменил его, чтобы модели выглядели более целостными под разными углами, привязав cap к вершинам и нормалям. То есть по сути это уже не matcap, но мне всё равно хотелось бы отдать должное этому шейдеру, с которого всё началось.

5b48ed20418ea63213d703571ea15c20.png


Будем двигаться по порядку, сначала вершинная функция:
1. Нормали объекта:

float3 v.normal;


2. Нормализованная позиция вершины, начинается с опорной точки модели

float3 vertexN = normalize(v.vertex);


3. Векторное произведение этих значений:

float3 viewCross = cross(vertexN, v.normal);


4. Уменьшаем crossproduct.xy вдвое и смещаем, чтобы создать более ровный результат

o.cap = viewCross.xy * 0.5 + 0.5;


Во фрагментной функции

5. Создадим маску и умножим

fixed4 m = tex2D(_Mask, i.uv);
i.cap *= (1 - m.g);


6. Спроецируем цветовую текстуру на результат. (Я использую оранжево-фиолетовый стиль, но вы можете использовать градиент побольше или что-то другое)

ac95ac77750ba6161c9bf3e0a969a0ef.png
fixed4 color = tex2D(_Matcap, i.cap);


Вот и всё, термальный шейдер готов; важный момент — нужно дать ему собственную метку, чтобы скрипт замены задавал его правильно, так что убедитесь, что метки содержат это:

 Tags{  "ThermalVision" = "ThermalColors"}


Вот полный шейдер: ссылка на Pastebin

Замена шейдера


Чтобы термальный шейдер мог заменить другой, вам просто нужно применить ту же метку к шейдеру, который нужно заменить:

Tags{  "ThermalVision" = "ThermalColors"}


И убедитесь, что все нужные свойства открыты для заменяемого шейдера:

_Mask("G = no thermal", 2D) = "black" {}
_Matcap("Matcap", 2D) = "white" {}
_Strength("Mask Strength", Range(0,2)) = 0.4


Чтобы переключить шейдер, вам нужно добавить вторую камеру и вызывать для неё

camera.SetReplacementShader(Shader, "NamedShader");

.

e24e44e2a6191926aea8472be733501a.png


Итак создайте новую камеру, и сделайте дочерней по отношению к основной камере, а затем обнулите позицию и поворот, чтобы они были расположены одинаково.

164aa8db6b6b7514675baaf0bbbbb7e3.png


Установите ей Solid Color и чёрный фон.

fd47d39f6f23b9d67ceb8f1cd76963f3.png


В «Camera Preview» вы должны видеть всё тоже самое, что и в обычной камере, только без скайбокса, с чёрным фоном.

Настала пора менять шейдеры,

Добавьте публичную переменную Shader и перетащите на неё шейдер термального эффекта.

Затем добавьте камеру как новую переменную и в Start вызовите SetReplacementShader, использовав публичный шейдер и имя, заданное в метках

  public Shader ThermalShader;
  Camera cam;
   void Start()
{
 cam = GetComponent();
 cam.SetReplacementShader(ThermalShader, "ThermalVision");
  }


aa5271622ca661a77e5fbe0f59261b56.png


После запуска вы должны увидеть термальный эффект только на мешах с заменённым шейдером.

Image Effect


cc275e9de7e313792aba17b10f03fbfd.png


На этом этапе термальный шейдер чётко виден, но кроме него не видно ничего. Чтобы вернуть окружение в камеру, я использую текстуру DepthNormals в качестве Image Effect в сочетании с текстурой Opaque.

Шейдер с Image Effect: ссылка на Pastebin

Добавьте этот простой Blit-скрипт к термальной камере и перетащите шейдер с Image Effect

Я поместил то же изображение, что и в термальный шейдер, но вы можете использовать и другое!

Скрипт переключения термального видения


f896bd0459717931cc1ded345cb2fe85.gif


Теперь достаточно просто переключать его во время игры.

a7146d368bbedf6c7943cb6c2d1ada67.png


fae0793562ebd8ce8ee80560d3f0c116.png


Для переключения булевой переменной, включающей камеру, выполняющей замену и объём постобработки, я использую клавишу T. Для обратного переключения нужно снова нажать T.

Чтобы закончить, добавим термальной камере немного постобработки. Я добавил Chromatic Abberation и Depth of Field.

Вот скрипт переключения термального видения: ссылка на Pastebin Link

(При использовании PPS 2 может потребоваться обновление до более новой версии Post Processing stack)

Дополнительно


Если вы не хотите, чтобы эффект просвечивал сквозь стены, то для камеры замены установите вместо «Solid Color» значение «Don’t Clear». Если вы хотите, чтобы скайбокс тоже становился чёрным, то в коде переключения кешируйте материал скайбокса и установите его в null

Private Material SkyboxMaterial;
skyboxMaterial = RenderSettings.skybox;
RenderSettings.skybox = null;


а затем возвращайте его при отключении термального эффекта:

RenderSettings.skybox = skyboxMaterial;


2280d848165405724453a22cb62b5b66.png


c4820e06f97ef8eb3d3a36e050f8cfb4.gif


Теперь это меньше похоже на геймплейную механику и больше на простой визуальный эффект.

Быстрый старт, если вам не интересны объяснения


1. Скачайте шейдер термального эффекта

2. Скачайте заменённый Toon-шейдер ИЛИ добавьте в собственный шейдер "ThermalVision" = "ThermalColors" и переменные _Matcap, _Mask, _Strength.

3. Создайте вторую камеру, дочернюю для основной, установите ей Solid Color, Black Background

4. Возьмите термальный шейдер с Image Effect, создайте материал и добавьте к этой второй камере скрипт ThermalBlit, перетащив этот материал.

5. Добавьте скрипт ThermalController, перетащите шейдер термального эффекта, добавьте объём постобработки (необязательно)

6. Нажмите T, чтобы включить видение. (У того, что должно отображаться, должен быть заменённый шейдер).

Ресурсы


Код шейдера термального эффекта: ссылка на Pastebin

Код шейдера, заменяющий Toon-шейдер: ссылка на Pastebin

Код шейдера с Image Effect: ссылка на Pastebin

Blit-скрипт на C#: ссылка на Pastebin

Скрипт переключателя термального видения на C#: ссылка на Pastebin

Matcap-изображения:

40668c35e78dd6c2c127cfd8c48aec58.png

8ad1bc89a1e570aa97af42d538301bbd.png

Дополнительная информация о заменяемых шейдерах:

Это старое видео, из которого я впервые о них узнал: Video on Replacement Shaders by Making stuff look good in Unity

dbbd618202d2707a65f6621b62640f8c.gif

© Habrahabr.ru