Ближе к концу превосходной ленты Вима Вендерса «Идеальные дни» главный герой Хираяма пьёт пиво под мостом после того, как увидел, как Бизнесмен ухаживает за девушкой, в которую влюблён Хираяма. Внезапно к нему подходит Бизнесмен. Всё оказалось не так просто, но их беседа приводит их к фундаментальным вопросам:
Бизнесмен: Тени. Становятся ли они темнее, когда накладываются друг на друга?
Хираяма: Не знаю.
Бизнесмен: Я не знаю ещё очень многого... Именно так заканчивается жизнь... Наверно.
Хираяма: Давайте узнаем прямо сейчас.
Бизнесмен: Что?
И они выходят на свет уличного фонаря, чтобы изучить свои тени (сцена целиком):
Хотя Бизнесмен и не видит разницы, Хираяма уверен, что пересекающиеся тени действительно становятся темнее. «Они должны становиться темнее, это логично». Очень сильная сцена.
К сожалению, Хираяма ошибается. Тени не становились темнее. Источник света всего один, и он довольно далеко, поэтому тень — это просто отсутствие света. Не важно, сколько раз перекрыт источник света.
В 3D-видеоиграх же тени — это нечто совсем иное. Очень легко нарисовать тёмное пятно под ногами персонажа и предполагать, что всё остальное освещено. Возможно, Хираяма вспоминал тень-пятно из Metal Gear Solid, которая становится темнее, когда накладывается на другие?
В реальном мире тени просто существуют, но в играх они разрабатываются и проектируются. Они должны обеспечивать хорошую производительность, но при этом прилично выглядеть. Эта взаимосвязь кажется мне восхитительной, и в статье я объясню, почему. Начнём с простых примеров.
Экранные 2D-тени
Можно отрисовать на экране изображение тени до отрисовки персонажа. Я говорю не о спрайтах теней, как в Duke Nukem 3D, а в буквальном смысле о 2D-изображении без масштабирования. Это срабатывает, если персонаж находится на самом переднем плане, как в Winter Gold или в MDK.
Как я и говорил, это было просто.
Тень-пятно
Так, а теперь 3D. Отрисуем тёмный диск под персонажем. Вот и всё.
На самом деле, нужно ещё и выровнять диск тени относительно земли, а также подумать, как обрабатывать ситуации, когда тень накладывается на уступ. Например, в Super Mario 64 пятна отрисовываются при помощи особой аппаратной функции, которая, по сути, усекает тень, чтобы она отображалась только на плоскости земли.
Тень-пятно может быть и анимированной. В Super Mario 64 она становится меньше при прыжке, а в Metal Gear Solid она меняет форму. Если вы хотите заморочиться, то можете решить проблему тени над выступом, проецируя четырёхугольник тени как декаль.
Проецируемые тени с текстурой для рендеринга
Пятно — это просто текстура, а на текстуры обычно можно выполнять рендеринг во время выполнения. Так что будем рендерить персонажа сверху и использовать это в качестве тени вместо тёмного круга. Это замечательно работает в Crash 3 (видео), но не очень хорошо в Soldier of Fortune, потому что разработчики оставили разрешение тени очень низким.
Стоит отметить, что это отличается от техники shadow mapping, при которой карта глубин рендерится с точки зрения источника света. Здесь мы рендерим только чёрно-белое изображение, используемое как текстура. То есть в каком-то смысле мы говорим об однобитной shadow map.
Как можно сделать тени резче?
Проецируемые тени с геометрией
Сразу приходит в голову такой вариант: «разгладить» отбрасывающий тень объект на плоскости, спроецировав его от источника света. Затем отрендерить его во второй раз, но уже в чёрном цвете. Такие тени обычно оставляют непрозрачными, чтобы скрыть, как части объекта отрисовываются одна поверх другой. Естественно, тень будет корректна только на плоской поверхности пола.
В некоторых ранних лётных симуляторах плоская тень в проекции сверху рендерилась на взлётной полосе. В процессе своих исследований я надеялся найти примеры того, что тень видна и во время полёта, но не смог обнаружить ни одного.
Визуально они выглядят как чёрные стенсил-тени, отбрасываемые на плоскую поверхность.
Тени на рельефе
Игра Virus (1987 год) Дэвида Брэбена на Acorn Archimedes и других домашних компьютерах отрисовывает космические корабли, отбрасывающие на рельеф тени с проекцией сверху.
Более сложный пример — это Interstate ’76. Разработчики изгибали и растягивали плоскую тень, чтобы она соответствовала наклону поверхности. Тени иногда проходят сквозь землю, но в целом эффект довольно правдоподобный. Любопытно, что в показанном ниже программно отрендеренном скриншоте тени слегка прозрачные, а при аппаратном ускорении они полностью чёрные.
Разработчики даже осмелились попробовать проецировать тени больших объектов наподобие мостов, и это им успешно удалось.
Но как отбрасывают тени в любом типе сцены?
Падающая тень на проецируемой текстуре
Этот подход имеет много общего с методикой «Проецируемые тени с текстурой для рендеринга», но работает на поверхностях любой формы. Игра рендерит текстуру тени из проекции сверху, но не отображает её на плоской поверхности, а проецирует текстуру на другие объекты. Можно представить, что это бэт-сигнал, но направленный прямо вниз с неба.
Подобные тени можно сделать очень резкими, но они могут выглядеть странно на вертикальных поверхностях и иногда даже отображаются на потолках. См. видео геймплея Sonic Adventure 2: Battle (2001 год, GameCube).
Кроме того, эта техника отлично подходит для деревьев:
Проецированные тени могут просвечивать сквозь объекты, поэтому применимы лишь в особых случаях. Shadow map (карты теней) можно использовать где угодно.
Shadow map
Этот подход обычно используется для реализации теней. Игра отрисовывает изображение глубин (shadow map) с точки зрения источника освещения, и выполняет чтение из этого изображения при рендеринге мира. Это легко сделать, поскольку можно заново использовать обычный код рендеринга игрового движка.
Ограниченное разрешение shadow map приводит к появлению хорошо известных артефактов с забавными названиями, например, Peter Panning и «теневое акне». Было предложено множество трюков для выделения большей площади shadow map поверхностям, находящимся рядом с камерой, где дополнительное разрешение нужно больше всего. Обычно для красивого отображения необходима некоторая настройка shadow map.
До того, как shadow map стали доминирующей технологией, у них был популярный конкурент.
Стенсил-тени
Ранее популярный способ реализации теней. Стенсил-тени отрисовывают резкие тени на любом типе поверхности. Они создают уникальную атмосферу в стиле фильмов жанра «нуар», который сложно имитировать при помощи shadow map. Самый известный пример — это, разумеется, Doom 3 с его тёмными помещениями:
Стенсил-тени основаны на принципе объёмов теней (shadow volume) — невидимой геометрии, разбивающей мир на освещённые и затенённые пространства. Игра применяет освещение только к тем пикселям, которые не находятся в объёме теней.
Чтобы стенсил-тени работали, мир необходимо перерисовывать множество раз. Если упростить, то игра сначала отрисовывает весь мир с освещением окружающей среды (ambient lighting). Затем для каждого источника света создаются все объёмы тени, за которыми снова следует весь мир, задействуя только незатенённые пиксели. Объёмы отрисовываются разными стенсил-операциями для передних и задних граней. То есть приходится отрисовывать очень большое количество пикселей.
Наверно, самой первой выпущенной игрой со стенсил-тенями стала Severance: Blade of Darkness (2001 год), где тени выглядят великолепно.
Читая обзор игры в британской версии журнала Edge за март 2001 года (pdf), становится очевидно, что, несмотря на графический прогресс, мир в те времена ещё не был готов к «соулслайкам».
Сегодня стенсил-тени особо не используются. Одна из причин этого заключается в непредсказуемых затратах во время выполнения. Эти затраты зависят от величины объёма тени на экране, а значит, могут сильно варьироваться. Кроме того, был запатентован оптимизированный алгоритм. Для разработки Doom 3 Id Software, похоже, заключила некий договор.
Мягкие стенсил-тени
Стенсил-тени не обязаны быть резкими. В игре 2001 года Silent Hill 2 для PlayStation 2, как показано выше, стенсил-тени размываются. На консоли это выглядит почти идеально.
Тени упрощённых персонажей
А что, если тени будут отбрасываться более простой моделью, чем та, которая видна на экране? Например, в Zelda на Nintendo 64 ноги Линка отбрасывают тени, даже если ничто их не отбрасывает:
Уникальный подход использован в Hyperblade — игроки на футуристической хоккейной арене отбрасывают проецируемые тени в виде простых анимированных фигур.
Тени в статическом освещении уровней
Для фиксации освещения на уровнях игры можно использовать техники цветов вершин и карт освещения (lightmap). Они применялись во многих играх как единственный способ отображения крупных теней, поэтому я и добавил их в статью.
Цвета вершин
В Ico видно, насколько сложными могут выглядеть тени при обычном старомодном вершинном освещении.
На низкополигональных картах даже резкие тени можно представить в виде цветов вершин. Отличным примером этого может служить Tony Hawk Pro Skater 2 (2000 год, Playstation), которая выглядела великолепно, учитывая простоту техники.
Карты освещения
Карты освещения — это классический способ хранения освещения и теней уровней. Вместо того, чтобы хранить цвет для каждой вершины, мы создаём второй набор текстур, хранящий только освещение. Их разрешение может варьироваться в зависимости от областей игры, благодаря чему в нужных местах тени способны быть более точными. С другой стороны, для карт освещения требуется больше памяти, чем для цветов вершин.
Карты освещения были популяризированы игрой Quake (1996 год, PC), где выглядели так: https://jbush001.github.io/2015/06/11/quake-lightmaps.html.
На этом мы закончим изучение традиционных методик создания теней. А теперь давайте немного поговорим об освещении в целом.
Тени в современных играх
По возможности в современных играх используются традиционные техники. Вот некоторые из примеров:
Разновидности shadow mapping, например, Cascaded Shadow Maps, позволяющие покрывать большие площади, сохраняя при этом высокую скорость.
Карты освещения в сочетании с другими техниками, например, light probe. В Call of Duty по-прежнему используются карты освещения, см. слайды Hemispherical Lighting Insights.
Идея упрощённой модели персонажа. В The Last of Us (2013 год, PlayStation 3) мягкие тени персонажей отбрасываются при помощи растянутых сфер. См. слайд из доклада Lighting Technology of The Last Of Us (2013). Кроме того, Unreal Engine поддерживает упрощённые капсульные тени для персонажей.
Проецируемые тени. В Hot Wheels Track Attack (2010 год, Wii) меши теней рендерятся на текстуру, а затем она проецируется на гоночную трассу, как описывается в блоге одного разработчика. В движении игра выглядит великолепно.
Тени, получаемые трассировкой лучей
В начале статьи мы сказали, что тени образуются отсутствием света. Если игра действительно пытается симулировать физически корректное освещение, то тени должны выглядеть естественно. Даже маленькие геометрические детали отбрасывают точные тени, в отличие случая с shadow map. Большие лампы естественным образом создают мягкие тени, а непрямое освещение делает светлее тёмные уголки. Для реализации всего этого потребовалось потратить невероятное количество времени и денег на разработку алгоритмов и оборудования трассировки лучей (ray tracing).
На практике современные игры имеют такие сложные сцены, что описанное выше симулируемое решение необходимо аппроксимировать. Например, в получаемых трассировкой лучей тенях Alan Wake 2 (2023 год) каждый пиксель принимает освещение только от одного случайно выбранного источника. Далее результат подаётся алгоритму устранения шумов, который интеллектуальным образом сглаживает шумную картинку. Подробности см. в презентации. Следовательно, даже полученные трассировкой лучей тени не будут «идеальными» и в зависимости от выбранных компромиссов обладают собственным уникальным внешним видом.
И под конец приведём ещё один очевидный вариант.
Отсутствие теней
Иногда тени для вас не главное.
Когда Хираяма в сцене из фильма внимательно изучает тени, его новый друг замечает:
Бизнесмен: Да тебе это действительно нравится.
Думаю, мы, как любители компьютерной графики, разделяем его увлечение.
Все скриншоты взяты с MobyGames, если не указано иное. Благодарю mankeli за подробные примечания по первому черновику статьи. Выражаю благодарность noby, msqrt, shaiggon и Warma за отзывы.