Pull to refresh

Шейдер интерьеров — придаём объём плоским зданиям

Level of difficultyMedium
Reading time3 min
Views5.1K

Эта техника популярна для игр, поскольку позволяет добавить визуального объёма простым объектам, состоящим из плоских полигонов, без существенного понижения производительности, как это было бы при создание физических интерьеров. Иллюзия помещения достигается путём использования cubemaps и эффекта параллакса.

Пример эффективного использования эффекта: Spiderman
Пример эффективного использования эффекта: Spiderman

Но не смотря на это, по какой-то причине, на русском языке нет туториала, как реализовать эффект интерьеров.

Я покажу реализацию в Unity используя Shader Graph, однако, путём некоторых манипуляций, вы можете воспроизвести эффект и в Unreal Engine используя Material Graph (изменить вертикальную ось на z, изменить формат cubemaps). Математика, стоящая за параллаксом, принципиально одинаковая.


Алгоритм параллакса для интерьера

  1. Подготавливаем UV координаты. Поскольку cubemap объёмный, UV координаты используются как Vector3.Умножение понадобиться в дальнейшем, пока не обращайте внимание. Ограничиваем координаты при помощи frac диапозоном от 0 до 1, выставляем точу отсчёта по центру. Хардкодим z = -1.

  2. Подготавливаем вектор взгляда в Tangent пространстве, чтобы он правильно складывался с UV.

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

  1. Расчёт параллакса. Берём обратное число (Reciprocal) вектора взгляда. Получаем абсолютное значение обратного вектора, умножаем обратной вектор взгляда на UV. Находим разность абсолютного значения и произведения. Находим минимальное значение из трёх координат. Умножаем его на вектор взгляда и добавляем к UV результат произведения

Теперь мы можем передать полученый значения в ноду Sample Cubemap, и вуаля, получим эффект параллакса с иллюзией, будто спроецированные стороны cubemap находятся на внутренней стороне куба

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

Однако, у этого алгоритма есть минус, одна из сторон оказывается перевёрнута.

"Красивым" математическим способом избавиться от этого переворачивания у меня не удалось, поэтому был имплементирован следующий костыль (ваши предложения по решению проблемы, если такие есть, пишите в комментариях):

Берём z координату и сравниваем её с неким float F по формуле round(z * F) <= F / 2. Если результат сравнения true, то умножаем y координату на -1.

В результате сторона поворачивается, но остаётся артефакт на прилегающей боковой стороне размером 1/(F/2) от длины стороны.

Артефакт при F = 2
Артефакт при F = 2

Подняв F до нескольких тысяч можно минимизировать этот артефакт, однако решение всё равно не идеально.

Артефакт при F = 5000, маленькие полоски видны под некоторыми углами
Артефакт при F = 5000, маленькие полоски видны под некоторыми углами

Почему нельзя пойти простым путём, и просто не проверять, равна ли координата -0.5? Дело в том, что по какой-то причине, у куба в его собственном пространстве ровная боковая грань по какой-то причине не имеет одинаковой координаты, и мы получаем куда более неприятный артефакт:

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


Особенности cubemap

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

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


Фасад

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

Превращаем текущий Graph в SubGrapph, который возвращает итоговый Vector3. Можно также открыть UV и переменную являющуюся количеством комнат.

Итак, шейдер фасада:

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

Использую текстуру прозрачности умноженную на эффект Френеля для смешивания текстуры и получения базового цвета. Для расчета emission умножаем цвет интерьера на прозрачность с эффектом Френеля. В качестве гладкости передаю просто базовую прозрачность.


Заключение

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

Куб с шейдером интерьеров
Куб с шейдером интерьеров

Tags:
Hubs:
Total votes 23: ↑22 and ↓1+21
Comments9

Articles