Русский
Русский
English
Статистика
Реклама

Конвейер рендеринга

Перевод Анализ графики Red Dead Redemption 2

01.07.2020 10:24:00 | Автор: admin
Одна из моих любимейших игр, Red Dead Redemption, в 2018 году вернулась с приквелом для консолей. В 2019 году её выпустили для PC, и мне наконец удалось поиграть в неё; меня сразу же поразила её графика. Однако я расстроился: мне едва удавалось играть при средних настройках с 25 FPS на настольном GPU 1050Ti. Понимаю, машина у меня не очень мощная, но 25 FPS на средних настройках?

Сегодня мы рассмотрим несколько примеров кадров из игры и проанализируем использованные в игре графические приёмы.

Предисловие


Это неофициальный анализ игры. Я просто проанализировал захват кадров при помощи RenderDoc. Если вы хотите узнать информацию от самих разработчиков, то можете изучить слайды с доклада на SIGGRAPH Фабиана Байера. Слайды (внизу страницы), видео (начинается с 1:58:00).

Также можно прочитать анализ графики GTA5, выполненный Адрианом Корреже [перевод на Хабре]. Так как и RDR2, и GTA5 созданы одной компанией и используют один движок, часть приёмов из GTA5 присутствует и здесь.

Ещё один важный момент я не являюсь опытным программистом графики и по-прежнему новичок в этой области. Поэтому многое мне непонятно. Если вы найдёте ошибки или то, что можно улучшить, пишите мне. Ну, поехали!

Разбираем кадр


Вот наш основной кадр для анализа:


Кадр захвачен на PC со средними настройками.

В играх наподобие RDR2 почти невозможно исследовать все приёмы в одном кадре. Их работа переносится между несколькими кадрами. Поэтому я выполнил захват нескольких кадров, но показанный выше будет основным. Он содержит множество свойств, в том числе: прожекторные и точечные источники освещения, направленное освещение (его очень мало, но оно есть), здания, NPC, лошадь, деревья, растительность, облака и т.д. В нём можно показать большинство используемых в игре техник рендеринга.

RDR2 это игра с открытым миром, поэтому потоковая загрузка данных выполняется постоянно. Следовательно, построение кадра начинается с набора таких задач, как создание и удаление текстур, просмотры ресурсов шейдеров, просмотры с беспорядочным доступом, обновление дескрипторов, буферов и т.д.

Карта земли/грязи


Грязь играет большую роль. Кроме того, что она является игровой механикой, грязь делает окружения более реалистичными. Игра рендерит текстуры следов людей и лошадей в карту смещений (displacement map) вместе с текстурами следов колёс повозок. Эта аккумулированная текстура используется для Parallax Occlusion Mapping при рендеринге рельефа.

MudMap

Карта грязи: R16_UNORM размером 2048x2048

Небо и облака


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

Карта окружений


Карты окружений (Environment maps) основной источник отражений RDR2, а также GTA5.
Как и GTA5, RDR2 генерирует кубическую карту окружений из позиции камеры. Движок игры генерирует тонкий GBuffer для карты окружений, похожий на используемый в Far Cry 4.

EnvironmentMapAlbedo

Грани кубической карты окружений (альбедо): RGBA8_SRGB

EnvironmentMapNormal

Грани кубической карты окружений (нормали): RGBA8_UNORM

EnvironmentMapDepth

Грани кубической карты окружений (глубина): D32S8

Генерация кубических карт окружений в каждом кадре может оказаться очень тяжеловесной задачей. Для снижения вычислительных затрат RDR2 использует оптимизации. Например, игра отрисовывает только статичные и непрозрачные объекты, выполняет усечение по пирамиде видимости (frustum culling) перед рендерингом каждой грани и отрисовывает версии моделей с пониженным уровнем LOD. Однако я выяснил, что количество полигонов рельефа всё равно очень высок для карт окружений.

После прохода G-Buffer генерируется кубическая карта окружений неба при помощи параболоидной карты неба и текстур облаков. Следующим этапом является свёртка. Для Image Based Lighting движок RDR2 использует split sum approximation. В этом способе используется предварительно отфильтрованная карта окружений вместе с LUT BRDF окружений. Для фильтрации игра сворачивает кубическую карту окружений и хранит свёрнутые версии в уровнях mip-текстур кубической карты.

Перед выполнением прохода освещения для кубической карты освещения RDR2 рендерит в ещё одну кубическую текстуру запечённое крупномасштабное ambient occlusion. Игра использует screen space ambient occlusion, но SSAO помогает только при мелких масштабах. Запечённое ambient occlusion помогает выполнять затемнение в бОльших масштабах, например, затемнение террас и интерьеров.

EnvironmentMapBakedAO

Грани кубической карты окружений (запечённое AO): R8_UNORM

Для вычисления освещения карт окружений игра использует отложенный тайловый рендеринг. Усечение света (light culling) и освещение вычисляются вместе в одном проходе вычислительного шейдера для каждой грани карты окружений. (Благодарю за эту подсказку @benoitvimont.) Также для запечённого освещения игра использует технику карты освещения мира с видом сверху (top-down world lightmap) похожую на использованную в Assassin's Creed III.

Для каждой грани кубической карты RDR2 рендерит окончательный цвет поверх текстуры окружений неба. Затем игра фильтрует кубическую карту окружений так же, как и кубическую карту окружений неба.

EnvironmentMapFinal

Грани кубической карты окружений (окончательные): R11G11B10_FLOAT

Также когда игрок находится рядом со зданием, RDR2 загружает карты окружений, расположенные в интерьерах зданий. Существуют также G-Buffers кубических карт, потоково загружающиеся с диска.

BakedEnvironmentMapAlbedo

Запечённые грани кубической карты окружений (альбедо): BC3_SRGB (запечённое AO хранится в альфа-канале)

BakedEnvironmentMapNormal

Запечённые грани кубической карты окружений (нормали): BC3_UNORM

BakedEnvironmentMapDepth

Запечённые грани кубической карты окружений (глубина): R16_UNORM

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

Проход G-Buffer


Этот этап начинается с предварительного прохода глубин рельефа, а затем игра рендерит сцену в G-Buffers.

GBuffer 0 RGB GBuffer 0 A
AlbedoTarget
AlbedoTargetA


  • RGBA8_SRGB этот буфер содержит в каналах RGB альбедо (базовый цвет). Я не совсем понимаю, для чего нужны данные альфа-канала, но они используются на этапе сглаживания.


GBuffer 1 RGB GBuffer 1 A
NormalTarget
NormalTargetA

  • RGBA8_UNORM: каналы RGB содержат нормали, а альфа-канал содержит что-то, относящееся к ткани и волосам.


GBuffer 2 RGB GBuffer 2 A
MaterialTarget
MaterialTargetA

  • RGBA8_UNORM: этот target используется для свойств материалов.
    • R: Reflectance(f0)
    • G: Smoothness
    • B: Metallic
    • A: содержит затенение (этот канал будет использоваться как маска теней на последующих этапах)

GBuffer 3 R GBuffer 3 B
Material2TargetR
Material2TargetB

  • RGBA8_UNORM: красный канал содержит полости. В синем канале снова какие-то загадочные данные. А в альфа-канале находятся данные, относящиеся к волосам. В зелёном канале мне не удалось ничего найти.

GBuffer 4 RG
MotionBlurTarget

  • RG16_FLOAT: этот буфер содержит скорость в экранном пространстве для реализации motion blur.

GBuffer 5 Depth GBuffer 5 Stencil
DepthTarget
StencilTarget

  • D32S8: как и GTA5, RDR2 использует для глубины обратную z, а также стенсил-буфер для присвоения значений определённой группе мешей.

Из запечённых данных генерируется ещё один target:

GBuffer 6 R GBuffer 6 G
BakedAO
MysteryTarget

Этот буфер содержит в красном канале такое же запечённое ambient occlusion, что и на этапе карт окружений. Но в этой текстуре есть и другие каналы. Зелёные канал содержит данные, напоминающие данные в синем канале GBuffer 3. Я опять не понимаю, для чего используются эти данные. У захваченных кадров я не смог найти никаких данных в синем и альфа-канале. Я изучу это более подробно.

Генерация карт теней


После этапа G-Buffer игра начинает рендерить карты теней (shadow maps). Она использует 2D-массивы текстур для карт теней точечных источников и кубические массивы текстур для карт теней прожекторных источников.

В некоторых играх для карт теней используется большая текстура атласа теней (например, в DOOM). Одно из преимуществ такого метода заключается в том, что размер карты теней может сильно варьироваться в зависимости от расстояния. При использовании массивов текстур эта гибкость теряется, потому что все текстуры в массиве должны иметь одинаковый размер. В RDR2 есть три разных массива текстур для разного уровня качества. Например, у прожекторных источников есть:

  • 512x768 D16 для далёких источников
  • 1024x1536 D16 для источников на среднем расстоянии (а при средних настройках графики и на ближнем расстоянии)
  • 2048x3072 D16 для близких источников (при высоких/ультракачественных настройках)

Точечные источники отбрасывают тени во всех направлениях. Чтобы справиться с этой задачей, в играх используется техника под названием Omnidirectional Shadow Mapping, при которой сцена рендерится в кубическую карту глубин из позиции камеры. При помощи этой техники отрендерены тени от костра и тени от фонаря Артура. Как и прожекторные источники, точечные имеют три разных массива для разных настроек качества.

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

Большинство источников света на стенах прожекторные, но игра не генерирует для них всенаправленную карту теней (omnidirectional shadow map). Вместо неё она генерирует карту теней и копирует память этой карты теней в кубический массив карты теней точечных источников.


Слева карта теней прожекторных источников размером 1024x1536, справа те же данные изображения в кубическом формате текстуры 512x512

Обратите внимание, что в локальных картах теней хранятся линейные z.

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

Также обратите внимание на то, что эта текстура не покрывает 360 градусов. Однако, к счастью, у источников на зданиях обычно есть на задней стороне стена, и запечённые карты теней закрывают её.

Ещё один интересный момент заключается в том, что процесс выполняется наоборот. Возьмём для примера Сен-Дени один из крупнейших городов в игре. Игра генерирует omnidirectional shadow maps для прожекторных источников и копирует эти данные в массив карт теней прожекторных источников. Я не знаю, зачем в RDR2 наложение теней выполняется таким образом. В Интернете мне не удалось найти никаких подобных приёмов.

Наложение теней направленного освещения в RDR2 реализовано почти так же, как в GTA5. Это Cascaded Shadow Mapping с четырьмя каскадами. В качестве каскада используется каждый тайл размером 1024x1024 из текстуры 1024x4096 (при средних настройках графики).

ShadowCascades

Атлас теней направленного освещения: R16_UNORM

Этап освещения


Наконец настало время для объединения всех этих карт окружений, gbuffers, карт теней и буферов ao.

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

Проход глобального освещения


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

LightPass1

Проход локального освещения


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

Чтобы избежать необязательных вызовов шейдеров, игра использует тестирование с ограничением по глубине дополнительную функцию OpenGL/D3D11, которая стала нативной в Vulkan/D3D12. Также она использует стенсил-тестирования для отбрасывания пикселей, поглощённых просвечивающими объектами, например, стёклами окон. Эти объекты будут рендериться во время прямого прохода.

LightPass2

Рендеринг воды и отражения


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

  • Как говорилось выше, карты окружений это основной источник отражений. Для стандартных отражений. например, для отражений в окнах, игра использует их.
  • Зеркала рендерятся с планарными отражениями, при которых сцена рендерится заново с направления отражения. Этот процесс также выполняется отложенным рендерингом.
  • Отражения в воде используют отражения экранного пространства (screen space reflections) в сочетании с картой отражений, сгенерированной в начале кадра.

Этап прямого затенения


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

Но прямой проход может быть затратным:

  • В нём используются прямые шейдеры затенения, которые более затратны отложенных.

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

  • Они отрисовывают каждый толстый просвечивающий объект дважды.

Для достижения правильного смешения необходимо сначала отрендерить задние грани объекта, а затем отрендерить передние. Из-за этого большинство просвечивающих объектов в сцене отрисовывается дважды. Двухмерные объекты-четырёхугольники (например, окна) рендерятся один раз.

  • Кроме того, между отрисовками происходит изменение состояния конвейера.

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

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

BloomMask

Target яркости bloom: R8_UNORM

Заметьте, что яркость bloom увеличивается на дальних расстояниях, чтобы туманные области больше светились.

Постобработка


На этом этапе выполняются временнОе сглаживание, bloom, motion blur, эффект глубины видимости и другие эффекты. Постобработке я планирую посвятить отдельный пост. Поэтому мы не будем особо её здесь обсуждать, но я бы хотел сказать пару слов о bloom. Благодаря объёмному освещению в основном render target уже есть свечение источников освещения.

Реализация bloom в RDR2 очень похожа на реализацию, описанную в Next Generation Post Processing in Call of Duty: Advanced Warfare.

  • В качестве входных данных берётся target без пороговых значений,
  • Render target R11G11B10_FLOAT уровня 7-mip ,
  • Билинейный фильтр 13-го порядка при даунсэмплинге, tent-фильтр 3x3 при апскейлинге.

Затем игра комбинирует этот отфильтрованный target эффекта bloom с основным target, а также с target яркости bloom.

Выводы


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

  • Первое, что я заметил игра выполняет множество переключений с вычислений к графике и обратно. Она использует асинхронные вычисления, если их включить. (Их нельзя включить в игровых настройках, придётся изменять конфигурационный файл игры.) Вот пример для эффекта bloom: игра переключается на вычислительные шейдеры и выполняет какую-то работу, затем снова переключается на графику и выполняет даунсэмплинг, затем снова переключается на вычисления для выполнения какой-то другой работы, а потом заново переключается на графику для апсэмплинга. Затратны ли такие переключения для GPU? Оправдывает ли выгода от вычислительных шейдеров затраты на переключения?
  • Ещё одна странность заключается в том, что RDR2 очищает большинство текстур. Это странно, потому что обычно игры стараются избегать необязательную очистку текстур (например, очистку GBuffers). Оказывают ли эти очистки текстур реальное влияние на производительность? Обязательно ли очищать эти текстуры?
  • Третья странность: в одном кадре есть три (а может и больше) одинаковых прохода даунсэмплинга глубин. Один для SSAO, второй для SSR, и ещё один для этапа генерации объёмного тумана и столбов света. Почему игра не использует подвергнутый даунсэмплингу target глубин из SSAO для других этапов?

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

Послесловие


Вот и всё! RDR2 это превосходно выглядящая игра, не только благодаря использованным графическим приёмам, но и из-за арта и освещения; всё выглядит просто феноменально. Я влюбился в цветовую палитру этой игры. Особенно в ночное время суток, оно напоминает мне Как трусливый Роберт Форд убил Джесси Джеймса, Старикам тут не место и другие вестерны, снимавшиеся 35-миллиметровыми камерами.
Подробнее..

Перевод Рендеринг кадра Cyberpunk 2077

18.12.2020 14:16:13 | Автор: admin

Введение


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

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

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

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

Эта статья ни в коем случае не является серьёзной попыткой реверс-инжиниринга.

Для этого мне не хватает ни времени, ни таланта. Кроме того, я оправдываю свою некачественную работу следующим: на самом деле так лучше.

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

Если мы знаем, то мы знаем, больше не остаётся никакой тайны. Именно незнание заставляет нас мыслить, и иногда мы в точности угадываем то, что происходит, но в других случаях мы можем достичь чего-то лучшего придумать нечто новое Разве это не чудесно?

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

Захваты выполнялись при высоких настройках графики, без RTX и DLSS, поскольку RenderDoc их не поддерживает (возможно, пока?). Я отключил Motion blur и другие неинтересные постэффекты и сделал так, чтобы игрок перемещался на всех захватах. Это даёт чуть больше понимания о передаче доступа к данным предыдущих кадров.

Кроме того, не использовалась никакая инсайдерская информация, так проще и веселее.

Основы


На первый взгляд, описать ядро рендеринга Cyberpunk 2077 можно очень кратко. Это классический отложенный рендерер (deferred renderer) с довольно ванильной схемой g-буфера. Мы не видим здесь безумного количества буферов, как, например, в Spiderman компании Suckerpunch, выпущенной на PS4. Нет здесь и сложной упаковки битов и реинтерпретации каналов.


  • Нормали формата 10.10.10.2 с 2-битным альфа-каналом, зарезервированным для того, чтобы помечать волосы.
  • Albedo в формате 10.10.10.2. Непонятно, что здесь делает альфа-канал, похоже для всего отрисовываемого он равен единице, но, возможно, так только в тех захватах, которые у меня есть.
  • Metalness, Roughness, Translucency и Emissive в формате 8.8.8.8 (в порядке RGBA)
  • Z-буфер и стенсил-буфер. Последний, похоже, используется для изоляции типов объектов/материалов. Движущиеся объекты помечены. Кожа, автомобили, растительность, волосы, дороги. Сложно понять значение каждой части, но общий смысл вам ясен...

Если взглянуть на кадр хронологически, то он начинается с множества отрисовок UI (которые я не исследовал), множества копий из буфера CPU в константы вершинных шейдеров, после чего идёт обновление карт теней (подробнее об этом позже) и, наконец, предварительный проход глубин.


Этот предварительный проход глубин частичен (не отрисовывает всю сцену) и используется только для снижения объёма перерисовки в последующем проходе g-буфера.

По сути, во всех отрисовках геометрии используется инстансинг и некая разновидность bindless-текстур. Могу предположить, что это была большая часть обновления движка из The Witcher 3 для адаптации под современное оборудование.

К сожалению, из-за bindless смотреть на захват renderDoc довольно напрягающе при выборочной проверке я не могу найти особо много разных шейдеров в проходе g-буфера. Вероятно, это признак того, что художникам не разрешили создавать шейдеры при помощи визуальных графов?

Другие предположения: я не вижу в g-буфере никакой сортировки спереди назад, а предварительный проход глубин рендерит все типы геометрии, не только стены. Похоже, для этого нет никакой обработки (кистей, образующих BSP), а художники не размечали вручную объекты для предварительного прохода, поскольку в рендер попадают довольно плохие перекрывающие объекты. Предполагаю, что после усечения список объектов сортируется по шейдеру, а далее инстансы отрисовки динамически формируются в CPU.

Титры в начале игры не упоминают технологию Umbra (которая использовалась The Witcher 3), поэтому предположу, что CDPr реализовала собственную систему видимости. Её эффективность очень сложно оценить, поскольку видимость это проблема балансировки GPU и CPU, однако, похоже, в захвате присутствует довольно много отрисовок, не вносящих вклад в изображение, хотя за это я не ручаюсь. Кроме того, похоже на то, что иногда рендеринг может отображать скрытые комнаты, поэтому, движок, кажется, не использует систему ячеек и порталов. Думаю, что для таких больших миров художникам непрактично выполнять большой объём ручной работы для вычисления видимости.


Наконец, я не вижу никакого усечения, выполняемого на стороне GPU, с использованием пирамид глубин и тому подобного; нет усечения на уровне треугольников или кластеров, как и нет прогнозируемых отрисовок (predicated draws), поэтому предполагаю, что всё усечение по пирамиде видимости и перекрытию выполняется на стороне CPU.

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

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

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

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


Похоже, здесь рендерятся только треугольники с декалями при помощи специальных мешей декалей, но всё остальное удивительно просто. В конце прохода декалей мы иногда видим и проецируемые декали; я не изучал динамические декали, создаваемые оружием, но статические декали уровней просто наносятся при помощи плотно прилегающих к геометрии параллелепипедов (вероятно, созданных вручную), без каких-либо техник разметки стенсилов (которые наверно в данном случае не помогли бы), чтобы минимизировать количество пикселей с затенением.


Что касается отрисовок основного g-буфера, может оказаться, что многие декали совершенно не участвуют в создании изображения, а я не увидел никаких признаков усечения декалей, но это может зависеть от выбранных мной параметров графики.

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

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


Освещение, часть 1: аналитические источники освещения


Очевидно, что анализ отложенного рендеринга не может закончиться на g-буфере; мы разделили затенение на две части, поэтому теперь нужно посмотреть, как реализовано освещение.

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


Тем не менее, достаточно очевидно, что после выполнения всей работы с буфером глубин/g-буфером, наступает черёд этапа суммирования всего, на котором выполняется множество операций, связанных с глубинами.

Сначала он упаковывает нормали и roughness в RGBA8 при помощи кодирования нормалей на основе таблиц поиска по принципу best-fit (эта техника создана компанией Crytek), затем создаёт mip-пирамиду min-max значений глубин.


Затем пирамида используется для создания чего-то, напоминающего объёмную (volumetric) текстуру для кластерного освещения.


То есть, исходя из увиденного, это похоже на кластерную систему отложенного освещения.

Кажется, кластеры это фрагменты 32x32 пикселя в экранном пространстве (фрокселы, froxels) с 64 z-срезами. Однако похоже, что освещение выполняется с разрешением в 16x16 тайлов, и целиком реализовано при помощи косвенного выполнения вычислительных шейдеров.

Рискну предположить, что так получилось из-за того, что вычислительные шейдеры специализируются на материалах и свете, присутствующих в тайле, а затем выполняются в соответствующем порядке такая схема часто используется в современных системах отложенного рендеринга (см., например, презентации Call of Duty Black Ops 3 и Uncharted 4 на эту тему).

На выходе прохода аналитического освещения получаются два буфера RGBA16; похоже, это вычисления diffuse и specular. Учитывая выбранные мной опции освещения сцены, не удивлюсь, что в ней присутствуют только прожекторные/точечные/сферические источники света и линейные/капсульные источники. Большинство источников освещения в Cyberpunk неоновые, поэтому поддержка линейных источников просто обязательна.

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


Освещение, часть 2: тени


Но увиденное нами выше не означает, что в Cyberpunk 2077 используются простые тени, всё совсем наоборот определённо использовалось множество трюков, и большинство из них не так просто подвергнуть реверс-инжинирингу!

Во-первых, перед предварительным проходом глубин происходит серия отрисовок в нечто, напоминающее карту теней (shadowmap). Подозреваю, что это CSM (каскадные карты теней), но в изученном мной захвате они нигде не используются, в них только выполняется рендеринг. Это указывает на то, что система обновляет карты теней на протяжении нескольких кадров (вероятно, с учётом только статичных объектов?).


Эти эффекты, растянутые на несколько кадров, сложно передать в захвате, поэтому нельзя понять, существуют ли другие системы кэширования (например, см. тени Black Ops 3, сжатые в деревья квадрантов).

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


Тени от солнца вычисляются заранее и записываются в буфер экранного пространства перед проходом вычисления освещения; думаю, это нужно для упрощения вычислительных шейдеров и более оптимальной нагрузки на GPU. Этот буфер генерируется в проходе, задействующем довольно много текстур, две из которых выглядят похожими на CSM. Одна из них это точно CSM, в моём случае с пятью элементами в массиве текстур, где срезы с 0 по 3 являются разными каскадами, а последний срез выглядит таким же, как и срез 0, но немного с другой точки зрения.

Если кто-то возьмётся за эту работу, то ему хорошенько придётся потрудиться над реверс-инжинирингом!


Все остальные тени в сцене представлены в некой форме VSM (variance shadow maps), многократно вычисляемых инкрементно в течение времени. Я видел, что используются карты размером 512x512 и 256x256, а в моих захватах на кадр рендерились пять карт теней, но предполагаю, что это зависит от настроек. Большинство из них, похоже, используются только как render target, поэтому, опять же, может оказаться так, что для завершения их рендеринга требуется несколько кадров. Одна из них размывается (VSM) в срез массива текстур я видел некоторые такие массивы с 10 срезами и с 20 срезами.


Наконец, в захватах есть то, что в настройках игры называется контактными тенями (contact shadows) тени малой дальности в экранном пространстве, вычисленные при помощи raymarching-а. Похоже, что они вычисляются самими шейдерами вычисления освещения, что логично, ведь они знают об источниках освещения и их направлениях

В целом, тени и просты, и сложны одновременно. Схема создания с CSM, VSM и опциональным raymarching-ом не особо удивляет, но уверен, что дьявол таится в деталях о том, как все они генерируются и подвергаются постепенному усилению. Очевидные артефакты в игре встречаются редко, за что стоит поблагодарить всю систему, которая хорошо справляется с работой даже в таком открытом мире!

Освещение, часть 3: всё остальное...


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


Во-первых, есть очень хороший проход SSAO половинного разрешения. Он вычисляется сразу после описанного выше общего прохода суммирования и использует упакованные в RGBA8 нормали и roughness, а не из g-буфера.

Похоже, что он вычисляет наклонные нормали и конусы апертур. Конкретную технику вычисления определить невозможно, но это определённо что-то типа HBAO-GTAO. Сначала глубина, нормали/roughness и векторы движения подвергаются даунсэмплингу до половинного разрешения. Затем проход вычисляет Ambient Occlusion текущего кадра, а последующие выполняют двунаправленную фильтрацию временное репроецирование. Паттерн дизеринга тоже довольно равномерный, предположу, что это градиентный шум Жорже.

Легко догадаться, что отдельные diffuse-specular, переданные из прохода освещения, используются здесь для упрощения более корректного их перекрытия с информацией конусов.


Во-вторых, нужно рассмотреть косвенное освещение. После прохода кластеризации освещения есть серия отрисовок, обновляющих массив текстур, похожих на развёрнутые сферически (или двойным параболоидом?) зонды. Всё это снова распределяется на несколько кадров, не все срезы этого массива обновляются в каждом кадре. В захватах легко заметить, что некоторые части массива зондов обновляются данными новых зондов, генерируя на лету mip-карты, предположительно, с предварительной фильтрацией GGX.


Сложнее найти источник данных зондов, но в основном захвате, который я использую, похоже, происходит повторное вычисление освещения кубической карты specular; для меня неочевидно, отличается ли этот зонд от находящихся в массиве, или он позже является источником данных массива.

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


Здесь используется стандартное объёмное освещение, вычисленное в 3D-текстуре с временным репроецированием. Raymarching ограничивается глубиной сцены, вероятно, для экономии ресурсов, но это, в свою очередь, иногда может приводить к утечкам и артефактам репроецирования. Однако в большинстве случаев они малозаметны.


Здесь всё снова становится очень интересным. Сначала используется потрясающий проход отражений в экранном пространстве (Screen-Space Reflection), на котором опять используется буфер упакованных нормалей/roughness, а значит, поддерживаются размытые отражения; всё это выполняется в полном разрешении (по крайней мере, при моих настройках графики).

В нём применяются данные цвета предыдущего кадра до композитинга UI (для репроецирования используются векторы движения). И получается довольно много шума, даже если для дизеринга применяется текстура синего шума!


Далее идёт косвенное diffuse/ambient GI (Global Illumination). Используется g-буфер и серия объёмных текстур 64x64x64, которые сложно расшифровать. Исходя из входных и выходных данных, можно предположить, что объём центрирован относительно камеры и содержит индексы какого-то вычисленного свечения, возможно, сферических гармоник или чего-то подобного.

Освещение очень мягкое/низкочастотное и косвенные тени в этом проходе не особо заметны. Возможно, это даже динамическое GI!

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


Наконец, выполняется общий композитинг всего: зондов specular, SSR, SSAO, diffuse GI, аналитического освещения. Этот проход снова создаёт два буфера, один из которых походит на окончательное освещение, а второй содержит только то, что похоже на части specular.

И здесь мы видим то, о чём я говорил в начале. Основная часть освещения берётся не из аналитических источников освещения! Здесь мы не видим привычных трюков со множеством заполняющих источников, добавленных художниками (хотя дизайн освещения определённо выполнен очень тщательно) бОльшую часть сцены создаёт косвенное освещение. Это косвенное освещение не такое точное, как в движках, более активно использующих запекания GI и сложное кодирование, но оно очень однородное и позволяет сохранить высокочастотные эффекты при помощи двух очень высококачественных проходов экранного пространства, проходов AO и отражений.



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

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

Всё остальное


В движке есть множество других эффектов, которые мы не будем рассматривать ради краткости статьи и чтобы я не сошёл с ума. Очень интересны волосы, похоже, что рендерится несколько срезов глубин и они частично вставляются в g-буфер с предварительно вычисленным освещением и странным эффектом нормалей (фальшивая анизотропия?). Ещё один важный эффект, который я не буду рассматривать это затенение просвечивания/кожи.


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

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


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


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

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



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

Разумеется, там есть эффект глубины поля зрения, тональная коррекция и автоматическая выдержка Также присутствуют все эффекты деградации изображения, которые можно ожидать от игр и которые вы скорее всего захотите отключить: зерно плёнки, lens flares, motion blur, хроматическая аберрация Даже композитинг UI выполняется нетривиально, всё реализовано на вычислительных шейдерах, но у меня нет времени на анализ Теперь, сняв этот груз с души, я могу, наконец, попробовать насладиться игрой! Пока!
Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru