- PVSM.RU - https://www.pvsm.ru -

Unreal Engine4 — PostProcess эффект сканирования

Unreal Engine4 — PostProcess эффект сканирования - 1

В эти выходные у меня появилось немного свободного времени между занятиями (прим. автор на момент статьи получал степень магистра наук), и я решил вернуться к созданию шейдеров, придумав этот postprocess эффект сканирования. Я представил, что он используется в игре как своего рода эффект сканирования на расстоянии. Также мы используем некоторые простые искажения шума, чтобы эффект выглядел немного интереснее.

В этой статье я расскажу, как реализовать данный эффект на UE4. Существуют несколько способов, с помощью которых вы можете создать этот эффект. Один из этих методов был выбран мною.

Вы можете открыть изображения в новой вкладке, чтобы посмотреть их в более высоком разрешении.

Основные компоненты

Основная идея этого эффекта состоит в том, чтобы создать версию рендера сцены с помощью оператора Собеля [1], а затем смешать его с обычным рендером сцены на основе SphereMask, которую мы будем анимировать для создания эффекта сканирования.

Этот эффект состоит из 3 основных компонентов:

  • Масштабируемое поле SphereMask
  • Функция Sobel-Edge (я не буду объяснять, как работает эта функция, поскольку она является отдельной темой, но я сошлюсь на код, который использовал)
  • Наложение спроецированной текстуры на сетку мира

Масштабируемое поле SphereMask

Эта часть про то, как мы создаем масштабируемую SphereMask. Для этого передаем положение blueprint’а в набор параметров материала, после чего используем его следующим образом

Unreal Engine4 — PostProcess эффект сканирования - 2

Соедините результат ноды Clamp к emissive выходу вашего материала, и вы увидите что-то вроде этого

Unreal Engine4 — PostProcess эффект сканирования - 3

«TexLoc» — это vector3, который определяет местоположение источника сферы, в моем случае он читается из набора параметров материала, так что его можно считывать и из самой игры, например, для определения положения игрока.

Набор параметров нод, указанный выше, создает поле с радиусом сферы в 1024 юнита. Я использовал его только для показа результате в окне превью. Если вы хотите более детально изучить работу с дистанционными функциями и понять методы их использования, настоятельно рекомендую проверить сайт Inigo Quilez'a [2].

Теперь мы будем использовать Time для изменения масштаба сферы с установленным промежутком времени.

Unreal Engine4 — PostProcess эффект сканирования - 4

Это нам даст следующий результат

Unreal Engine4 — PostProcess эффект сканирования - 5

Frac(time) в основном дает нам постоянный период, который продолжает идти 0-1,0-1,0-1. Мы умножаем время на 0.25, чтобы контролировать скорость масштабирования, а затем умножаем результат на радиус сферы, что приводит к изменению радиуса от 0 до 1024, и дает нам анимированную маску.

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

Unreal Engine4 — PostProcess эффект сканирования - 6

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

Unreal Engine4 — PostProcess эффект сканирования - 7

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

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

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

Для этого мы будем использовать ноду Vector Noise, который входит в состав UE4. Вы можете почитать о ней здесь [3], или вы можете использовать текстуру шума, которая содержит в себе World Aligned UV координаты.

В моем шейдере я установил в ноде Vector Noise параметр Function в Cellnoise, не стесняйтесь экспериментировать с другими типами данного параметра, чтобы получить свой собственный уникальный эффект.

Unreal Engine4 — PostProcess эффект сканирования - 8

Результат будет выглядеть следующим образом

Unreal Engine4 — PostProcess эффект сканирования - 9

На этом первый этап нашего шейдера завершен, далее мы рассмотрим реализацию функции Sobel-Edge.

Функция Sobel-Edge

Существует много различных вариантов этой функции, некоторые из которых более оптимизированы, чем другие, я не буду объяснять ее суть, поскольку это является отдельной темой, но обычный поиск в Google по ключевым словам «Sobel Edge» или «Оператор Собеля» выдаст вам множество вариантов. Или воспользуйтесь статьей на хабре от Gepard_vvk [4]Алгоритмы выделения контуров изображений [5].

Основная идея оператора Собеля заключается в следующем: мы берем RenderTarget сцены (представьте, что это текстура, которая содержит то, что вы в данный момент видите в вашем окне просмотра) и сравниваете каждый пиксель со всеми соседними пикселями вокруг него. Далее мы сравниваем разницу в яркости, и если разница выше определенного порога, мы помечаем его как край, и в этом процессе мы получаем черно-белую маску текстуры RenderTarget, в которой на края налаживается маска.

Приведенный ниже код является простым примером функции оператора Собеля, которую создал RebelMoogle [6] на сайте Shadertoy (скорее всего этот вариант не полностью оптимизирован, так что можете попробовать другую реализацию), мы воссоздадим ее в UE4 в нашем материале.

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = fragCoord.xy / iResolution.xy;
    
    vec3 TL = texture(iChannel0, uv + vec2(-1, 1)/ iResolution.xy).rgb;
    vec3 TM = texture(iChannel0, uv + vec2(0, 1)/ iResolution.xy).rgb;
    vec3 TR = texture(iChannel0, uv + vec2(1, 1)/ iResolution.xy).rgb;
    
    vec3 ML = texture(iChannel0, uv + vec2(-1, 0)/ iResolution.xy).rgb;
    vec3 MR = texture(iChannel0, uv + vec2(1, 0)/ iResolution.xy).rgb;
    
    vec3 BL = texture(iChannel0, uv + vec2(-1, -1)/ iResolution.xy).rgb;
    vec3 BM = texture(iChannel0, uv + vec2(0, -1)/ iResolution.xy).rgb;
    vec3 BR = texture(iChannel0, uv + vec2(1, -1)/ iResolution.xy).rgb;
                         
    vec3 GradX = -TL + TR - 2.0 * ML + 2.0 * MR - BL + BR;
    vec3 GradY = TL + 2.0 * TM + TR - BL - 2.0 * BM - BR;
   	    
    fragColor.r = length(vec2(GradX.r, GradY.r));
    fragColor.g = length(vec2(GradX.g, GradY.g));
    fragColor.b = length(vec2(GradX.b, GradY.b));
}

В UE4 это выглядит следующим образом

Unreal Engine4 — PostProcess эффект сканирования - 10

Небольшое замечание о реализации функции — убедитесь, что ваши ноды SceneTexture настроены на использование PostProcessInput0

Unreal Engine4 — PostProcess эффект сканирования - 11

Две Custom ноды GradX и GradY, настройте их подобным образом

Unreal Engine4 — PostProcess эффект сканирования - 12

GradX:

return -TL + TR - 2.0 * ML + 2.0 * MR - BL + BR;

GradY:

return TL + 2.0 * TM + TR - BL - 2.0 * BM - BR;

Это не обязательно должно быть сделано в Custom, я использовал ее просто для удобства, так как в противном случае бы слишком много нод и образуется спагетти.

Если вы подключите результат функции в emissive выход материала, вы увидите следующее

Unreal Engine4 — PostProcess эффект сканирования - 13

Также мы умножаем результат на обычный vector3, чтобы сделать края любого цвета, который мы захотим.

Unreal Engine4 — PostProcess эффект сканирования - 14

В итоге изменяется цвет края

Unreal Engine4 — PostProcess эффект сканирования - 15

Наложение текстуры на сетку мира

Самая простая часть: мы просто используем текстуру сетки и проецируем ее по всему миру, а затем комбинируем ее с функцией Sobel-Edge, для получения крутого эффекта.

Unreal Engine4 — PostProcess эффект сканирования - 16

Если вы подключите результат функции в emissive выход, то увидите

Unreal Engine4 — PostProcess эффект сканирования - 17

Собираем все вместе

Теперь мы соберем все три части вместе для нашего пост эффекта!

Сначала мы объединим функцию Sobel-Edge и World-Aligned-Grid, сложив их вместе

Unreal Engine4 — PostProcess эффект сканирования - 18

Затем мы создаем ноду SceneTexture и добавляем в него результат из Sobel-Edge и World-Aligned-Grid.

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

Unreal Engine4 — PostProcess эффект сканирования - 19

И вуаля, мы это сделали. Финальный результат будет выглядеть примерно так. Вы можете, конечно, настроить параметры и попробовать изменить их значения, чтобы получить более интересные варианты.

Unreal Engine4 — PostProcess эффект сканирования - 20

Надеюсь вам пригодится данная информация, всего доброго :)

Пример проекта с данным шейдером можете найти на github [7].

Автор: Александр Тарабака

Источник [8]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/razrabotka-igr/304388

Ссылки в тексте:

[1] оператора Собеля: https://ru.wikipedia.org/wiki/%D0%9E%D0%BF%D0%B5%D1%80%D0%B0%D1%82%D0%BE%D1%80_%D0%A1%D0%BE%D0%B1%D0%B5%D0%BB%D1%8F

[2] сайт Inigo Quilez'a: http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm

[3] здесь: https://docs.unrealengine.com/latest/INT/Engine/Rendering/Materials/ExpressionReference/Vector/#vectornoise

[4] Gepard_vvk: https://habr.com/users/gepard_vvk/

[5] Алгоритмы выделения контуров изображений: https://habr.com/post/114452/

[6] RebelMoogle: https://www.shadertoy.com/view/4t3XDM

[7] github: https://github.com/UnrealPlayground/PostProcessScanEffect

[8] Источник: https://habr.com/post/435240/?utm_source=habrahabr&utm_medium=rss&utm_campaign=435240