Я создал этот видеошейдер VHS в Unreal в рамках первого испытания шейдеров для канала Технически говоря в Discord. Темой конкурса было «Ретро», и я экспериментировал с идеями для FMV-игры, поэтому решил объединить две темы.
Интересующиеся исходным кодом могут посмотреть файлы проекта.
Здесь .
Разархивируйте эти папки и скопируйте их в папку содержимого вашего проекта.
Не стесняйтесь задавать мне вопросы в комментариях к оригинальной статье или в Твиттер .
видео
Видео текстура
Давайте начнем с импорта видеотекстуры и создания простого материала без света, который будет ее использовать.Далее мы создадим схему, которая откроет импортированный источник мультимедиа при запуске уровня.
Инструкции по импорту, настройке и использованию видеотекстуры в уровне можно найти по адресу Страница документации Unreal , поэтому я не буду об этом здесь говорить.
Видео текстура на сфере
Это видео представляет собой видеоролик ужасов, который я записал на свой телефон, рассматривая самые жуткие вещи, которые нашел у себя дома.
Качество видео не имеет значения, ведь мы уменьшим его размер в несколько раз; плюс низкое качество делает его более старым!
Размытие
Чтобы придать видео настоящий олдскульный стиль, мы добавим немного расфокусировки, чтобы уменьшить резкость изображения.Здесь мы немного схитрим — вместо написания собственной функции воспользуемся нодом SpiralBlur-Texture. Если он не может принять внешний образец текстуры в качестве входных данных, просто возьмите внутренний узел Custom и используйте его непосредственно в своем графике.
Узел «Спиральное размытие»
Логика размытия с использованием узла Custom из Spiral Blur.
Преобразуйте данные, поступающие в этот узел, в скалярные параметры.
Я обнаружил, что значения, показанные ниже, работают хорошо.
Очень маленькое расстояние, но очень большое количество шагов расстояния дает нам значительное размытие, но сохраняет целостность изображения.
Параметры скалярного размытия в экземпляре материала
Размытие выглядит великолепно, но мы не хотим, чтобы камера все время была не в фокусе! Чтобы исправить это, мы подвергнем исходное изображение и размытое изображение линейной интерполяции (lerp), используя оператор деления с остатком для переключения между ними.
Деление с остатком (узел Fmod в Unreal) возвращает остаток деления.
Остаток от 4 от деления на 2 равен 0, а остаток от 5 от деления на 2 равен единице.
Узел Fмод
Получая остаток от деления Времени на скалярный параметр, мы создаем неравномерное колебание значений.
Это создает более естественный вид, чем волновая функция.
Округлив результат, мы создаем резкий переход, который хорошо подходит для изображения VHS.
Разница между остатком (по модулю) и синусоидой.
Теперь мы можем использовать скалярный параметр, чтобы контролировать, как часто мы хотим видеть каждую версию изображения.
Значения типа 2 часто приводят к 0, а значения типа 5, скорее всего, будут иметь остаток, поэтому результат будет 1 или более.
Вы можете наблюдать за изменениями результатов на гифке, показанной выше.
Я поместил нормальное изображение в слот A, а размытое изображение в слот B, а затем, поскольку размытое изображение появлялось чаще, чем обычное изображение, я вставил минус, чтобы поменять значения.
Я включил это главным образом ради красоты графика, поэтому вы можете пропустить этот момент или изменить порядок входных данных на графике.
Два образца плюс лерп между ними.
Материал по сфере; деление с остатком производится на 2, чтобы эффект был легче увидеть.
Темные области на гифке, показанной выше, — это места, где остаток имеет отрицательное число.
Лично я считаю, что это улучшает эффект, но если вы хотите избавиться от них, вы можете использовать для этого нод Saturate перед Lerp. (Насыщение выполняет ограничение 0–1 на инструкцию ALU, а узел Clamp на некоторых типах оборудования может быть представлен несколькими инструкциями.
)
УФ-манипуляция
Теперь, когда у нас есть красивое размытое изображение, мы можем внести изменения в UV, чтобы добавить растяжение, хроматическую аберрацию и разрешение, соответствующее периоду.
Разрешение
Разрешение VHS — 333х430, поэтому наше видео должно это передать.Я объяснил технику уменьшения разрешения в предыдущий пост , однако реализовано это было в hlsl, поэтому для Unreal повторим все еще раз.
Давайте создадим скалярный параметр или константу для разрешения X и Y, присвоив им значения 333 и 430. Давайте объединим их, создав значение float2, а затем округлим в меньшую сторону (пол).
Давайте умножим на это координаты нашей текстуры, чтобы создать сетку изображения.
После создания сетки мы округляем ее вниз, а затем делим по разрешению.
Это уменьшит тайлинг, но из-за округления в меньшую сторону оно будет ограничено сеткой, которую мы создали изначально.
? Расчет шагов по уменьшению разрешения.
Узлы уменьшения разрешения.
Затем это можно использовать в качестве входного UV для видеотекстуры.
Шейдер с разным разрешением.
Растяжка
Далее мы добавим периодическое растяжение изображения.Это реализуется путем умножения разрешения Y на lerp между синусоидой и 1. Мы используем синусоидальную волну, чтобы каждый раз, когда происходит растяжение, она находилась в немного другом положении.
Давайте создадим параметр скорости растяжения, а затем умножим его на время.
Давайте получим синус значения, создав базовую волну.
Затем умножьте это на 0,5 и прибавьте 0,5. Итак, перенесем волну из пространства -1 -> 1 в пространство 0 -> 1 (-1*0,5 = – 0,5, +0,5 = 0, тогда 1*0,5 = 0,5, +0,5 = 1).
Наконец, давайте умножим это на другой скалярный параметр, чтобы контролировать силу синусоидальной волны.
Для интерполятора мы используем то же деление с остаточной логикой, что и для размытия.
Создадим новый скалярный параметр, определяющий частоту появления растянутой версии, разделим остаток на время, а затем округлим значение.
Хроматическая аберрация
Последним изменением УФ будет хроматическая аберрация.Это эффект, при котором мы получаем красный и синий цвета по краям изображения из-за смещения каналов относительно друг друга.
Чтобы реализовать это, мы заменим один образец неразмытой версии текстуры тремя новыми образцами, два из которых будут смещены.
Давайте возьмем UV, которые мы создали в результате изменения разрешения, и добавим к ним скалярный параметр для смещения.
Давайте добавим это значение от 1 вдоль оси Y, а затем применим его к входным данным в качестве UV первой текстуры.
Для второй текстуры возьмем UV без изменений.
Для третьего умножьте параметр смещения на -1, затем прибавьте его к UV и прибавьте от 1 к Y. Сделав это, мы возьмем R из первой текстуры, G из второй и B из третьей, а затем объединим их, чтобы создать готовый цвет. После чего его можно использовать для интерполяции с размытием.
Структура узла хроматической аберрации.
Хроматическая аберрация на сфере.
Ээффекты изображения
Теперь, когда вы закончили экспериментировать с UV и базовым изображением, вы можете начать добавлять статические и другие эффекты изображения, которые сделают шейдер похожим на видео в стиле VHS. Для этих эффектов нам понадобится текстура, каналы которой будут хранить растровые линии, блок белого цвета и дату/время.Я рекомендую поместить дату/время в канал G, растровые линии в R и белый блок в B, чтобы воспользоваться разницей в качестве сжатия между каналами.
Моя текстура - делай как я говорю, а не как я сделал! Блокировка канала G была плохим выбором.
Если вы работаете в Photoshop, то для создания эффекта растровых линий я рекомендую использовать дискретную кисть, затем размытие в движении, а затем добавлять шум.
Модификации
Первое, что мы сделаем, это возьмем вывод lerp между размытым и нормальным видео и добавим модификации.Добавляйте узлы мощности и умножения, а затем создайте для них параметры.
Мощность позволяет регулировать гамму изображения, а умножение дает цветовой оттенок.
Материал на сфере со значительно расширенной гаммой.
Зернистость
Далее мы добавим эффект зерна.Он будет умножен на результат описанных выше модификаций.
Вместо текстуры возьмем нод симплексного шума.
Мы выполним линейную интерполяцию между шумом и единицей минус шум, чтобы положение видимого шума изменилось.
(При умножении будут видны только черные области.
) Интерполятор представляет собой скругленную синусоиду, поэтому для скорости мы добавляем Время, умноженное на новый скалярный параметр, а затем получаем синус этого значения.
Умножьте на 0,5 и прибавьте 0,5, как мы делали выше, а затем округлите, чтобы получить значения только -1, 0 или 1. После этого добавим еще один параметр для силы, поменяем его знаком минус, а затем добавим в lerp. Мы изменили его, потому что зернистость становится сильнее, когда в ней меньше белого, но это противоречит здравому смыслу пользователя, и мы делаем входящие данные чище.
Этот результат затем можно умножить на результат модификаций.
Материал на сфере с добавленной зернистостью — уменьшение гаммы позволяет легче увидеть эффект.
Вывод эффекта зерна.
Растровые линии
Далее нам нужно добавить растровые линии.Вот тут-то и пригодится текстура, которую мы создали выше.
Давайте возьмем канал блока белой текстуры, умножим его на константу float 2 со значением 1,75, чтобы создать тонкие линии.
Затем мы используем узел Panner, чтобы переместить его вдоль оси Y. Я оставил их константами, но вы можете добавить параметры скорости и тайлинга! Давайте умножим это на зерно и модификации.
Узлы для растровых линий.
Работа почти закончена!
Статические помехи
Следующим эффектом будут статические помехи.Это длинные статические полосы, создающие ощущение настоящей записи VHS. Как и в случае с растровыми линиями, мы будем использовать текстуру с Panner, но нам понадобится немного логики с координатами и скоростью, чтобы немного изменить эффект. Начнем с того, что возьмем канал растровых линий текстуры и подключим к нему нод Panner. Для координат мы создадим синусоидальную волну, которая будет менять масштаб текстуры.
Давайте умножим Время на скалярный параметр скорости, а затем получим синус этого значения и умножим его на другой параметр, чтобы получить амплитуду.
Я назвал амплитуду «Вариация», потому что она меняет значение, а значит и степень отличия текстуры от оригинала.
Умножим ее на координату текстуры, и получим растровую линию, меняющую свой масштаб! Мы хотим, чтобы скорость менялась вдоль оси y, а не вдоль оси x, поэтому добавим узел Append с константой 0 вдоль оси x. Давайте умножим волну на новый параметр скорости (не такой же, как скорость масштабирования — с постоянством шум становится менее очевидным), а затем поместим результат в слот y. Это даст нам колебательную скорость.
Добавим образец текстуры с умножением на зернистость и растровые линии.
К эффекту добавлены статические линии.
Выглядит красиво, но не очень хорошо, если на экране постоянно остается статика.
Давайте умножим это на другой вариант деления с остатком, который мы использовали для других эффектов.
Узлы статического эффекта.
Менее частый статический шум из-за деления с остатком.
Наложение
Последнее, что мы сделаем, это добавим наложение даты и времени.Давайте просто возьмем канал даты/времени из текстуры и добавим его к предыдущим эффектам.
Затем вы можете добавить множитель ко всему эффекту, чтобы создать более яркое свечение.
Наложение узлов.
Параметры
Вот и все! Вот скриншот параметров и настроек, которые я использовал при записи видео, показанного в начале статьи.
Производительность
графический процессор
Хотя этот эффект не был разработан с учетом производительности и не предназначен для игр, я призываю вас понять, как шейдеры влияют на время работы графического процессора и память! Инструкций и сэмплов здесь довольно много, даже несмотря на количество операций по выборке видеотекстур.Судя по статистике, обработка занимает около 0,3 мс во время выполнения, что я считаю вполне приемлемым, даже если видео не было основным элементом сцены.
Если бы мы использовали эффект в игре с целью добиться 60 кадров в секунду, то на 0,3 мс я бы, наверное, сэкономил.
Память
Видеотекстуры нельзя передавать в потоковом режиме, как обычные текстуры.Вы можете сгенерировать для них мип-текстуры, но они не будут иметь одинаковое поведение, поэтому всегда следует предполагать, что видео загрузится.
В моем приложении без потоковой передачи в память этот эффект в сцене занимал 130 МБ.
Это огромный объем памяти для одной текстуры.
Если это будет единственный важный элемент в сцене, то это нормально, но если он будет использоваться в больших масштабах, это может стать проблемой.
Если вы хотите использовать эту технику в игре, есть несколько способов сделать ее менее затратной:
- Сделайте видео короче - мое видео было довольно длинным.
- Уменьшите видео — я просто использовал стандартное разрешение своего телефона, а затем изменил его с помощью шейдера, и вы можете уменьшить разрешение исходного видео.
- Если вы вообще не можете себе позволить использовать видео, то создайте атлас текстур из фотографий и переключайте их по одному в шейдере.
-
Как Использовать Облачные Вычисления
19 Oct, 24 -
Косметические Изменения Gmail
19 Oct, 24 -
Google Купил Онлайн-Конкурента Word
19 Oct, 24 -
Обновление Снайпера Team Fortress 2
19 Oct, 24 -
Google Analytics Обновил Код Счетчика
19 Oct, 24 -
Новогодний Подарок От Moving Pictures
19 Oct, 24