Как написать шейдер, который загорается, когда объекты находятся рядом с поверхностью?

15

В этом видео об игре Overwatch щит персонажа светится белым в областях, которые находятся рядом с геометрией других объектов.

Щит Рейнхарта обрезает некоторую геометрию уровня

Обратите внимание на белые края на синем щите около пола, стен и колонны.

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

Синий жук
источник
2
Если вы используете Unity, этот доклад может представлять интерес . Посмотрите раздел «Основные моменты пересечения», начиная со слайда 26.
Д.М.Григорий
Таким образом, ответ уже был
описан

Ответы:

28

Общий план:

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

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

  3. В шейдере вычислите разницу в глубине сцены от глубины фрагмента экрана и используйте эту разницу для изменения цвета фрагмента.

демонстрация

Я написал простую демоверсию WebGL об этом.

скриншот демо

Построчно

Давайте подробно рассмотрим код фрагмента шейдера:

float solidsDepth = texture2D(depthMap, gl_FragCoord.xy / dims).r;

Пример карты глубины для каждого фрагмента. Не забудьте разделить размеры вашего окна просмотра, чтобы преобразовать ваш фрагмент из экранного пространства [0, ширина / высота] в нормализованные [0.0, 1.0] координаты. На этом этапе, если вы просто установите цвет фрагмента в выбранный пиксель карты глубины, это будет выглядеть так:

скриншот карты глубины

Карта глубины представлена ​​в градациях серого, поэтому вы можете получить значение из любого канала (я использовал rздесь).

float solidsDiff = 1.0 - smoothstep(
    zNear,
    zFar,
    gl_FragCoord.z / gl_FragCoord.w
  ) - solidsDepth;

Затем вы можете использовать этот образец глубины, чтобы найти разницу между глубиной сцены и глубиной фрагмента экрана. Не забудьте также нормализовать свою глубину, взяв ее от [zNear, zFar] (ближняя и дальняя плоскости вашей камеры) до [0.0, 1.0]. smoothstepделает это красиво. Значение 1.0 -должно инвертировать значение, равное solidsDiff1,0, когда разница является максимальной (zFar - zNear), и 0,0 - минимальной (0,0).

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

float alpha = 0.3 + max(0.0, 1.0 - log(100.0 * (solidsDiff - 0.005) + 1.0));

Затем вы можете изменить альфа-канал вашего щита в зависимости от разницы глубины. Здесь мы начинаем с минимальной альфа 0.3, затем создаем хорошее резкое увеличение альфа, когда мы приближаемся к 0.0разнице.

- 0.005Смещение просто добавляет белый запас для того чтобы сделать «пересечение» толще. Попробуйте изменить его!

gl_FragColor = vec4(vec3(1.0), alpha);

И наконец, примените эту альфу к цвету вашего фрагмента.


Улучшения

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

Небо Ваша видеокарта это предел!

Юсеф Амар
источник
Ой. Мои. Хорошие новости. Ты за удивительный урок.
Blue Bug
5

Это просто использование карты глубины. Он рендерит мир, затем рендерит экран и берет разницу между отображаемым значением z экрана и значением z буфера глубины, чтобы сделать пиксель более белым.

Sirisian
источник
3

Я не знаю, какой движок, если есть, вы используете. Или на каком языке вы работаете. Тем не менее, большую часть того, что вы можете найти в Интернете, нетрудно перенести из одной среды в другую для достижения того, что вы ищете.

И, конечно, в Интернете есть материал, который может вам помочь. См. Это обсуждение, связанное с Unity: http://www.superspacetrooper.com/2012/06/tutorial-force-field-weapon-impact-energy-dispersion/ и этот вопрос, связанный с UE4: https: //answers.unrealengine. ru / questions / 74858 / dynamic-forcefield-shader.html . Для полного примера шейдера, реализующего этот эффект щита из недавних дебатов в Reddit, вы можете увидеть: https://www.reddit.com/r/Unity3D/comments/3edi0n/does_any_one_knows_how_to_make_this_shield_effect/ И для учебника, который не является именно на это, но имеет отношение к интересам: http://www.nightbox-studios.com/2015/09/05/assets-shield-effect-scripts-for-texture3d-perlin-noise-shader/

Кроме того, вот ссылки на 3 связанных вопроса, ранее заданные на этом сайте, которые, вероятно, будут полезны для понимания концепций, которые вы хотите достичь:

Космический корабль

Как внедрить звездный энергетический щит в игру

Эффект щита XNA с проблемой первичной сферы

Наконец, есть довольно много хороших реализаций щитовых шейдеров как в Unity, так и в Unreal Engine в их соответствующих виртуальных хранилищах, если вы используете какой-либо из этих движков. Конечно, они, как правило, платные активы, но почти всегда с открытым исходным кодом после покупки - и часто дешевы. Даже если вам не удастся использовать эти движки, эти ресурсы могут помочь поиграть и учиться.

Надеюсь, это поможет.

MAND
источник
Хотя эти ссылки полезны, этот ответ, в основном, является просто ссылками и фактически не затрагивает вопрос напрямую. Было бы лучше извлечь соответствующее содержание ссылок в фактическое объяснение.
Анко
Хотя эта ссылка может ответить на вопрос, лучше включить сюда основные части ответа и предоставить ссылку для справки. Ответы, содержащие только ссылки, могут стать недействительными, если связанная страница изменится. - Из обзора
Vaillancourt
@ Анко: Конечно, плохо. Я обычно включаю объяснение и набор ссылок, но на этот раз вы правы, настоящего объяснения не было. Тогда я, вероятно, удалю ответ.
2015 года
@AlexandreVaillancourt Мне не нравится идея просто скопировать и вставить из другой ссылки вместо перенаправления OP на исходный источник. Тогда, на мой взгляд, лучше всего дать ссылки в комментариях к вопросу. Проблема в том, что вы знаете много материала, который может помочь, но он слишком велик для комментариев. Но, тем не менее, поскольку хороший объяснительный ответ уже был размещен здесь, я просто
удалю