[Перевод] Как рендерится кадр Elden Ring

image


После выхода Elden Ring мне захотелось заглянуть за кулисы этой игры и узнать, что же там находится. Когда я смотрел анализ PC-версии игры Elden Ring в Digital foundry, то заметил, что MSI-Afterburner/Rivatuner сообщает, что эта игра основана на D3D12, и это меня восхитило. Потому что а) последняя изученная мной игра была старой и работала на D3D9 (подробнее об этом в будущем), а игра до неё была проектом 2022 года, работающим на D3D11, и это стало большим разочарованием; поэтому почти полгода я не изучал современные игровые технологии выпущенных игр для PC; б) это значит, что в игре будет много интересных функций D3D12, используемых хитрым способом. Что может быть лучше использования современного графического API для игры на PC в 2022 году?

На самом деле, всё оказалось иначе. Меня немного разочаровали решения разработчиков, но не очень сильно; подробнее об этом я напишу ниже. Однако любому геймеру очевидно, что в подобной игре главное — базовая боёвка, лор и геймплей, а графика уровня AAA — лишь дополнение, обеспечивающее более глубокий лор. Первые демонстрации игры выглядели потрясающе (ну, этим всегда славились E3 и все AAA!), но визуальное качество и уровень детализации готовой игры не так хороши (на мой взгляд). На самом деле, в Bloodborne и Sekiro качество с точки зрения визуальной красоты было выше. Так что да, меня как исследователя графики немного разочаровала игра для PC на D3D12. Зато как геймер я очень доволен!


На этот раз захваты были выполнены только на одном из моих PC, я не хотел тратить больше времени, как при анализе предыдущей игры, когда я делал захваты конфигураций на двух машинах и копировал файлы сохранений по сети! На этот раз я выбрал PC с RTX 3080, Ryzen 5950x и 32 ГБ ОЗУ. Параметры качества игры (Quality Settings) установлены на максимум (Maximum), а разрешение (Resolution) выбрано равным 1080p и включено автоматическое распознавание наилучших параметров (Auto-Detect Best Rendering Settings) (этот параметр работает как динамическое разрешение, только для практически всех графических аспектов, а не только для разрешения). Но я всё равно думаю, что эта настройка никак не повлияет на игру и не будет ничего менять, так как тестовый PC достаточно хорош для такой игры.

Учитывая всё это, я удивлён «странным» выбором параметров графики: некоторые параметры, например, качество текстур (Texture Quality), имеют четыре конфигурации, а другие, например, качество сглаживания (Antialiasing Quality) — только три конфигурации. Всё можно было организовать гораздо лучше!

d354fed1d5e3870cc9871ea623614624.png


0a5aa8502cee0b6e542f2b560937ceb9.png


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

Я больше склонен ссылаться на захваты кинематографических вставок, чем на захваты самого геймплея: они используют один движок и имеют примерно одинаковые очереди рендеринга, но я заметил (и это достаточно распространено), что во вставках всё выкручено на максимум и есть некоторые любимые мной эффекты (например, DoF), которые совершенно отсутствуют в геймплее. С другой стороны, я заметил, что игре не удаётся работать со стабильными 60 fps во время геймплея, когда игрок находится под открытым небом, однако внутри помещений (пещер, подземелий, замка и т. п.) и во время кинематографических вставок выдаёт стабильные 60 fps. Поэтому в захватах из вставок гарантированно будут отсутствовать даунскейлинг/динамическое разрешение и тому подобное.

Примечание: если вы захотите выполнять захваты в этой игре, то это может стать настоящим кошмаром из-за ПО EasyAntiCheat, которое запускается для запуска самой игры, поэтому практически все привычные инструменты практически бесполезны против этой игры. Поэтому вам придётся найти способ это обойти. Однако в целом для меня это оказалось довольно проблемно! И даже после успешного захвата игра часто вылетала. Я больше не буду углубляться в эту тему, но могу намекнуть, что EasyAntiCheat, вероятно, назвали «easy», потому что этот античит легко обмануть!


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

D3D12


Как я говорил выше, ещё до того, как делать захваты, я знал, что в порте игры для Windows используется D3D12, и был очень рад этому. Но оказалось, что если разработчик создаёт качественные игры для PlayStation, ситуация с портом для PC необязательно будет такой же. На самом деле, я считаю, что игре вполне было бы достаточно D3D11 или даже более старой версии, поскольку она практически не использует возможности D3D12. По крайней мере, в ней, похоже, не используется технология VRS, которая для меня является одной из самых интересных функций D3D12. Mesh Shaders, Raytracing, Sampler Feedback, Direct Storage — всё это совершенно не используется в порте Elden Ring для PC с D3D12.

Draw


Копирование/создание ресурсов


Каждый кадр в Elden Ring начинается с приблизительно 25 тысяч команд CopyDescriptorsSimple и CreateConstantBufferView. Их назначение понятно из названия, они подготавливают данные ресурсов к доступу. Если вы чаще всего работали с OpenGL, а теперь с Vulkan (то есть слабо знакомы с DX), то можете сказать: «Ага, то есть так работают с DX12», но на самом деле это не так! Можете попробовать делать захваты из опенсорсных игр/движков на D3D12, можете сделать захваты из игр Unreal на D3D12, можете взять новый проект Unreal на основе RHI D3D12, упаковать его и сделать захваты в нём, даже использовать BaseMark GPU Benchmark для D3D12 — во всех этих играх/приложениях D3D12 вы заметите два основных аспекта:

1. Они редко вызывают эти функции (а то и вовсе их не вызывают)
2. Они не подготавливают «все» просмотры доступа к ресурсам до выполнения рендеринга кадра.

Чтобы чётче понять эту проблему (которая может быть вероятной причиной споров о торможениях Elden Ring), можете ниже посмотреть на последовательности первого захвата из BaseMarkGPU; как видите, с начала кадра и до конца, это вся работа над кадром, как и ожидается. С другой стороны, последовательность второго захвата — это кадр Elden Ring; вы видите, что сама работа над кадром (отрисовка/вычисления) происходит в последней четверти длительности кадра, и это очень странно!

88134eca80e8cc76c03d6226823f895b.png


c2c38bda10cf3cb46d73f11b56f88b20.png


Не обращайте внимания на количество событий, BaseMarkGPU предназначен для стресс-тестов GPU

Это интересно, сбивает с толку и наводит на множество вопросов. Самый простой из них: зачем? Второй по простоте вопрос в моём списке: Разве никто не заметил этого в процессе работы над игрой? Приходится довольно долго ждать ExecuteCommandLists. Это совершенно точно связано с простоями и торможением ЦП! Не любое «потерянное время» должно быть связано с Device Wait/Idle, он может относиться и ко многому другому. И чтобы подтвердить теорию простоев ЦП, можно сравнить длительность работы GPU и ЦП, долгий период ожидания заметен сразу.

3e8d9c9925c698eb56631de1449b1e05.png


Длительность работы GPU

754e9c36cb936d075e0004b912668028.png


Длительность работы ЦП

Показанный на изображениях маркер находится в «фиксированной» точке времени жизни кадра, но на двух «шкалах». Когда маркер кадра на GPU Duration Scale находится на 0.005632ms, эта точка соответствует 17.8682ms на CPU Duration Scale. Именно тогда начинается работа GPU!

Если вы ещё не поняли, ниже я объясняю шкалы времени работы ЦП-GPU: по сути, мы как бы «вырезали» это первое изображение (последовательность кадра GPU) и «вставили» его туда, где оно должно быть на втором изображении (последовательность кадра ЦП).

a13a5828d4ffa9cba017bf64a47b881c.png


Я считаю, что при другой организации/архитектуре кадра Elden Ring могла бы работать гораздо быстрее и без торможений!

Copy и Clear


Ничего особенно важного, это просто три прохода копирования/очистки данных предыдущего кадра, последовательность CopyBufferRegion и ClearDepthStencilView. В основном эти операции связаны с GBuffer, например, добавление барьеров ресурсов, а затм копирование содержимого render target GBuffer из предыдущего кадра (Color, Surface, Normals, AO, Depth, SSS и т. п.), так как они могут понадобиться в текущем кадре.

Временное кольцо

Если бы я выбирал этой игре название, связанное с графикой, то она называлась бы «Временным кольцом», а не «Кольцом Элдена», потому что многие данные переносятся из предыдущего кадра (копируются), а многие вещи накапливаются между кадрами, становятся «временнЫми». Когда мы слышим это слово, то обычно знаем, что тема будет касаться сглаживания, однако во «Временном кольце» всё заходит гораздо дальше — AA является временным, SSAO, Glare, даже тени — тени из предыдущего кадра переносятся в текущий! А те аспекты, которые не используют RT предыдущего кадра, используют скорость или дельту движения из предыдущего кадра. Я заметил, что это применимо практически к любому важному этапу/эффекту в игре — они тем или иным образом используют данные предыдущего кадра. При глубоком изучении игры начинаешь привыкать к префиксу Prev!


Вершины Elden


Один из аспектов, сильно интересующих меня в разных играх — это описания вершин. Мне всегда любопытно, используется ли в движке ленивое описание вершин (как я делал когда-то давно) и одно и то же описание вершин применяется для всего (обычно со скиннингом даже для мешей без скиннинга), или же применяются продуманные разные описания, соответствующие различным ситуациям. Или же они крайне специализированы и используют множество описаний вершин для разных типов одного и того же объекта. И насколько я могу судить, разработчики Elden Ring относятся к третьей категории и создают микроспециализированные описания вершин. Ниже представлены самые широко используемые в движке описания (но не все, существующие в игровом движке/рендерере).

Описания вершин Elden Ring — большинство мешей (камни, скалы, здания и т. п.)
bktzhq1shkgbegfnrkliy7xeaks.png


Описания вершин Elden Ring — меши со скиннингом (персонажи, враги, животные и т. п.)
sacmhaswny09oeu-sf7r-o0ce74.png


Описания вершин Elden Ring — меши со скиннингом (ткань)
vqjwd6elcml_u3vy_l-mtpiydpq.png


Описания вершин Elden Ring — меши со скиннингом (ткань под тканью)
rycne-equlhsjmqshirah2prfw4.png


Описание вершин Elden Ring — меши листвы
ddi6h96e_fqjjwajqnye5-sygfq.png


Описания вершин Elden Ring — некоторые камни
8uscjcvfrthxm-rf1q9a9m0g2gg.png


Описание вершин Elden Ring — некоторые виды инстансинга (SpeedTree)
jpgoksln7q7ruom0lvu-5qk0lp8.png


Описания вершин Elden Ring — некоторые меши (используются только в течение прохода теней)
ah1fkwasbsro_9ki9bhof839unu.png


За многие годы я научился любить и практиковать специализированные вещи, например, описания вершин, но не настолько специализированные! К примеру, если вы думаете, что это все вариации описаний вершин ткани, то вы ошибаетесь — есть ещё пара вариаций для описаний мешей ткани; одна из них предназначена для ткани под тканью, уже находящейся под тканью! Вы легко можете увидеть в игре эти слои одежды и брони, особенно в кинематографических вставках — лучше всего это заметно на Мелине!

CSM прямого освещения


Несколько ранних проходов только глубин для направленного/непосредственного освещения (солнечного света), также называемых Shadow Map Cascades. Это может быть от 6 до 14 проходов глубин (возможно, и больше, но это максимум, который я обнаружил на своих захватах), всё зависит от количества детализации (количества объектов/мешей на кадр), то есть может быть 6 или 8 проходов для кадра в подземелье, но 14 (а может и больше) в открытом мире над землёй. В конечном итоге остаётся 5 каскадов, всегда сохраняемых размером 8192×4096 формата R16_TYPELESS. Всегда! Даже когда игрок находится в подземелье, они имеют тот же размер. Постоянство — это хорошо… иногда!

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

e1-cvqxg1mxntlej92jgvv-knq8.png


Изображения в высоком разрешении


Проходы цвета [GBuffer/отложенное затенение]


Так как игра рендерится с отложенным затенением, на этом этапе будет создаваться последовательный набор отложенного затенения, передаваемого для создания окончательных render target GBuffer. Количество (длительность) этих проходов может разниться в зависимости от количества отрисовываемых элементов. В пещере или киновставке может быть 8–12 проходов отрисовки, а на большом открытом пространстве — 20 или больше. В конечном итоге мы приходим к обычному GBuffer, здесь нет ничего непривычного.

3d088f94fd251b912589e6f3773b001c.png


Готовая Swapchain

ffbaf4063e661bd0c2d7988a205f21d2.jpg


Цвет — R8G8B8A8_TYPELESS

a78791112c1334b28232566bcce8e13e.png


Глубина — D32S8_TYPELESS

9c2b1f67cdd62cc330fe835581f96c9d.jpg


Нормали — R10G10B10A2_UNORM

2da19be107e564172ebced1ec8d8a161.png


Поверхности — R8G8B8A8_UNORM

В render target определения поверхностей используются отдельные каналы. Один — это metallic, второй — roughness, а третий довольно «необычен». Он для теней (используется несколькими этапами далее).

e750ac7421bf1f89127a4165b7f6bfcb.png


R

ed47067dc1e09289aebabcf98406ac9c.png


G

1ea2e708f9c33ab43245221f7fd72ee6.png


B
[A] — это сплошной белый, не используется, поскольку позже создаются другие полные RT и используются только их [R] или [A]

А вот таймлапс render target GBuffer.

ЦветГлубинаНормалиПоверхностиR поверхностейG поверхностейB поверхностей

Стоит заметить, что обычно в GBuffer есть два render target, которые не делают ничего, они полностью чёрные — в одном проходе находятся все основные render target + эти два, в другом проходе эти два хранят некоторые из значений основных render target, при том что сами render target полностью чёрные. Это происходит совершенно случайно и, насколько я могу судить, какой-то предсказуемый паттерн отсутствует.

И, разумеется, в некоторых кадрах/областях будут существовать значения в отдельном Render Target для Emissive (свечения), при котором предыдущий кадр имеет почти 0 свечения, а RT чёрный, но в примере кадра ниже показан полезный render target свечения, сопровождающий GBuffer.

47defadeeb3636d58e96ddf258158ce6.png


Окончательный кадр Swapchain — 1920×1080

0371727d53df27f1264961c6eb111edc.jpg


Вспомогательный Render Target свечения — 1920×1080 — R16G16B16A16_FLOAT

Дизеринг


Многие объекты в Elden Ring поддерживают дизеринг-прозрачность и во время отрисовки им передаётся глобальная одноканальная текстура дизеринга размером 8×8. Вне зависимости от того, видите ли вы дизеринг этих объектов, при необходимости они отрисовываются готовыми для этого. Трава, деревья, все типы листвы, а также броня и одежда персонажа, флаги и знамёна, NPC и враги — все они изначально поддерживают дизеринг.

725be8ef704ad012eaf0ca62ca48520b.png


Это увеличенная версия глобальной текстуры дизеринга с линейной фильтрацией. А вот как она выглядит в реальном размере:

4c096d16ec4a4dfc14f87ef5d7269d76.jpg


Декали


Отрисовка декалей поверх отложенного GBuffer происходит в последовательности DrawIndexedInstanced в зависимости от вариаций декалей и их количества. Здесь особо ничего интересного.

Итак, у нас есть отложенный GBuffer

f99a3788cf8b11ee42e4f8ab8c9c45f7.jpg


1920×1080 — цвет

6d596368092a256ca7cd7830761c6802.png


1920×1080 — поверхность (Metallic, Roughness…)

6d789e3a562e01787f6c641caf3d2ab3.jpg


1920×1080 — нормали

e3682f5afc851af41010d3f03132000d.png


1920×1080 — глубина

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

75ecb840bcd3c0e3a0d70b9eac2c9f84.png


Кадр swapchain в конце

Мы пройдём по двум операциям отрисовки, для каждой из них в качестве маски используется декаль, а также несколько дополнительных текстур (таких как diffuse, specular и normal) для проецирования декали в нужное положение.

Отрисовка 1

f99a3788cf8b11ee42e4f8ab8c9c45f7.jpg


Кадр на входе (декалей пока нет)

37ffbc82d3d31524e32f1f0caafcdb8c.png


512×512 BC4_UNORM

65664388daec8d08f19a1c6b00f311ce.png


256×256 BC7_UNORM

e459c20d989b4eab25049042c52b4d72.png


256×256 BC1_TYPELESS

1dd46808a0cb59eb688c0d3d8841fc8c.png


256×256 BC1_TYPELESS

2a02a8a18021ca15dd891235386e4b13.jpg


Кадр на выходе

b7386fa1cc868418d83a8ed63fc14915.png


Свойства поверхностей GBuffer на выходе

Отрисовка 2

2a02a8a18021ca15dd891235386e4b13.jpg


Кадр на входе (с одной отрисовкой декали)

5c74be514c0246a438957e30e6ccd3b7.png


512×512 BC4_UNORM

65664388daec8d08f19a1c6b00f311ce.png


256×256 BC7_UNORM

e459c20d989b4eab25049042c52b4d72.png


256×256 BC1_TYPELESS

1dd46808a0cb59eb688c0d3d8841fc8c.png


256×256 BC1_TYPELESS

8f2be25e8aa1d6d2287c6e126026e03e.jpg


Кадр на выходе

00b0a5e56da6bad334b3b98c308ed373.png


Свойства поверхностей GBuffer на выходе

Отрисовка N…

Небольшое примечание: маска крови на самом деле не красная, в ней используется BC4_UNORM, то есть это просто совпадение, что маска крови «выглядит» красной.

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

48270eae4cf63a589fd7126bc57b1a7b.gif


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

5c74be514c0246a438957e30e6ccd3b7.png


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

75ecb840bcd3c0e3a0d70b9eac2c9f84.png


7d88f5dca8425054916e1b2e6b1fb5ae.png


661349dfb0dbfb0c4d6d3d4cde057447.png


c472cf7e7edc4cdbd8b278f5d068812e.png


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

00b0a5e56da6bad334b3b98c308ed373.png


d86a00e5043d66ca2f65b51d6a758b58.png


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

Если отложенным декалям передаётся часть с ресурсами, то как насчёт параметра шейдеров? Вот список параметров декалей, передаваемый шейдерам

MTD Param
bwaebdaftzmjixqwnd1ehitao7u.png

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


Instance Data
pllhipxxx2b3rpswpjqjp5wipbg.png
Обратите внимание, что этот массив структур InstanceData всегда имеет два элемента, вне зависимости от количества экземпляров отрисовываемых декалей и даже без учёта того, если ли декали. Всегда два элемента в массиве.


Model Param
jyybhnvblnss3nezthmba66cwgg.png


Decal Param
kcqawnpqljsyej6lihkyalqc3le.png
Наконец-то! Хотя бы одна из четырёх передаваемых шейдеру структур полностью относится к делу.


А теперь о самом интересном аспекте декалей в Elden Ring. Декали используются (обычно) для детализации объектов сцены/мира, и один из них (как вы могли видеть в предыдущих разборах) — это следы подошв. В этом смысле Elden Ring не отличается от других игр. Посмотрите на показанный ниже готовый кадр: зная, как выглядят декали следов, сможете ли вы найти их в мире, и если они есть, то где эти следы проецируются? И самое главное — можете ли вы прикинуть по готовому кадру, сколько видов следов отрисовывается как декали? Считайте это викториной и при желании откройте ответ под спойлером!

7d88f5dca8425054916e1b2e6b1fb5ae.png


Готовый кадр

25f5a1e86c6e8813dba9d9b353c2c5ec.png


Diffuse декали — 256×256 BC1_TYPELESS

a4867133a4bbf4641acfe8db7c55e49c.png


Specular декали — 256×256 BC1_TYPELESS

7a2a35a99ba3f514bf29b208f815ed78.png


Bump декали — 256×256 BC7_UNORM

0f0b8caadf7ecc7fba95d9a4b9495c6e.png


Маска декали — 512×512 BC4_UNORM
За множество проведённых в игре часов я не нашёл ни одной вариации следов, кроме той. Она используется для всего!

Показать ответ

Итак, вы ошибаетесь, если думаете, что следов нет — на самом деле в этом кадре спроецировано и отрисовано 60 различных следов, и ни один из них невидим ни игроку, ни на финальном кадре, они просто скрыты где-то за теми далёкими деревьями! Единственная декаль, которую вы видите из почти семидесяти команд отрисовки декалей — то пятно крови рядом с птицей. Декали занимают не так уж мало ресурсов, поэтому я думаю, что в Elden Ring можно было бы оптимизировать!


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

fd940f74f378d9a380af61fedf95b089.png


Готовый кадр

3b068bdca020b52422618efd21c17802.gif


Цвет GBuffer декалей

d46566e29f01851f96400eb9d4cdfd68.gif


Нормали GBuffer декалей

3647e92b4265a909ea7bb32ef8b37ef4.gif


Поверхности GBuffer декалей

Обратите внимание, что эти изображения GBuffer анимированы!

Irradiance и Specular Accumulation


Имея полностью готовый GBuffer, его можно использовать множеством различных способов. Он в месте с кубической картой или текстурой IBL, а также запечённым IrradianceVolume (XYZW) передаются шейдеру, который выполняет все необходимые вычисления освещения, создавая Irradiance RT и Specular AccumulationRT.

Cubemap (IBL) + GBuffer«s (Normals + Depth + Surface) + Irradiance Volume XYZW = Irradiance RT + Specular Acc RT

15de60a47c7a9ac8d99f3c5c48eca8e9.png


7fc0429ff680a6b9676a99823900af15.png


Примеры кубических карт (IBL) Elden Ring, каждая из которых имеет по 6 слайсов (±X, ±Y, ±Z) с 5 mip-текстурами (от 128×128 до 8×8) в формате BC6_UFLOAT

На некоторые области влияет одна кубическая карта, а на другие — две или более.

e008558435b532fce14c7bf1e7b9b351.gif


Irradiance Volume X

c8d4cba9284106965668dd811e622590.gif


Irradiance Volume Y

9e41dd943ce2238fb20a5cfd464c67ea.gif


Irradiance Volume Z

8f76ca50b9854230d91506171b1262b7.gif


Irradiance Volume W

На показанных выше анимациях демонстрируется запечённый Irradiance Volume для одной области; в данном случае объём имеет 72 слайса, но это число варьируется в зависимости от размера объёма, оно может быть больше (более 100 слайсов) или меньше (20 слайсов и менее). Эти запечённые данные Irradiance обычно имеют формат BC7_UNORM, однако размеры тоже меняются в зависимости от количества слайсов, в данном случае это 120×124.

И, разумеется, как и в случае с кубическими картами, у некоторых областей будет один объём, а у других несколько, это зависит от «пространства», на которое смотрит игрок.

7e27a1792c7caf33818fa63d6812fbb8.gif


X

c88bf1b3517cc2501ba08486fdfbb0d8.gif


Y

1cf7fbeee04eeb8251ae603130f98318.gif


Z

e988c61c5df4eb288437e0c234fec3c2.gif


W

Ещё один пример объёма/3d-текстуры размером 236×84 из 144 слайсов

Итак, эти два элемента (IBL + Irradiance Bakes) совместно с GBuffer приводят к созданию Irradiance RT, а также Specular Accumulation RT.

04e2108dcec59bcc2c9e5ff8659c0db5.png


Irradiance RT — 1920×1080 — R11G11B10_FLOAT

2f227eddc622092609aa5e31031f4853.png


Specular Accumulation RT — 1920×1080 — R11G11B10_FLOAT

И кадр киновставки в этом не отличается — все входные данные точно такие же; я надеялся, что во вставках используется кубическая карта большего разрешения или что-то подобное, но увы, они одинаковые…

bbf6f26c124cd8a4032f0e72f6da567d.png


Irradiance RT — 1920×1080 — R11G11B10_FLOAT

875be65a12edab096fd5a2c356712f7a.png


Specular Accumulation RT — 1920×1080 — R11G11B10_FLOAT

Даунсэмплинг глубин


Даунсэмплинг глубин выполняется дважды. Один раз здесь (Graphics Queue) и один раз в Compute Queue. Тот, который выполняется здесь (пока) не оправдан, его результаты не используются, но стоит упомянуть, что он существует! Другой этап под названием Depth Downsampling находится в compute и его результаты используются; об этом мы поговорим ниже.

f4a9b2bde3a655eb9b7c03cc7c655984.png


1920×1080 — D32S8_TYPELESS

38a7d69905afe0d738e98df33450d271.png


960×540 — D32S8_TYPELESS

04ee947f3fc793782a253bf6956f21ce.png


480×270 — D32S8_TYPELESS

Даунсэмплированные до 960×540 глубины очень важны в Elden Ring, поскольку большинство эффектов, использующих глубины, пользуются этими данными, а не полнокадровым target глубины 1920×1080

SSAO


Генерация SSAO выполняется за три этапа. Вот примеры двух кадров

1. Генерация SSAO + вращения


При помощи имеющихся глубин половинного размера + render target нормалей, а также вспомогательной текстуры «Random Rotations» мы получаем новый render target SSAO.

38a7d69905afe0d738e98df33450d271.png


in Depth — 960×540 — D32S8_TYPELESS

c9ef9156b353c9a0aa8b4c4f7eeededa.jpg


in Normal — 1920×1080 — R10G10B10A2_UNORM

58ab5df24f70eb636db7e23921b4af08.png


in RandomRot — 64×64 — R8G8B8A8_UNORM

fc085c476ca36e83008e75e1bdad06d1.jpg


Out SSAO — 960×540 — R8G8B8A8_UNORM

ce2d3bdcabe1045c26132343d830517c.png


in Depth — 960×540 — D32S8_TYPELESS

b841274ce819bab8dcc368f072e7d2fa.jpg


in Normal — 1920×1080 — R10G10B10A2_UNORM

58ab5df24f70eb636db7e23921b4af08.png


in RandomRot — 64×64 — R8G8B8A8_UNORM

b45fa7c2de3e2403fe52cee67f37739d.jpg


Out SSAO — 960×540 — R8G8B8A8_UNORM

Этот новый SSAO является упакованной текстурой. Реальный SSAO находится в канале R, а канал A — это маска для SSAO (на практике можно считать, что это маска скайбокса, поскольку это единственное, к чему мы не можем применить SSAO). Канал G хранит случайные повороты для ядра сэмпла в каждом пикселе. А канал B, насколько я понимаю — это «проверка расстояния», позволяющая избежать ошибочных перекрытий.

fc085c476ca36e83008e75e1bdad06d1.jpg


RGBA

b4005802f96911c4b03f53d75761a1c9.png


R

e1db9bc7bd27dc28498e253213854a61.png


G

a8f686ba4e54a0bece7527cde7131053.png


B

1305a6174f28026610871bcb206d0212.png


A

b45fa7c2de3e2403fe52cee67f37739d.jpg


RGBA

e483ccdb560aef383c4c8ec1080536a0.png


R

4d62f595d8b9cdab3ede045b4cd6df6c.png


G

ba3c02ae430a6b66da7f6819dbe8e357.png


B

cc414c7a0ab828796e23a4cb6dcdc6dd.png


A

2. Предыдущий и текущий кадр


Выполняем своего рода интерполяцию (временнУю) между SSAO предыдущего и текущего кадра.

fc085c476ca36e83008e75e1bdad06d1.jpg


Текущий кадр

© Habrahabr.ru