Ближе к концу превосходной ленты Вима Вендерса «Идеальные дни» главный герой Хираяма пьёт пиво под мостом после того, как увидел, как Бизнесмен ухаживает за девушкой, в которую влюблён Хираяма. Внезапно к нему подходит Бизнесмен. Всё оказалось не так просто, но их беседа приводит их к фундаментальным вопросам:

Бизнесмен: Тени. Становятся ли они темнее, когда накладываются друг на друга?
Хираяма: Не знаю.
Бизнесмен: Я не знаю ещё очень многого... Именно так заканчивается жизнь... Наверно.
Хираяма: Давайте узнаем прямо сейчас.
Бизнесмен: Что?

И они выходят на свет уличного фонаря, чтобы изучить свои тени (сцена целиком):

Знаковая сцена из «Идеальных дней» (2023 год)
Знаковая сцена из «Идеальных дней» (2023 год)

Хотя Бизнесмен и не видит разницы, Хираяма уверен, что пересекающиеся тени действительно становятся темнее. «Они должны становиться темнее, это логично». Очень сильная сцена.

В Metal Gear Solid тени действительно становятся темнее, когда накладываются друг на друга.
В Metal Gear Solid тени действительно становятся темнее, когда накладываются друг на друга.

К сожалению, Хираяма ошибается. Тени не становились темнее. Источник света всего один, и он довольно далеко, поэтому тень — это просто отсутствие света. Не важно, сколько раз перекрыт источник света.

В 3D-видеоиграх же тени — это нечто совсем иное. Очень легко нарисовать тёмное пятно под ногами персонажа и предполагать, что всё остальное освещено. Возможно, Хираяма вспоминал тень-пятно из Metal Gear Solid, которая становится темнее, когда накладывается на другие?

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

Экранные 2D-тени

Можно отрисовать на экране изображение тени до отрисовки персонажа. Я говорю не о спрайтах теней, как в Duke Nukem 3D, а в буквальном смысле о 2D-изображении без масштабирования. Это срабатывает, если персонаж находится на самом переднем плане, как в Winter Gold или в MDK.

Winter Gold (1996 год, SNES) и MDK (1996 год, PC) отрисовывают анимированные 2D-изображения теней. Кстати, оцените отличную видеозаставку Winter Gold в стиле Amiga
Winter Gold (1996 год, SNES) и MDK (1996 год, PC) отрисовывают анимированные 2D-изображения теней. Кстати, оцените отличную видеозаставку Winter Gold в стиле Amiga

Как я и говорил, это было просто.

Тень-пятно

Так, а теперь 3D. Отрисуем тёмный диск под персонажем. Вот и всё.

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

В Super Mario 64 (1996 год, Nintendo 64) для персонажей используются тени-пятна. Слева: тень-пятно накладывается на тени деревьев. В центре: тень-пятно усекается при помощи аппаратной функции декалей. Справа: у всех подвижных персонажей и объектов есть собственные тени. Усечённая тень внутри этого прозрачного пузыря показывает ограничения функции декалей Nintendo 64. Скриншоты сделаны в эмуляторе ares.
В Super Mario 64 (1996 год, Nintendo 64) для персонажей используются тени-пятна. Слева: тень-пятно накладывается на тени деревьев. В центре: тень-пятно усекается при помощи аппаратной функции декалей. Справа: у всех подвижных персонажей и объектов есть собственные тени. Усечённая тень внутри этого прозрачного пузыря показывает ограничения функции декалей Nintendo 64. Скриншоты сделаны в эмуляторе ares.

Тень-пятно может быть и анимированной. В Super Mario 64 она становится меньше при прыжке, а в Metal Gear Solid она меняет форму. Если вы хотите заморочиться, то можете решить проблему тени над выступом, проецируя четырёхугольник тени как декаль.

Проецируемые тени с текстурой для рендеринга

Пятно — это просто текстура, а на текстуры обычно можно выполнять рендеринг во время выполнения. Так что будем рендерить персонажа сверху и использовать это в качестве тени вместо тёмного круга. Это замечательно работает в Crash 3 (видео), но не очень хорошо в Soldier of Fortune, потому что разработчики оставили разрешение тени очень низким.

Слева: Crash Bandicoot: Warped (1998 год, PlayStation) рендерит текстуры теней во время выполнения. Справа: Soldier of Fortune (2000 год, PC) делает так же, но с меньшим разрешением. Кадр взят из видео FirstPlays HD.
Слева: Crash Bandicoot: Warped (1998 год, PlayStation) рендерит текстуры теней во время выполнения. Справа: Soldier of Fortune (2000 год, PC) делает так же, но с меньшим разрешением. Кадр взят из видео FirstPlays HD.

Стоит отметить, что это отличается от техники shadow mapping, при которой карта глубин рендерится с точки зрения источника света. Здесь мы рендерим только чёрно-белое изображение, используемое как текстура. То есть в каком-то смысле мы говорим об однобитной shadow map.

Как можно сделать тени резче?

Проецируемые тени с геометрией

Самолёт F-117A, отбрасывающий тень в F-19 Stealth Fighter (1988 год, DOS).
Самолёт F-117A, отбрасывающий тень в F-19 Stealth Fighter (1988 год, DOS).

Сразу приходит в голову такой вариант: «разгладить» отбрасывающий тень объект на плоскости, спроецировав его от источника света. Затем отрендерить его во второй раз, но уже в чёрном цвете. Такие тени обычно оставляют непрозрачными, чтобы скрыть, как части объекта отрисовываются одна поверх другой. Естественно, тень будет корректна только на плоской поверхности пола.

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

Проецируемые тени GLQuake в двух играх. Слева: Kingpin: Life of Crime (1999 год, PC) использует чёрные тени. Справа: проблемы с прозрачностью в Half-Life alpha 0.52
Проецируемые тени GLQuake в двух играх. Слева: Kingpin: Life of Crime (1999 год, PC) использует чёрные тени. Справа: проблемы с прозрачностью в Half-Life alpha 0.52

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

Тени на рельефе

Virus (1987 год), порт на Atari ST. Маленький корабль отбрасывает милую падающую тень.
Virus (1987 год), порт на Atari ST. Маленький корабль отбрасывает милую падающую тень.

Игра Virus (1987 год) Дэвида Брэбена на Acorn Archimedes и других домашних компьютерах отрисовывает космические корабли, отбрасывающие на рельеф тени с проекцией сверху.

Более сложный пример — это Interstate ’76. Разработчики изгибали и растягивали плоскую тень, чтобы она соответствовала наклону поверхности. Тени иногда проходят сквозь землю, но в целом эффект довольно правдоподобный. Любопытно, что в показанном ниже программно отрендеренном скриншоте тени слегка прозрачные, а при аппаратном ускорении они полностью чёрные.

Разработчики даже осмелились попробовать проецировать тени больших объектов наподобие мостов, и это им успешно удалось.

В Interstate ’76 (1997 год, PC) были отбрасываемые солнцем на поверхность земли проецируемые наклонные тени.
В Interstate ’76 (1997 год, PC) были отбрасываемые солнцем на поверхность земли проецируемые наклонные тени.

Но как отбрасывают тени в любом типе сцены?

Падающая тень на проецируемой текстуре

Слева: слайд из доклада Toy Story 3: The Video Game Rendering Techniques. Справа: падающая тень становится темнее, когда накладывается на другие тени. Кадр взят из видео геймплея на Xbox 360 Toy Story 3: The Video Game (2010 год).
Слева: слайд из доклада Toy Story 3: The Video Game Rendering Techniques. Справа: падающая тень становится темнее, когда накладывается на другие тени. Кадр взят из видео геймплея на Xbox 360 Toy Story 3: The Video Game (2010 год).

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

Подобные тени можно сделать очень резкими, но они могут выглядеть странно на вертикальных поверхностях и иногда даже отображаются на потолках. См. видео геймплея Sonic Adventure 2: Battle (2001 год, GameCube).

Кроме того, эта техника отлично подходит для деревьев:

The Elder Scrolls IV: Oblivion (2006 год, Xbox 360) имела красивые спроецированные тени деревьев.
The Elder Scrolls IV: Oblivion (2006 год, Xbox 360) имела красивые спроецированные тени деревьев.

Проецированные тени могут просвечивать сквозь объекты, поэтому применимы лишь в особых случаях. Shadow map (карты теней) можно использовать где угодно.

Shadow map

Этот подход обычно используется для реализации теней. Игра отрисовывает изображение глубин (shadow map) с точки зрения источника освещения, и выполняет чтение из этого изображения при рендеринге мира. Это легко сделать, поскольку можно заново использовать обычный код рендеринга игрового движка.

В Half-Life 2 (2004 год, PC) shadow map использовались для персонажей. Динамические тени от фонаря (на скриншоте не показаны) были добавлены в расширении Episode Two (2007 год).
В Half-Life 2 (2004 год, PC) shadow map использовались для персонажей. Динамические тени от фонаря (на скриншоте не показаны) были добавлены в расширении Episode Two (2007 год).

Ограниченное разрешение shadow map приводит к появлению хорошо известных артефактов с забавными названиями, например, Peter Panning и «теневое акне». Было предложено множество трюков для выделения большей площади shadow map поверхностям, находящимся рядом с камерой, где дополнительное разрешение нужно больше всего. Обычно для красивого отображения необходима некоторая настройка shadow map.

До того, как shadow map стали доминирующей технологией, у них был популярный конкурент.

Стенсил-тени

Ранее популярный способ реализации теней. Стенсил-тени отрисовывают резкие тени на любом типе поверхности. Они создают уникальную атмосферу в стиле фильмов жанра «нуар», который сложно имитировать при помощи shadow map. Самый известный пример — это, разумеется, Doom 3 с его тёмными помещениями:

В Doom 3 (2004 год) не было статического освещения уровней и все тени вычислялись во время выполнения. Скриншот из Doom 3 shadow engine snapshots.
В Doom 3 (2004 год) не было статического освещения уровней и все тени вычислялись во время выполнения. Скриншот из Doom 3 shadow engine snapshots.

Стенсил-тени основаны на принципе объёмов теней (shadow volume) — невидимой геометрии, разбивающей мир на освещённые и затенённые пространства. Игра применяет освещение только к тем пикселям, которые не находятся в объёме теней.

Игра должна создавать меши «объёмов теней», показанные жёлтым цветом. Поверхности внутри объёмов остаются неосвещёнными. Иллюстрация shadow volume автора Rainwarrior.
Игра должна создавать меши «объёмов теней», показанные жёлтым цветом. Поверхности внутри объёмов остаются неосвещёнными. Иллюстрация shadow volume автора Rainwarrior.

Чтобы стенсил-тени работали, мир необходимо перерисовывать множество раз. Если упростить, то игра сначала отрисовывает весь мир с освещением окружающей среды (ambient lighting). Затем для каждого источника света создаются все объёмы тени, за которыми снова следует весь мир, задействуя только незатенённые пиксели. Объёмы отрисовываются разными стенсил-операциями для передних и задних граней. То есть приходится отрисовывать очень большое количество пикселей.

Наверно, самой первой выпущенной игрой со стенсил-тенями стала Severance: Blade of Darkness (2001 год), где тени выглядят великолепно.

Severance: Blade of Darkness (2001 год, PC) со стенсил-тенями.
Severance: Blade of Darkness (2001 год, PC) со стенсил-тенями.

Читая обзор игры в британской версии журнала Edge за март 2001 года (pdf), становится очевидно, что, несмотря на графический прогресс, мир в те времена ещё не был готов к «соулслайкам».

Сегодня стенсил-тени особо не используются. Одна из причин этого заключается в непредсказуемых затратах во время выполнения. Эти затраты зависят от величины объёма тени на экране, а значит, могут сильно варьироваться. Кроме того, был запатентован оптимизированный алгоритм. Для разработки Doom 3 Id Software, похоже, заключила некий договор.

Мягкие стенсил-тени

Слева: Silent Hill 2 (2001 год, PlayStation 2) с мягкими стенсил-тенями. В центре: двукратное увеличение. Справа: режим отладки теней, где неосвещённые области окрашены чёрным. Немного осветлённые скриншоты из эмулятора PCSX2.
Слева: Silent Hill 2 (2001 год, PlayStation 2) с мягкими стенсил-тенями. В центре: двукратное увеличение. Справа: режим отладки теней, где неосвещённые области окрашены чёрным. Немного осветлённые скриншоты из эмулятора PCSX2.

Стенсил-тени не обязаны быть резкими. В игре 2001 года Silent Hill 2 для PlayStation 2, как показано выше, стенсил-тени размываются. На консоли это выглядит почти идеально.

Тени упрощённых персонажей

А что, если тени будут отбрасываться более простой моделью, чем та, которая видна на экране? Например, в Zelda на Nintendo 64 ноги Линка отбрасывают тени, даже если ничто их не отбрасывает:

В The Legend of Zelda: Ocarina of Time (1998 год, Nintendo 64) ноги Линка отбрасывают тени, как будто они состоят из высоких вертикальных цилиндров. Предполагаю, что тени — это две растянутые декали.
В The Legend of Zelda: Ocarina of Time (1998 год, Nintendo 64) ноги Линка отбрасывают тени, как будто они состоят из высоких вертикальных цилиндров. Предполагаю, что тени — это две растянутые декали.

Уникальный подход использован в Hyperblade — игроки на футуристической хоккейной арене отбрасывают проецируемые тени в виде простых анимированных фигур.

В Hyperblade (1996 год, PC) проецируются упрощённые плоские подвижные тени. Как видно на правом скриншоте, они неидеальны. Кадры из видео Bit Games Reviews.
В Hyperblade (1996 год, PC) проецируются упрощённые плоские подвижные тени. Как видно на правом скриншоте, они неидеальны. Кадры из видео Bit Games Reviews.

Тени в статическом освещении уровней

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

Цвета вершин

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

В Ico (2001 год, PlayStation 2) освещение уровней запекалось в цвета вершин. Для персонажей использовались стенсил-тени.
В Ico (2001 год, PlayStation 2) освещение уровней запекалось в цвета вершин. Для персонажей использовались стенсил-тени.

На низкополигональных картах даже резкие тени можно представить в виде цветов вершин. Отличным примером этого может служить Tony Hawk Pro Skater 2 (2000 год, Playstation), которая выглядела великолепно, учитывая простоту техники.

Уровень Venice Beach в Tony Hawk Pro Skater 2 (2000 год, PlayStation) с резкими тенями в виде цветов вершин. Кадр взят из порта для Dreamcast.
Уровень Venice Beach в Tony Hawk Pro Skater 2 (2000 год, PlayStation) с резкими тенями в виде цветов вершин. Кадр взят из порта для Dreamcast.

Карты освещения

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

Mirror’s Edge (2008 год, PC), по сути, и есть одни сплошные карты освещённости.
Mirror’s Edge (2008 год, PC), по сути, и есть одни сплошные карты освещённости.

Карты освещения были популяризированы игрой Quake (1996 год, PC), где выглядели так: https://jbush001.github.io/2015/06/11/quake-lightmaps.html.

На этом мы закончим изучение традиционных методик создания теней. А теперь давайте немного поговорим об освещении в целом.

Тени в современных играх

По возможности в современных играх используются традиционные техники. Вот некоторые из примеров:

Тени, получаемые трассировкой лучей

В начале статьи мы сказали, что тени образуются отсутствием света. Если игра действительно пытается симулировать физически корректное освещение, то тени должны выглядеть естественно. Даже маленькие геометрические детали отбрасывают точные тени, в отличие случая с shadow map. Большие лампы естественным образом создают мягкие тени, а непрямое освещение делает светлее тёмные уголки. Для реализации всего этого потребовалось потратить невероятное количество времени и денег на разработку алгоритмов и оборудования трассировки лучей (ray tracing).

На практике современные игры имеют такие сложные сцены, что описанное выше симулируемое решение необходимо аппроксимировать. Например, в получаемых трассировкой лучей тенях Alan Wake 2 (2023 год) каждый пиксель принимает освещение только от одного случайно выбранного источника. Далее результат подаётся алгоритму устранения шумов, который интеллектуальным образом сглаживает шумную картинку. Подробности см. в презентации. Следовательно, даже полученные трассировкой лучей тени не будут «идеальными» и в зависимости от выбранных компромиссов обладают собственным уникальным внешним видом.

И под конец приведём ещё один очевидный вариант.

Отсутствие теней

Иногда тени для вас не главное.

В Alone in the Dark (1992 год, DOS) у персонажей не было теней.
В Alone in the Dark (1992 год, DOS) у персонажей не было теней.

Когда Хираяма в сцене из фильма внимательно изучает тени, его новый друг замечает:

Бизнесмен: Да тебе это действительно нравится.

Думаю, мы, как любители компьютерной графики, разделяем его увлечение.

Все скриншоты взяты с MobyGames, если не указано иное. Благодарю mankeli за подробные примечания по первому черновику статьи. Выражаю благодарность noby, msqrt, shaiggon и Warma за отзывы.

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


  1. Maximov_psy
    31.10.2024 12:07

    Ничего не понятно, но очень интересно!


  1. Treviz
    31.10.2024 12:07

    С Doom3, насколько я помню, была такая история. Кармак написал движок: графику, физику, звук. Звуковой софтварный движок, кстати, очень неплохой получился. Но Креатив с патентом на тени (они когда-то и видюхи выпускали, с тех времён осталось) пригрозила судом. В рамках досудебного урегулирования добавили в игру поддержку X-Fi с EAX. Причём внедрением по сути занималась сама Креатив: Кармак их недолюбливал. Заодно перелопатили весь OpenAL.


  1. barnes
    31.10.2024 12:07

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


  1. DimPal
    31.10.2024 12:07

    Тема интересная, но статья выглядит как поток сознания (путано и не последовательно). Полностью забыто что есть мягкие тени. Light map - это метод кэширования освещения (включая вторичку), а не генерации теней. Самопересекающися тени это либо результат оптимизации по скорости, либо непонимание как сделать правильно (хотя зависит от постановки задачи). Все методы имеют разнве артефакты при наивной реализации, методы борьбы с ними - действительно интересная, но узкая тема.


  1. da-nie
    31.10.2024 12:07

    Ну а я делал так.

    И получалось так:


    1. DimPal
      31.10.2024 12:07

      А если там скелетно анимированные монстры побегут на десяток тысяч полигонов, для их теней производительности CPU хватит всё пересчитать на лету?


      1. da-nie
        31.10.2024 12:07

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


        1. DimPal
          31.10.2024 12:07

          Для узкоспециализированых задач - отличный алгоритм.


  1. ArkadiyMak
    31.10.2024 12:07

    В Half-Life 2 (2004 год, PC) shadow map использовались для персонажей.
    Это не так, в хл2 были проекционные тени.

    The Elder Scrolls IV: Oblivion (2006 год, Xbox 360) имела красивые спроецированные тени деревьев.
    Это не так, на геометрию под деревьями накладывалась заранее нарисованная тайлящаяся текстура. Деревья не рендерились в проекционную текстуру, со спидтришными спрайтовыми листьями это вообще было бы проблематично сделать.