Одним прекрасным утром прошлой осенью мы узнали долгожданную новость: антагонист готов!
Это была всего лишь черновая модель: без волос, скина и соответствующей настройки материалов, но мы все равно очень обрадовались. Кто-то сразу предложил: «Давайте скорей налепим на него материалы! Уже не терпится увидеть этого парня на экране!».

Так мы и сделали. Но что-то пошло не так… «Стойте, а мы точно настроили его для получения динамических теней?» Всё верно. Но результат совсем не оправдал наши ожидания.



Проблема

Покопавшись в шейдере, мы обнаружили суть проблемы: половина теней не отображалась в принципе, а вторая половина отображалась неправильно.



«В чем дело?» – спросите вы. – «Как же новый алгоритм фильтрации в Unity 5, который делает тени более мягкими и реалистичными?». А дело в том, что в некоторых сценах камера находилась на расстоянии до 3000 метров, и мы хотели, чтобы тени отображались на каждом пикселе в пределах ее поля зрения. Разумеется, мы специально настроили каскадные сплиты и параметры смещения для качественного отображения теней как непосредственно перед камерой, так и на большом расстоянии.

Проблема в том, что мы совсем не предусмотрели крупный план персонажа в такой масштабной сцене. Мало того, что для создания мягких теней нам не хватало разрешения, так еще и смещение глубины, которое мы настроили для сцены, было настолько большим, что персонаж практически остался без теней. Оказывается, мягкая тень, отбрасываемая кожаным ремешком на броню, сильно отличается от мягкой тени, отбрасываемой крупным булыжником на поверхность земли. Кто бы мог подумать!

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

Решение

Тем не менее мы решили применить более традиционную технологию: сделать для персонажей отдельные карты теней. Две сотни строчек кода – и вуаля! Вот что у нас получилось:



На этом этапе мы уже имели достаточно данных для применения практически любого фильтра теней. Но времени на его точную настройку не хватало, поэтому решили остановиться на простом сэмплинге с учетом расстояния, похожем на технологию теней Nvidia PCSS [1].

Кроме того, у нас появилась возможность собирать данные со статичных объектов, находящихся за пределами крупного плана и отбрасывающих тени на динамические объекты, то есть на персонажей. Статичные объекты проецировались на переднюю плоскость камеры рендеринга, что обеспечивало максимальное расстояние Blocker-to-Receiver в схеме мягкой фильтрации теней.

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

#pragma multi_compile _ UNIQUE_SHADOW UNIQUE_SHADOW_LIGHT_COOKIE #include "UniqueShadow_ShadowSample.cginc"

Обратите внимание, что для корректной работы этой функции строка #include должна быть прописана перед любыми другими строками #include в коде. Если вы планируете использовать этот метод для похожих целей, учтите, что вся сложность замены заключается в коде, спрятанном в файле include:

#if SOME_CONDITION_ENABLING_OUR_FEATURE #include "AutoLight.cginc" #undef SHADOW_COORDS #undef TRANSFER_SHADOW #undef SHADOW_ATTENUATION #define SHADOW_COORDS(i) SOME_OTHER_COORD(i) #define TRANSFER_SHADOW SOME_OTHER_TRANSFER #define SHADOW_ATTENUATION(i) SOME_OTHER_ATTEN(i) #endif

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

Результат

Итак, удалось ли нам достичь удовлетворительных результатов? Посмотрите сами! Вот так выглядит тот же рендер с уникальными тенями и без них:



Вывод

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

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

Чтобы лучше продемонстрировать эту фичу, мы создали небольшой демопроект, который можно скачать на Asset Store. На примере сцены из ролика вы можете увидеть, как сохранить высокую детализацию крупного плана персонажа в большом открытом пространстве. Несмотря на то, что первый каскад покрывает всего 1 % общего Shadow Distance, разница налицо: модель с уникальными тенями слева выглядит намного лучше, чем модель с каскадными тенями справа.



Референсы.

Комментарии (1)


  1. fshp
    09.12.2015 14:44
    +2

    А где сравнение полных рендеров? По рендеру буфера ничего не понятно.